+ // Check for an empty packet
+ if(dataLen == 0) {
+ if( Header->Flags == TCP_FLAG_ACK )
+ {
+ Log_Log("TCP", "ACK only packet");
+ return ;
+ }
+ Connection->NextSequenceRcv ++; // TODO: Is this right? (empty packet counts as one byte)
+ Log_Log("TCP", "Empty Packet, inc and ACK the current sequence number");
+ Header->DestPort = Header->SourcePort;
+ Header->SourcePort = htons(Connection->LocalPort);
+ Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
+ Header->SequenceNumber = htonl(Connection->NextSequenceSend);
+ Header->Flags |= TCP_FLAG_ACK;
+ TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
+ return ;
+ }
+
+ // NOTES:
+ // Flags
+ // PSH - Has Data?
+ // /NOTES
+
+ sequence_num = ntohl(Header->SequenceNumber);
+
+ Log_Log("TCP", "0x%08x <= 0x%08x < 0x%08x",
+ Connection->NextSequenceRcv,
+ ntohl(Header->SequenceNumber),
+ Connection->NextSequenceRcv + TCP_WINDOW_SIZE
+ );
+
+ // Is this packet the next expected packet?
+ if( sequence_num == Connection->NextSequenceRcv )
+ {
+ int rv;
+ // Ooh, Goodie! Add it to the recieved list
+ rv = TCP_INT_AppendRecieved(Connection,
+ (Uint8*)Header + (Header->DataOffset>>4)*4,
+ dataLen
+ );
+ if(rv != 0) {
+ break;
+ }
+ Log_Log("TCP", "0x%08x += %i", Connection->NextSequenceRcv, dataLen);
+ Connection->NextSequenceRcv += dataLen;
+
+ // TODO: This should be moved out of the watcher thread,
+ // so that a single lost packet on one connection doesn't cause
+ // all connections on the interface to lag.
+ // - Meh, no real issue, as the cache shouldn't be that large
+ TCP_INT_UpdateRecievedFromFuture(Connection);
+
+ // ACK Packet
+ Header->DestPort = Header->SourcePort;
+ Header->SourcePort = htons(Connection->LocalPort);
+ Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
+ Header->SequenceNumber = htonl(Connection->NextSequenceSend);
+ Header->WindowSize = htons(TCP_WINDOW_SIZE);
+ Header->Flags &= TCP_FLAG_SYN; // Eliminate all flags save for SYN
+ Header->Flags |= TCP_FLAG_ACK; // Add ACK
+ Log_Log("TCP", "Sending ACK for 0x%08x", Connection->NextSequenceRcv);
+ TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
+ //Connection->NextSequenceSend ++;
+ }
+ // Check if the packet is in window
+ else if( WrapBetween(Connection->NextSequenceRcv, sequence_num,
+ Connection->NextSequenceRcv+TCP_WINDOW_SIZE, 0xFFFFFFFF) )
+ {
+ Uint8 *dataptr = (Uint8*)Header + (Header->DataOffset>>4)*4;
+ #if CACHE_FUTURE_PACKETS_IN_BYTES
+ Uint32 index;
+ int i;
+
+ index = sequence_num % TCP_WINDOW_SIZE;
+ for( i = 0; i < dataLen; i ++ )
+ {
+ Connection->FuturePacketValidBytes[index/8] |= 1 << (index%8);
+ Connection->FuturePacketData[index] = dataptr[i];
+ // Do a wrap increment
+ index ++;
+ if(index == TCP_WINDOW_SIZE) index = 0;
+ }
+ #else
+ tTCPStoredPacket *pkt, *tmp, *prev = NULL;
+
+ // Allocate and fill cached packet
+ pkt = malloc( sizeof(tTCPStoredPacket) + dataLen );
+ pkt->Next = NULL;
+ pkt->Sequence = ntohl(Header->SequenceNumber);
+ pkt->Length = dataLen;
+ memcpy(pkt->Data, dataptr, dataLen);
+
+ Log_Log("TCP", "We missed a packet, caching",
+ pkt->Sequence, Connection->NextSequenceRcv);
+
+ // No? Well, let's cache it and look at it later
+ SHORTLOCK( &Connection->lFuturePackets );
+ for(tmp = Connection->FuturePackets;
+ tmp;
+ prev = tmp, tmp = tmp->Next)
+ {
+ if(tmp->Sequence >= pkt->Sequence) break;
+ }
+
+ // Add if before first, or sequences don't match
+ if( !tmp || tmp->Sequence != pkt->Sequence )
+ {
+ if(prev)
+ prev->Next = pkt;
+ else
+ Connection->FuturePackets = pkt;
+ pkt->Next = tmp;
+ }
+ // Replace if larger
+ else if(pkt->Length > tmp->Length)
+ {
+ if(prev)
+ prev->Next = pkt;
+ pkt->Next = tmp->Next;
+ free(tmp);
+ }
+ else
+ {
+ free(pkt); // TODO: Find some way to remove this
+ }
+ SHORTREL( &Connection->lFuturePackets );
+ #endif
+ }
+ // Badly out of sequence packet
+ else
+ {
+ Log_Log("TCP", "Fully out of sequence packet (0x%08x not between 0x%08x and 0x%08x), dropped",
+ sequence_num, Connection->NextSequenceRcv, Connection->NextSequenceRcv+TCP_WINDOW_SIZE);
+ // TODO: Spec says we should send an empty ACK with the current state
+ }
+ break;
+
+ // --- Remote close states
+ case TCP_ST_CLOSE_WAIT:
+
+ // Ignore everything, CLOSE_WAIT is terminated by the client
+ Log_Debug("TCP", "CLOSE WAIT - Ignoring packets");
+
+ break;
+
+ // LAST-ACK - Waiting for the ACK of FIN (from CLOSE WAIT)
+ case TCP_ST_LAST_ACK:
+ if( Header->Flags & TCP_FLAG_ACK )
+ {
+ Connection->State = TCP_ST_FINISHED; // Connection completed
+ Log_Log("TCP", "LAST-ACK to CLOSED - Connection remote closed");
+ // TODO: Destrory the TCB
+ }
+ break;
+
+ // --- Local close States
+ case TCP_ST_FIN_WAIT1:
+ if( Header->Flags & TCP_FLAG_FIN )
+ {
+ Connection->State = TCP_ST_CLOSING;
+ Log_Debug("TCP", "Conn %p closed, sent FIN and recieved FIN", Connection);
+ VFS_MarkError(&Connection->Node, 1);
+
+ // ACK Packet
+ Header->DestPort = Header->SourcePort;
+ Header->SourcePort = htons(Connection->LocalPort);
+ Header->AcknowlegementNumber = Header->SequenceNumber;
+ Header->SequenceNumber = htonl(Connection->NextSequenceSend);
+ Header->WindowSize = htons(TCP_WINDOW_SIZE);
+ Header->Flags = TCP_FLAG_ACK;
+ TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
+ break ;
+ }
+
+ // TODO: Make sure that the packet is actually ACKing the FIN
+ if( Header->Flags & TCP_FLAG_ACK )
+ {
+ Connection->State = TCP_ST_FIN_WAIT2;
+ Log_Debug("TCP", "Conn %p closed, sent FIN ACKed", Connection);
+ VFS_MarkError(&Connection->Node, 1);
+ return ;
+ }
+ break;
+
+ case TCP_ST_FIN_WAIT2:
+ if( Header->Flags & TCP_FLAG_FIN )
+ {
+ Connection->State = TCP_ST_TIME_WAIT;
+ Log_Debug("TCP", "FIN sent and recieved, ACKing and going into TIME WAIT %p FINWAIT-2 -> TIME WAIT", Connection);
+ // Send ACK
+ Header->DestPort = Header->SourcePort;
+ Header->SourcePort = htons(Connection->LocalPort);
+ Header->AcknowlegementNumber = Header->SequenceNumber;
+ Header->SequenceNumber = htonl(Connection->NextSequenceSend);
+ Header->WindowSize = htons(TCP_WINDOW_SIZE);
+ Header->Flags = TCP_FLAG_ACK;
+ TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
+ }
+ break;
+
+ case TCP_ST_CLOSING:
+ // TODO: Make sure that the packet is actually ACKing the FIN
+ if( Header->Flags & TCP_FLAG_ACK )
+ {
+ Connection->State = TCP_ST_TIME_WAIT;
+ Log_Debug("TCP", "Conn %p CLOSING -> TIME WAIT", Connection);
+ VFS_MarkError(&Connection->Node, 1);
+ return ;
+ }
+ break;
+
+ // --- Closed (or near closed) states) ---
+ case TCP_ST_TIME_WAIT:
+ Log_Log("TCP", "Packets on Time-Wait, ignored");
+ break;
+
+ case TCP_ST_FINISHED:
+ Log_Log("TCP", "Packets when CLOSED, ignoring");
+ break;
+
+ //default:
+ // Log_Warning("TCP", "Unhandled TCP state %i", Connection->State);
+ // break;
+ }
+
+}
+
+/**
+ * \brief Appends a packet to the recieved list
+ * \param Connection Connection structure
+ * \param Data Packet contents
+ * \param Length Length of \a Data
+ */
+int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length)
+{
+ Mutex_Acquire( &Connection->lRecievedPackets );
+
+ if(Connection->RecievedBuffer->Length + Length > Connection->RecievedBuffer->Space )
+ {
+ VFS_MarkAvaliable(&Connection->Node, 1);
+ Log_Error("TCP", "Buffer filled, packet dropped (:%i) - %i + %i > %i",
+ Connection->LocalPort, Connection->RecievedBuffer->Length, Length,
+ Connection->RecievedBuffer->Space
+ );
+ Mutex_Release( &Connection->lRecievedPackets );
+ return 1;
+ }
+
+ RingBuffer_Write( Connection->RecievedBuffer, Data, Length );
+
+ VFS_MarkAvaliable(&Connection->Node, 1);
+
+ Mutex_Release( &Connection->lRecievedPackets );
+ return 0;
+}
+
+/**
+ * \brief Updates the connections recieved list from the future list
+ * \param Connection Connection structure
+ *
+ * Updates the recieved packets list with packets from the future (out
+ * of order) packets list that are now able to be added in direct
+ * sequence.
+ */
+void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection)
+{
+ #if CACHE_FUTURE_PACKETS_IN_BYTES
+ int i, length = 0;
+ Uint32 index;
+
+ // Calculate length of contiguous bytes
+ length = Connection->HighestSequenceRcvd - Connection->NextSequenceRcv;
+ index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE;
+ for( i = 0; i < length; i ++ )
+ {
+ if( Connection->FuturePacketValidBytes[i / 8] == 0xFF ) {
+ i += 7; index += 7;
+ continue;
+ }
+ else if( !(Connection->FuturePacketValidBytes[i / 8] & (1 << (i%8))) )
+ break;
+
+ index ++;
+ if(index > TCP_WINDOW_SIZE)
+ index -= TCP_WINDOW_SIZE;
+ }
+ length = i;
+
+ index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE;
+
+ // Write data to to the ring buffer
+ if( TCP_WINDOW_SIZE - index > length )
+ {
+ // Simple case
+ RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData + index, length );
+ }
+ else
+ {
+ int endLen = TCP_WINDOW_SIZE - index;
+ // 2-part case
+ RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData + index, endLen );
+ RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData, endLen - length );
+ }
+
+ // Mark (now saved) bytes as invalid
+ // - Align index
+ while(index % 8 && length)
+ {
+ Connection->FuturePacketData[index] = 0;
+ Connection->FuturePacketData[index/8] &= ~(1 << (index%8));
+ index ++;
+ if(index > TCP_WINDOW_SIZE)
+ index -= TCP_WINDOW_SIZE;
+ length --;
+ }
+ while( length > 7 )
+ {
+ Connection->FuturePacketData[index] = 0;
+ Connection->FuturePacketValidBytes[index/8] = 0;
+ length -= 8;
+ index += 8;
+ if(index > TCP_WINDOW_SIZE)
+ index -= TCP_WINDOW_SIZE;
+ }
+ while(length)
+ {
+ Connection->FuturePacketData[index] = 0;
+ Connection->FuturePacketData[index/8] &= ~(1 << (index%8));
+ index ++;
+ if(index > TCP_WINDOW_SIZE)
+ index -= TCP_WINDOW_SIZE;
+ length --;
+ }
+
+ #else
+ tTCPStoredPacket *pkt;
+ for(;;)
+ {
+ SHORTLOCK( &Connection->lFuturePackets );
+
+ // Clear out duplicates from cache
+ // - If a packet has just been recieved, and it is expected, then
+ // (since NextSequenceRcv = rcvd->Sequence + rcvd->Length) all
+ // packets in cache that are smaller than the next expected
+ // are now defunct.
+ pkt = Connection->FuturePackets;
+ while(pkt && pkt->Sequence < Connection->NextSequenceRcv)
+ {
+ tTCPStoredPacket *next = pkt->Next;
+ free(pkt);
+ pkt = next;
+ }
+
+ // If there's no packets left in cache, stop looking
+ if(!pkt || pkt->Sequence > Connection->NextSequenceRcv) {
+ SHORTREL( &Connection->lFuturePackets );
+ return;
+ }
+
+ // Delete packet from future list
+ Connection->FuturePackets = pkt->Next;
+
+ // Release list
+ SHORTREL( &Connection->lFuturePackets );
+
+ // Looks like we found one
+ TCP_INT_AppendRecieved(Connection, pkt);
+ Connection->NextSequenceRcv += pkt->Length;
+ free(pkt);
+ }
+ #endif