X-Git-Url: https://git.ucc.asn.au/?p=tpg%2Facess2.git;a=blobdiff_plain;f=Modules%2FIPStack%2Ftcp.c;h=bb71fdbf58638d9fc2447d292cc140f870641a10;hp=fe7c299dd4bd91afb5f296b20a1400dc32601eec;hb=c205f388f8722a5d73f71ee98b0232444c5c7e9d;hpb=fbdee4576c1abe0e817ed974c882bfec63eaa842 diff --git a/Modules/IPStack/tcp.c b/Modules/IPStack/tcp.c index fe7c299d..bb71fdbf 100644 --- a/Modules/IPStack/tcp.c +++ b/Modules/IPStack/tcp.c @@ -5,9 +5,12 @@ #define DEBUG 1 #include "ipstack.h" #include "ipv4.h" +#include "ipv6.h" #include "tcp.h" #define USE_SELECT 1 +#define HEXDUMP_INCOMING 0 +#define HEXDUMP_OUTGOING 0 #define CACHE_FUTURE_PACKETS_IN_BYTES 1 // Use a ring buffer to cache out of order packets #define TCP_MIN_DYNPORT 0xC000 @@ -23,7 +26,7 @@ void TCP_StartConnection(tTCPConnection *Conn); void TCP_SendPacket(tTCPConnection *Conn, size_t Length, tTCPHeader *Data); void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer); void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length); -void TCP_INT_AppendRecieved(tTCPConnection *Connection, tTCPStoredPacket *Ptk); +int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length); void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection); Uint16 TCP_GetUnusedPort(); int TCP_AllocatePort(Uint16 Port); @@ -64,9 +67,11 @@ Uint32 gaTCP_PortBitmap[0x800]; */ void TCP_Initialise(void) { + giTCP_NextOutPort += rand()%32; IPStack_AddFile(&gTCP_ServerFile); IPStack_AddFile(&gTCP_ClientFile); IPv4_RegisterCallback(IP4PROT_TCP, TCP_GetPacket); + IPv6_RegisterCallback(IP4PROT_TCP, TCP_GetPacket); } /** @@ -77,22 +82,43 @@ void TCP_Initialise(void) */ void TCP_SendPacket( tTCPConnection *Conn, size_t Length, tTCPHeader *Data ) { - size_t buflen; - Uint32 *buf; + Uint16 checksum[2]; + + Data->Checksum = 0; + checksum[1] = htons( ~IPv4_Checksum( (void*)Data, Length ) ); // Partial checksum + if(Length & 1) + ((Uint8*)Data)[Length] = 0; + + // TODO: Fragment packet + switch( Conn->Interface->Type ) { - case 4: // Append IPv4 Pseudo Header - buflen = 4 + 4 + 4 + ((Length+1)&~1); - buf = malloc( buflen ); - buf[0] = ((tIPv4*)Conn->Interface->Address)->L; - buf[1] = Conn->RemoteIP.v4.L; - buf[2] = (htons(Length)<<16) | (6<<8) | 0; - Data->Checksum = 0; - memcpy( &buf[3], Data, Length ); - Data->Checksum = htons( IPv4_Checksum( buf, buflen ) ); - free(buf); + case 4: + // Append IPv4 Pseudo Header + { + Uint32 buf[3]; + buf[0] = ((tIPv4*)Conn->Interface->Address)->L; + buf[1] = Conn->RemoteIP.v4.L; + buf[2] = (htons(Length)<<16) | (6<<8) | 0; + checksum[0] = htons( ~IPv4_Checksum(buf, sizeof(buf)) ); // Partial checksum + } + Data->Checksum = htons( IPv4_Checksum(checksum, 2*2) ); // Combine the two IPv4_SendPacket(Conn->Interface, Conn->RemoteIP.v4, IP4PROT_TCP, 0, Length, Data); break; + + case 6: + // Append IPv6 Pseudo Header + { + Uint32 buf[4+4+1+1]; + memcpy(buf, Conn->Interface->Address, 16); + memcpy(&buf[4], &Conn->RemoteIP, 16); + buf[8] = htonl(Length); + buf[9] = htonl(6); + checksum[0] = htons( ~IPv4_Checksum(buf, sizeof(buf)) ); // Partial checksum + } + Data->Checksum = htons( IPv4_Checksum(checksum, 2*2) ); // Combine the two + IPv6_SendPacket(Conn->Interface, Conn->RemoteIP.v6, IP4PROT_TCP, Length, Data); + break; } } @@ -109,17 +135,10 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe tTCPListener *srv; tTCPConnection *conn; - Log_Log("TCP", "TCP_GetPacket: SourcePort = %i, DestPort = %i", - ntohs(hdr->SourcePort), ntohs(hdr->DestPort)); -/* - Log_Log("TCP", "TCP_GetPacket: SequenceNumber = 0x%x", ntohl(hdr->SequenceNumber)); - Log_Log("TCP", "TCP_GetPacket: AcknowlegementNumber = 0x%x", ntohl(hdr->AcknowlegementNumber)); - Log_Log("TCP", "TCP_GetPacket: DataOffset = %i", hdr->DataOffset >> 4); - Log_Log("TCP", "TCP_GetPacket: WindowSize = %i", htons(hdr->WindowSize)); - Log_Log("TCP", "TCP_GetPacket: Checksum = 0x%x", htons(hdr->Checksum)); - Log_Log("TCP", "TCP_GetPacket: UrgentPointer = 0x%x", htons(hdr->UrgentPointer)); -*/ - Log_Log("TCP", "TCP_GetPacket: Flags = %s%s%s%s%s%s%s%s", + Log_Log("TCP", "TCP_GetPacket: :%i from [%s]:%i, Flags= %s%s%s%s%s%s%s%s", + ntohs(hdr->SourcePort), + IPStack_PrintAddress(Interface->Type, Address), + ntohs(hdr->DestPort), (hdr->Flags & TCP_FLAG_CWR) ? "CWR " : "", (hdr->Flags & TCP_FLAG_ECE) ? "ECE " : "", (hdr->Flags & TCP_FLAG_URG) ? "URG " : "", @@ -133,11 +152,13 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe if( Length > (hdr->DataOffset >> 4)*4 ) { Log_Log("TCP", "TCP_GetPacket: SequenceNumber = 0x%x", ntohl(hdr->SequenceNumber)); +#if HEXDUMP_INCOMING Debug_HexDump( - "[TCP ] Packet Data = ", + "TCP_GetPacket: Packet Data = ", (Uint8*)hdr + (hdr->DataOffset >> 4)*4, Length - (hdr->DataOffset >> 4)*4 ); +#endif } // Check Servers @@ -155,8 +176,6 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe // Is this in an established connection? for( conn = srv->Connections; conn; conn = conn->Next ) { - Log_Log("TCP", "TCP_GetPacket: conn->Interface(%p) == Interface(%p)", - conn->Interface, Interface); // Check that it is coming in on the same interface if(conn->Interface != Interface) continue; @@ -166,10 +185,8 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe if(conn->RemotePort != ntohs(hdr->SourcePort)) continue; // Check Source IP - if(conn->Interface->Type == 6 && !IP6_EQU(conn->RemoteIP.v6, *(tIPv6*)Address)) - continue; - if(conn->Interface->Type == 4 && !IP4_EQU(conn->RemoteIP.v4, *(tIPv4*)Address)) - continue; + if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) != 0 ) + continue ; Log_Log("TCP", "TCP_GetPacket: Matches connection %p", conn); // We have a response! @@ -274,9 +291,9 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe * \param Length Length of the packet */ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length) -{ - tTCPStoredPacket *pkt; +{ int dataLen; + Uint32 sequence_num; // Silently drop once finished // TODO: Check if this needs to be here @@ -306,7 +323,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // switch( Connection->State ) { - // Pre-init conneciton? + // Pre-init connection? case TCP_ST_CLOSED: Log_Log("TCP", "Packets to a closed connection?!"); break; @@ -387,31 +404,33 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // PSH - Has Data? // /NOTES - // Allocate and fill cached packet - pkt = malloc( sizeof(tTCPStoredPacket) + dataLen ); - pkt->Next = NULL; - pkt->Sequence = ntohl(Header->SequenceNumber); - pkt->Length = dataLen; - memcpy(pkt->Data, (Uint8*)Header + (Header->DataOffset>>4)*4, dataLen); + sequence_num = ntohl(Header->SequenceNumber); Log_Log("TCP", "0x%08x <= 0x%08x < 0x%08x", Connection->NextSequenceRcv, - pkt->Sequence, + ntohl(Header->SequenceNumber), Connection->NextSequenceRcv + TCP_WINDOW_SIZE ); // Is this packet the next expected packet? - if( pkt->Sequence == Connection->NextSequenceRcv ) + if( sequence_num == Connection->NextSequenceRcv ) { + int rv; // Ooh, Goodie! Add it to the recieved list - TCP_INT_AppendRecieved(Connection, pkt); - free(pkt); + 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 @@ -427,24 +446,32 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head //Connection->NextSequenceSend ++; } // Check if the packet is in window - else if( WrapBetween(Connection->NextSequenceRcv, pkt->Sequence, + 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 = pkt->Sequence % TCP_WINDOW_SIZE; - for( i = 0; i < pkt->Length; i ++ ) + index = sequence_num % TCP_WINDOW_SIZE; + for( i = 0; i < dataLen; i ++ ) { Connection->FuturePacketValidBytes[index/8] |= 1 << (index%8); - Connection->FuturePacketValidBytes[index] = pkt->Data[i]; + Connection->FuturePacketData[index] = dataptr[i]; // Do a wrap increment index ++; if(index == TCP_WINDOW_SIZE) index = 0; } #else - tTCPStoredPacket *tmp, *prev = NULL; + 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); @@ -477,7 +504,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head } else { - free(pkt); + free(pkt); // TODO: Find some way to remove this } SHORTREL( &Connection->lFuturePackets ); #endif @@ -486,8 +513,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head else { Log_Log("TCP", "Fully out of sequence packet (0x%08x not between 0x%08x and 0x%08x), dropped", - pkt->Sequence, Connection->NextSequenceRcv, Connection->NextSequenceRcv+TCP_WINDOW_SIZE); - free(pkt); + sequence_num, Connection->NextSequenceRcv, Connection->NextSequenceRcv+TCP_WINDOW_SIZE); // TODO: Spec says we should send an empty ACK with the current state } break; @@ -585,27 +611,30 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head /** * \brief Appends a packet to the recieved list * \param Connection Connection structure - * \param Pkt Packet structure on heap + * \param Data Packet contents + * \param Length Length of \a Data */ -void TCP_INT_AppendRecieved(tTCPConnection *Connection, tTCPStoredPacket *Pkt) +int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length) { Mutex_Acquire( &Connection->lRecievedPackets ); - if(Connection->RecievedBuffer->Length + Pkt->Length > Connection->RecievedBuffer->Space ) + + if(Connection->RecievedBuffer->Length + Length > Connection->RecievedBuffer->Space ) { - Log_Error("TCP", "Buffer filled, packet dropped (%s)", - // TCP_INT_DumpConnection(Connection) - "" + 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 ); - return ; + Mutex_Release( &Connection->lRecievedPackets ); + return 1; } - RingBuffer_Write( Connection->RecievedBuffer, Pkt->Data, Pkt->Length ); + RingBuffer_Write( Connection->RecievedBuffer, Data, Length ); - #if USE_SELECT VFS_MarkAvaliable(&Connection->Node, 1); - #endif Mutex_Release( &Connection->lRecievedPackets ); + return 0; } /** @@ -1065,7 +1094,7 @@ void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, void *Dat packet->SourcePort = htons(Connection->LocalPort); packet->DestPort = htons(Connection->RemotePort); packet->DataOffset = (sizeof(tTCPHeader)/4)*16; - packet->WindowSize = TCP_WINDOW_SIZE; + packet->WindowSize = htons(TCP_WINDOW_SIZE); packet->AcknowlegementNumber = htonl(Connection->NextSequenceRcv); packet->SequenceNumber = htonl(Connection->NextSequenceSend); @@ -1074,8 +1103,9 @@ void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, void *Dat memcpy(packet->Options, Data, Length); Log_Debug("TCP", "Send sequence 0x%08x", Connection->NextSequenceSend); - Debug_HexDump("[TCP ] TCP_INT_SendDataPacket: Data = ", - Data, Length); +#if HEXDUMP_OUTGOING + Debug_HexDump("TCP_INT_SendDataPacket: Data = ", Data, Length); +#endif TCP_SendPacket( Connection, sizeof(tTCPHeader)+Length, packet );