void IPv4_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer);
tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast);
Uint32 IPv4_Netmask(int FixedBits);
-Uint16 IPv4_Checksum(const Uint16 *Buf, int WordCount);
+Uint16 IPv4_Checksum(const void *Buf, size_t Length);
int IPv4_Ping(tInterface *Iface, tIPv4 Addr);
// === GLOBALS ===
hdr->HeaderChecksum = 0; // Will be set later
hdr->Source = *(tIPv4*)Iface->Address;
hdr->Destination = Address;
- hdr->HeaderChecksum = htons(IPv4_Checksum((Uint16*)hdr, sizeof(tIPv4Header)/2));
+ hdr->HeaderChecksum = htons( IPv4_Checksum(hdr, sizeof(tIPv4Header)) );
Log_Log("IPv4", "Sending packet to %i.%i.%i.%i",
Address.B[0], Address.B[1], Address.B[2], Address.B[3]);
Uint16 hdrVal, compVal;
hdrVal = ntohs(hdr->HeaderChecksum);
hdr->HeaderChecksum = 0;
- compVal = IPv4_Checksum((Uint16*)hdr, (hdr->HeaderLength * 4) / 2);
+ compVal = IPv4_Checksum(hdr, hdr->HeaderLength * 4);
if(hdrVal != compVal) {
Log_Log("IPv4", "Header checksum fails (%04x != %04x)", hdrVal, compVal);
return ;
*
* One's complement sum of all 16-bit words (bitwise inverted)
*/
-Uint16 IPv4_Checksum(const Uint16 *Buf, int WordCount)
+Uint16 IPv4_Checksum(const void *Buf, size_t Length)
{
+ const Uint16 *words = Buf;
Uint32 sum = 0;
int i;
// Sum all whole words
- for(i = 0; i < WordCount; i++ )
+ for(i = 0; i < Length/2; i++ )
{
- Uint16 val = ntohs(Buf[i]);
- sum += val;
+ sum += ntohs(words[i]);
}
+ if( Length & 1 )
+ sum += ntohs( words[i] & 0xFF );
// Apply one's complement
while (sum >> 16)
#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
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);
+void 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);
IPStack_AddFile(&gTCP_ServerFile);
IPStack_AddFile(&gTCP_ClientFile);
IPv4_RegisterCallback(IP4PROT_TCP, TCP_GetPacket);
+ IPv6_RegisterCallback(IP4PROT_TCP, TCP_GetPacket);
}
/**
*/
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 );
- if(Length & 1)
- ((Uint8*)buf)[12+Length] = 0;
- Data->Checksum = htons( IPv4_Checksum( (Uint16*)buf, buflen/2 ) );
- 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;
}
}
if( Length > (hdr->DataOffset >> 4)*4 )
{
Log_Log("TCP", "TCP_GetPacket: SequenceNumber = 0x%x", ntohl(hdr->SequenceNumber));
+#if HEXDUMP_INCOMING
Debug_HexDump(
"TCP_GetPacket: Packet Data = ",
(Uint8*)hdr + (hdr->DataOffset >> 4)*4,
Length - (hdr->DataOffset >> 4)*4
);
+#endif
}
// Check Servers
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!
* \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
//
switch( Connection->State )
{
- // Pre-init conneciton?
+ // Pre-init connection?
case TCP_ST_CLOSED:
Log_Log("TCP", "Packets to a closed connection?!");
break;
// 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 )
{
// Ooh, Goodie! Add it to the recieved list
- TCP_INT_AppendRecieved(Connection, pkt);
- free(pkt);
+ TCP_INT_AppendRecieved(Connection,
+ (Uint8*)Header + (Header->DataOffset>>4)*4,
+ dataLen
+ );
Log_Log("TCP", "0x%08x += %i", Connection->NextSequenceRcv, dataLen);
Connection->NextSequenceRcv += dataLen;
//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);
}
else
{
- free(pkt);
+ free(pkt); // TODO: Find some way to remove this
}
SHORTREL( &Connection->lFuturePackets );
#endif
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;
/**
* \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)
+void 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)
return ;
}
- RingBuffer_Write( Connection->RecievedBuffer, Pkt->Data, Pkt->Length );
+ RingBuffer_Write( Connection->RecievedBuffer, Data, Length );
VFS_MarkAvaliable(&Connection->Node, 1);
memcpy(packet->Options, Data, Length);
Log_Debug("TCP", "Send sequence 0x%08x", Connection->NextSequenceSend);
+#if HEXDUMP_OUTGOING
Debug_HexDump("TCP_INT_SendDataPacket: Data = ", Data, Length);
+#endif
TCP_SendPacket( Connection, sizeof(tTCPHeader)+Length, packet );