From: John Hodge Date: Wed, 21 Mar 2012 14:07:57 +0000 (+0800) Subject: Modules/IPStack - Moving to reduction of memcpy usage X-Git-Tag: rel0.15~724 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=849329d50395b44ac97c5b5145fc2df0749eace2;p=tpg%2Facess2.git Modules/IPStack - Moving to reduction of memcpy usage - Apears to have broken something in TCP receive... somehow. > Lock in RingBuffer_Write never succeeds --- diff --git a/KernelLand/Modules/IPStack/Makefile b/KernelLand/Modules/IPStack/Makefile index 0838a343..b0ee26b8 100644 --- a/KernelLand/Modules/IPStack/Makefile +++ b/KernelLand/Modules/IPStack/Makefile @@ -2,6 +2,7 @@ # OBJ := main.o interface.o +OBJ += buffer.o OBJ += link.o arp.o OBJ += ipv4.o icmp.o OBJ += ipv6.o diff --git a/KernelLand/Modules/IPStack/arp.c b/KernelLand/Modules/IPStack/arp.c index 9dd48b95..607f201e 100644 --- a/KernelLand/Modules/IPStack/arp.c +++ b/KernelLand/Modules/IPStack/arp.c @@ -149,9 +149,14 @@ tMacAddr ARP_Resolve4(tInterface *Interface, tIPv4 Address) req.SourceIP = *(tIPv4*)Interface->Address; req.DestMac = cMAC_BROADCAST; req.DestIP = Address; - + + tIPStackBuffer *buffer = IPStack_Buffer_CreateBuffer(3); // Assumes only a header and footer at link layer + IPStack_Buffer_AppendSubBuffer(buffer, sizeof(struct sArpRequest4), 0, &req, NULL, NULL); + // Send Request - Link_SendPacket(Interface->Adapter, 0x0806, req.DestMac, sizeof(struct sArpRequest4), &req); + Link_SendPacket(Interface->Adapter, 0x0806, req.DestMac, buffer); + + IPStack_Buffer_DestroyBuffer(buffer); timeout = now() + Interface->TimeoutDelay; @@ -333,7 +338,12 @@ void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffe req4->SourceMac.B[0], req4->SourceMac.B[1], req4->SourceMac.B[2], req4->SourceMac.B[3], req4->SourceMac.B[4], req4->SourceMac.B[5]); - Link_SendPacket(Adapter, 0x0806, req4->DestMac, sizeof(tArpRequest4), req4); + + // Assumes only a header and footer at link layer + tIPStackBuffer *buffer = IPStack_Buffer_CreateBuffer(3); + IPStack_Buffer_AppendSubBuffer(buffer, sizeof(struct sArpRequest4), 0, &req4, NULL, NULL); + Link_SendPacket(Adapter, 0x0806, req4->DestMac, buffer); + IPStack_Buffer_DestroyBuffer(buffer); } break; #if ARPv6 diff --git a/KernelLand/Modules/IPStack/buffer.c b/KernelLand/Modules/IPStack/buffer.c new file mode 100644 index 00000000..9151c1c1 --- /dev/null +++ b/KernelLand/Modules/IPStack/buffer.c @@ -0,0 +1,140 @@ +/* + * Acess2 Networking Stack + * - By John Hodge (thePowersGang) + * + * buffer.c + * - Scatter-gather handling + */ +#include "ipstack.h" +#include "include/buffer.h" + +// === STRUCTURES === +struct sIPStackBuffer +{ + int MaxSubBufffers; + int nSubBuffers; + size_t TotalLength; + struct _subbuffer + { + const void *Data; + size_t PreLength; + size_t PostLength; + // TODO: Callbacks? + } SubBuffers[]; +}; + +// === CODE === +tIPStackBuffer *IPStack_Buffer_CreateBuffer(int MaxBuffers) +{ + tIPStackBuffer *ret; + + ret = malloc( sizeof(*ret) + MaxBuffers * sizeof(ret->SubBuffers[0]) ); + ret->MaxSubBufffers = MaxBuffers; + ret->nSubBuffers = 0; + ret->TotalLength = 0; + memset(ret->SubBuffers, 0, MaxBuffers * sizeof(ret->SubBuffers[0])); + return ret; +} + +void IPStack_Buffer_DestroyBuffer(tIPStackBuffer *Buffer) +{ + // TODO: Fire callbacks? + Buffer->MaxSubBufffers = 0; + Buffer->nSubBuffers = 0; + free(Buffer); +} + +void IPStack_Buffer_AppendSubBuffer(tIPStackBuffer *Buffer, + size_t HeaderLen, size_t FooterLen, const void *Data, + tIPStackBufferCb Cb, void *Arg + ) +{ + if( Buffer->nSubBuffers == Buffer->MaxSubBufffers ) { + // Ah, oops? + Log_Error("IPStack", "Buffer %p only had %i sub-buffers allocated, which was not enough", + Buffer, Buffer->MaxSubBufffers); + return ; + } + + int index = Buffer->nSubBuffers++; + Buffer->TotalLength += HeaderLen + FooterLen; + + Buffer->SubBuffers[index].Data = Data; + Buffer->SubBuffers[index].PreLength = HeaderLen; + Buffer->SubBuffers[index].PostLength = FooterLen; +} + +size_t IPStack_Buffer_GetLength(tIPStackBuffer *Buffer) +{ + return Buffer->TotalLength; +} + +void *IPStack_Buffer_CompactBuffer(tIPStackBuffer *Buffer, size_t *Length) +{ + void *ret; + ret = malloc(Buffer->TotalLength); + if(!ret) { + *Length = 0; + return NULL; + } + + *Length = Buffer->TotalLength; + + Uint8 *dest = ret; + for( int i = Buffer->nSubBuffers; i --; ) + { + memcpy(dest, + Buffer->SubBuffers[i].Data, + Buffer->SubBuffers[i].PreLength + ); + dest += Buffer->SubBuffers[i].PreLength; + } + for( int i = 0; i < Buffer->nSubBuffers; i ++ ) + { + if( Buffer->SubBuffers[i].PostLength ) + { + memcpy(dest, + (Uint8*)Buffer->SubBuffers[i].Data + Buffer->SubBuffers[i].PreLength, + Buffer->SubBuffers[i].PostLength + ); + dest += Buffer->SubBuffers[i].PreLength; + } + } + return ret; +} + +int IPStack_Buffer_GetBuffer(tIPStackBuffer *Buffer, int Index, size_t *Length, const void **DataPtr) +{ + if( Index == -1 ) Index = 0; + + if( Index >= Buffer->nSubBuffers*2 ) { + return -1; + } + + if( Index > Buffer->nSubBuffers ) + { + // Appended buffers + Index -= Buffer->nSubBuffers; + + // Bit of a hack to avoid multiple calls which return a zero length + while( !Buffer->SubBuffers[Index].PostLength ) + { + if( Index++ == Buffer->nSubBuffers ) + return -1; + } + + *DataPtr = (Uint8*)Buffer->SubBuffers[Index].Data + Buffer->SubBuffers[Index].PreLength; + *Length = Buffer->SubBuffers[Index].PostLength; + + return (Index + 1) + Buffer->nSubBuffers; + } + else + { + Index = Buffer->nSubBuffers - Index; + // Prepended buffers + *DataPtr = Buffer->SubBuffers[Index].Data; + *Length = Buffer->SubBuffers[Index].PreLength; + return Buffer->nSubBuffers - (Index - 1); + } +} + diff --git a/KernelLand/Modules/IPStack/icmp.c b/KernelLand/Modules/IPStack/icmp.c index 16037199..f1355fa6 100644 --- a/KernelLand/Modules/IPStack/icmp.c +++ b/KernelLand/Modules/IPStack/icmp.c @@ -83,7 +83,11 @@ void ICMP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buff hdr->Checksum = 0; hdr->Checksum = htons( IPv4_Checksum( (Uint16*)hdr, Length/2 ) ); //Log_Debug("ICMPv4", "Checksum = 0x%04x", hdr->Checksum); - IPv4_SendPacket(Interface, *(tIPv4*)Address, 1, ntohs(hdr->Sequence), Length, hdr); + + tIPStackBuffer *buffer = IPStack_Buffer_CreateBuffer(1 + IPV4_BUFFERS); + IPStack_Buffer_AppendSubBuffer(buffer, Length, 0, hdr, NULL, NULL); + IPv4_SendPacket(Interface, *(tIPv4*)Address, 1, ntohs(hdr->Sequence), buffer); + IPStack_Buffer_DestroyBuffer(buffer); break; default: break; @@ -121,7 +125,10 @@ int ICMP_Ping(tInterface *Interface, tIPv4 Addr) ts = now(); - IPv4_SendPacket(Interface, Addr, 1, i, sizeof(buf), buf); + tIPStackBuffer *buffer = IPStack_Buffer_CreateBuffer(1 + IPV4_BUFFERS); + IPStack_Buffer_AppendSubBuffer(buffer, sizeof(buf), 0, buf, NULL, NULL); + IPv4_SendPacket(Interface, Addr, 1, i, buffer); + IPStack_Buffer_DestroyBuffer(buffer); end = ts + Interface->TimeoutDelay; while( !gICMP_PingSlots[i].bArrived && now() < end) Threads_Yield(); diff --git a/KernelLand/Modules/IPStack/include/buffer.h b/KernelLand/Modules/IPStack/include/buffer.h new file mode 100644 index 00000000..62c1308c --- /dev/null +++ b/KernelLand/Modules/IPStack/include/buffer.h @@ -0,0 +1,58 @@ +/* + * Acess2 Networking Stack + * - By John Hodge (thePowersGang) + * + * include/buffer.h + * - Outbound packet buffer management + */ +#ifndef _IPSTACK__BUFFER_H_ +#define _IPSTACK__BUFFER_H_ + +typedef struct sIPStackBuffer tIPStackBuffer; +typedef void (*tIPStackBufferCb)(void *Arg, size_t HeadLen, size_t FootLen, const void *Data); + +/** + * \brief Create a buffer object, with space for \a MaxSubBuffers calls to IPStack_Buffer_AppendSubBuffer + */ +extern tIPStackBuffer *IPStack_Buffer_CreateBuffer(int MaxSubBuffers); +/** + * \brief Destory a created buffer object + */ +extern void IPStack_Buffer_DestroyBuffer(tIPStackBuffer *Buffer); + +/** + * \brief Append a buffer to the object + * \param Buffer Buffer object from IPStack_Buffer_CreateBuffer + * \param HeadLength Number of bytes in \a Data that should be at the beginning of the packet + * \param FootLength Number of bytes in \a Data that should be at the end of the packet + * \param Data Actual data + * \param Cb Unused - eventually will be called when object is destroyed + * \param Arg Unused - will be argument for \a Cb + */ +extern void IPStack_Buffer_AppendSubBuffer(tIPStackBuffer *Buffer, + size_t HeadLength, size_t FootLength, const void *Data, + tIPStackBufferCb Cb, void *Arg + ); + +/** + * \brief Get the total length of a buffer + */ +extern size_t IPStack_Buffer_GetLength(tIPStackBuffer *Buffer); +/** + * \brief Get a sub-buffer from the buffer object + * \param PrevID Previous return value, or -1 to start + * \return -1 when the last buffer has been returned (*Length is not valid in this case) + * \note Used to iterate though the buffer without compacting it + */ +extern int IPStack_Buffer_GetBuffer(tIPStackBuffer *Buffer, int PrevID, size_t *Length, const void **Data); + +/** + * \brief Compact a buffer into a single contiguous malloc'd buffer + * \param Buffer Input buffer object + * \param Length Pointer in which to store the length of the allocated buffer + * \return malloc'd packet data + */ +extern void *IPStack_Buffer_CompactBuffer(tIPStackBuffer *Buffer, size_t *Length); + +#endif + diff --git a/KernelLand/Modules/IPStack/ipv4.c b/KernelLand/Modules/IPStack/ipv4.c index 9bafeead..d5c2f965 100644 --- a/KernelLand/Modules/IPStack/ipv4.c +++ b/KernelLand/Modules/IPStack/ipv4.c @@ -62,14 +62,15 @@ int IPv4_RegisterCallback(int ID, tIPCallback Callback) * \param Data Packet Data * \return Boolean Success */ -int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, int Length, const void *Data) +int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, tIPStackBuffer *Buffer) { tMacAddr to; - int bufSize = sizeof(tIPv4Header) + Length; - char buf[bufSize]; - tIPv4Header *hdr = (void*)buf; - int ret; + tIPv4Header hdr; + int length; + + length = IPStack_Buffer_GetLength(Buffer); + // --- Resolve destination MAC address to = ARP_Resolve4(Iface, Address); if( MAC_EQU(to, cMAC_ZERO) ) { // No route to host @@ -78,40 +79,47 @@ int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, int return 0; } - // OUTPUT Firewall rule go here - ret = IPTables_TestChain("OUTPUT", + // --- Handle OUTPUT firewall rules + // TODO: Update firewall rules for tIPStackBuffer + #if 0 + int ret = IPTables_TestChain("OUTPUT", 4, (tIPv4*)Iface->Address, &Address, Protocol, 0, - Length, Data); + length, Data); if(ret > 0) { // Just drop it (with an error) Log_Notice("IPv4", "Firewall dropped packet"); return 0; } + #endif + + // --- Initialise header + hdr.Version = 4; + hdr.HeaderLength = sizeof(tIPv4Header)/4; + hdr.DiffServices = 0; // TODO: Check - memcpy(&hdr->Options[0], Data, Length); - hdr->Version = 4; - hdr->HeaderLength = sizeof(tIPv4Header)/4; - hdr->DiffServices = 0; // TODO: Check - - hdr->Reserved = 0; - hdr->DontFragment = 0; - hdr->MoreFragments = 0; - hdr->FragOffLow = 0; - hdr->FragOffHi = 0; - - hdr->TotalLength = htons( bufSize ); - hdr->Identifcation = htons( ID ); // TODO: Check - hdr->TTL = DEFAULT_TTL; - hdr->Protocol = Protocol; - hdr->HeaderChecksum = 0; // Will be set later - hdr->Source = *(tIPv4*)Iface->Address; - hdr->Destination = Address; - hdr->HeaderChecksum = htons( IPv4_Checksum(hdr, sizeof(tIPv4Header)) ); + hdr.Reserved = 0; + hdr.DontFragment = 0; + hdr.MoreFragments = 0; + hdr.FragOffLow = 0; + hdr.FragOffHi = 0; + hdr.TotalLength = htons( sizeof(tIPv4Header) + length ); + hdr.Identifcation = htons( ID ); // TODO: Check + hdr.TTL = DEFAULT_TTL; + hdr.Protocol = Protocol; + hdr.HeaderChecksum = 0; // Will be set later + hdr.Source = *(tIPv4*)Iface->Address; + hdr.Destination = Address; + + // Actually set checksum (zeroed above) + hdr.HeaderChecksum = htons( IPv4_Checksum(&hdr, sizeof(tIPv4Header)) ); + + IPStack_Buffer_AppendSubBuffer(Buffer, sizeof(tIPv4Header), 0, &hdr, NULL, NULL); + Log_Log("IPv4", "Sending packet to %i.%i.%i.%i", Address.B[0], Address.B[1], Address.B[2], Address.B[3]); - Link_SendPacket(Iface->Adapter, IPV4_ETHERNET_ID, to, bufSize, buf); + Link_SendPacket(Iface->Adapter, IPV4_ETHERNET_ID, to, Buffer); return 1; } @@ -247,8 +255,8 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff hdr->Destination.B[2], hdr->Destination.B[3], ((tIPv4*)rt->NextHop)->B[0], ((tIPv4*)rt->NextHop)->B[1], ((tIPv4*)rt->NextHop)->B[2], ((tIPv4*)rt->NextHop)->B[3]); - Link_SendPacket(rt->Interface->Adapter, IPV4_ETHERNET_ID, to, Length, Buffer); - + Log_Warning("IPv4", "TODO: Implement forwarding with tIPStackBuffer"); +// Link_SendPacket(rt->Interface->Adapter, IPV4_ETHERNET_ID, to, Length, Buffer); return ; } diff --git a/KernelLand/Modules/IPStack/ipv4.h b/KernelLand/Modules/IPStack/ipv4.h index 7c69a623..dd78788f 100644 --- a/KernelLand/Modules/IPStack/ipv4.h +++ b/KernelLand/Modules/IPStack/ipv4.h @@ -6,6 +6,7 @@ #define _IPV4_H_ #include "ipstack.h" +#include "include/buffer.h" typedef struct sIPv4Header tIPv4Header; @@ -41,6 +42,7 @@ struct sIPv4Header #define IP4PROT_ICMP 1 #define IP4PROT_TCP 6 #define IP4PROT_UDP 17 +#define IPV4_BUFFERS 3 // 1 + Link #define IPV4_ETHERNET_ID 0x0800 @@ -48,6 +50,6 @@ struct sIPv4Header extern int IPv4_RegisterCallback(int ID, tIPCallback Callback); extern Uint16 IPv4_Checksum(const void *Buf, size_t Length); extern Uint32 IPv4_Netmask(int FixedBits); -extern int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, int Length, const void *Data); +extern int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, tIPStackBuffer *Buffer); #endif diff --git a/KernelLand/Modules/IPStack/link.c b/KernelLand/Modules/IPStack/link.c index 8bca51fc..37b72608 100644 --- a/KernelLand/Modules/IPStack/link.c +++ b/KernelLand/Modules/IPStack/link.c @@ -4,16 +4,19 @@ */ #include "ipstack.h" #include "link.h" +#include "include/buffer.h" // === CONSTANTS === #define MAX_PACKET_SIZE 2048 // === PROTOTYPES === void Link_RegisterType(Uint16 Type, tPacketCallback Callback); -void Link_InitCRC(); -Uint32 Link_CalculateCRC(void *Data, int Length); -void Link_SendPacket(tAdapter *Adapter, Uint16 Type, tMacAddr To, int Length, void *Buffer); +void Link_SendPacket(tAdapter *Adapter, Uint16 Type, tMacAddr To, tIPStackBuffer *Buffer); void Link_WatchDevice(tAdapter *Adapter); +// --- CRC --- +void Link_InitCRC(void); +Uint32 Link_CalculateCRC(tIPStackBuffer *Buffer); +Uint32 Link_CalculatePartialCRC(Uint32 CRC, const void *Data, int Length); // === GLOBALS === int giRegisteredTypes = 0; @@ -71,25 +74,31 @@ void Link_RegisterType(Uint16 Type, tPacketCallback Callback) * \fn void Link_SendPacket(tAdapter *Adapter, Uint16 Type, tMacAddr To, int Length, void *Buffer) * \brief Formats and sends a packet on the specified interface */ -void Link_SendPacket(tAdapter *Adapter, Uint16 Type, tMacAddr To, int Length, void *Buffer) +void Link_SendPacket(tAdapter *Adapter, Uint16 Type, tMacAddr To, tIPStackBuffer *Buffer) { - int bufSize = sizeof(tEthernetHeader) + ((Length+3)&~3) + 4; - Uint8 buf[bufSize]; // dynamic stack arrays ftw! + int length = IPStack_Buffer_GetLength(Buffer); + int ofs = 4 - (length & 3); + Uint8 buf[sizeof(tEthernetHeader) + ofs + 4]; tEthernetHeader *hdr = (void*)buf; - + + if( ofs == 4 ) ofs = 0; + Log_Log("Net Link", "Sending %i bytes to %02x:%02x:%02x:%02x:%02x:%02x (Type 0x%x)", - Length, To.B[0], To.B[1], To.B[2], To.B[3], To.B[4], To.B[5], Type); - + length, To.B[0], To.B[1], To.B[2], To.B[3], To.B[4], To.B[5], Type); + hdr->Dest = To; hdr->Src = Adapter->MacAddr; hdr->Type = htons(Type); + *(Uint32*)(buf + sizeof(tEthernetHeader) + ofs) = 0; + + IPStack_Buffer_AppendSubBuffer(Buffer, sizeof(tEthernetHeader), ofs + 4, hdr, NULL, NULL); - memcpy(hdr->Data, Buffer, Length); - - *(Uint32*) &hdr->Data[bufSize-4] = 0; - *(Uint32*) &hdr->Data[bufSize-4] = htonl( Link_CalculateCRC(buf, bufSize) ); - - VFS_Write(Adapter->DeviceFD, bufSize, buf); + *(Uint32*)(buf + sizeof(tEthernetHeader) + ofs) = htonl( Link_CalculateCRC(Buffer) ); + + size_t outlen = 0; + void *data = IPStack_Buffer_CompactBuffer(Buffer, &outlen); + VFS_Write(Adapter->DeviceFD, outlen, data); + free(data); } void Link_WorkerThread(void *Ptr) @@ -181,45 +190,49 @@ void Link_WatchDevice(tAdapter *Adapter) #define QUOTIENT 0x04c11db7 void Link_InitCRC(void) { - int i, j; - Uint32 crc; - - for (i = 0; i < 256; i++) - { - crc = i << 24; - for (j = 0; j < 8; j++) - { - if (crc & 0x80000000) - crc = (crc << 1) ^ QUOTIENT; - else - crc = crc << 1; - } - gaiLink_CRCTable[i] = crc; - } + int i, j; + Uint32 crc; + + for (i = 0; i < 256; i++) + { + crc = i << 24; + for (j = 0; j < 8; j++) + { + if (crc & 0x80000000) + crc = (crc << 1) ^ QUOTIENT; + else + crc = crc << 1; + } + gaiLink_CRCTable[i] = crc; + } gbLink_CRCTableGenerated = 1; } -Uint32 Link_CalculateCRC(void *Data, int Length) +Uint32 Link_CalculateCRC(tIPStackBuffer *Buffer) +{ + Uint32 ret = 0xFFFFFFFF; + const void *data; + size_t length; + + int id = -1; + while( (id = IPStack_Buffer_GetBuffer(Buffer, id, &length, &data)) != -1 ) + { + ret = Link_CalculatePartialCRC(ret, data, length); + } + + return ~ret; +} + +Uint32 Link_CalculatePartialCRC(Uint32 CRC, const void *Data, int Length) { // x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 - Uint32 result; - int i; - Uint32 *data = Data; - - if(Length < 4) return 0; - - result = *data++ << 24; - result |= *data++ << 16; - result |= *data++ << 8; - result |= *data++; - result = ~ result; - Length -= 4; - - for( i = 0; i < Length; i++ ) - { - result = (result << 8 | *data++) ^ gaiLink_CRCTable[result >> 24]; - } - - return ~result; + const Uint32 *data = Data; + + for( int i = 0; i < Length/4; i++ ) + { + CRC = (CRC << 8 | *data++) ^ gaiLink_CRCTable[CRC >> 24]; + } + + return CRC; } diff --git a/KernelLand/Modules/IPStack/link.h b/KernelLand/Modules/IPStack/link.h index d96008d4..bdea0e2c 100644 --- a/KernelLand/Modules/IPStack/link.h +++ b/KernelLand/Modules/IPStack/link.h @@ -5,11 +5,13 @@ #ifndef _LINK_H_ #define _LINK_H_ +#include "include/buffer.h" + // === EXTERNAL === typedef void (*tPacketCallback)(tAdapter *Interface, tMacAddr From, int Length, void *Buffer); extern void Link_RegisterType(Uint16 Type, tPacketCallback Callback); -extern void Link_SendPacket(tAdapter *Interface, Uint16 Type, tMacAddr To, int Length, void *Buffer); +extern void Link_SendPacket(tAdapter *Interface, Uint16 Type, tMacAddr To, tIPStackBuffer *Buffer); extern void Link_WatchDevice(tAdapter *Adapter); // === INTERNAL === diff --git a/KernelLand/Modules/IPStack/tcp.c b/KernelLand/Modules/IPStack/tcp.c index 20c22f80..ee71bc7f 100644 --- a/KernelLand/Modules/IPStack/tcp.c +++ b/KernelLand/Modules/IPStack/tcp.c @@ -23,7 +23,7 @@ // === PROTOTYPES === void TCP_Initialise(void); void TCP_StartConnection(tTCPConnection *Conn); -void TCP_SendPacket(tTCPConnection *Conn, size_t Length, tTCPHeader *Data); +void TCP_SendPacket(tTCPConnection *Conn, tTCPHeader *Header, size_t DataLen, const void *Data); void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer); void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length); int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length); @@ -94,30 +94,42 @@ void TCP_Initialise(void) * \param Length Length of data * \param Data Packet data (cast as a TCP Header) */ -void TCP_SendPacket( tTCPConnection *Conn, size_t Length, tTCPHeader *Data ) +void TCP_SendPacket( tTCPConnection *Conn, tTCPHeader *Header, size_t Length, const void *Data ) { - Uint16 checksum[2]; - - Data->Checksum = 0; - checksum[1] = htons( ~IPv4_Checksum( (void*)Data, Length ) ); // Partial checksum - if(Length & 1) - ((Uint8*)Data)[Length] = 0; + tIPStackBuffer *buffer; + Uint16 checksum[3]; + int packlen = sizeof(*Header) + Length; + + buffer = IPStack_Buffer_CreateBuffer(2 + IPV4_BUFFERS); + if( Data && Length ) + IPStack_Buffer_AppendSubBuffer(buffer, Length, 0, Data, NULL, NULL); + IPStack_Buffer_AppendSubBuffer(buffer, sizeof(*Header), 0, Header, NULL, NULL); + + Log_Debug("TCP", "Sending %i+%i to %s:%i", sizeof(*Header), Length, + IPStack_PrintAddress(Conn->Interface->Type, &Conn->RemoteIP), + Conn->RemotePort + ); + + Header->Checksum = 0; + checksum[1] = htons( ~IPv4_Checksum(Header, sizeof(tTCPHeader)) ); + checksum[2] = htons( ~IPv4_Checksum(Data, Length) ); // TODO: Fragment packet switch( Conn->Interface->Type ) { case 4: - // Append IPv4 Pseudo Header + // Get IPv4 pseudo-header checksum { Uint32 buf[3]; buf[0] = ((tIPv4*)Conn->Interface->Address)->L; buf[1] = Conn->RemoteIP.v4.L; - buf[2] = (htons(Length)<<16) | (6<<8) | 0; + buf[2] = (htons(packlen)<<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); + // - Combine checksums + Header->Checksum = htons( IPv4_Checksum(checksum, sizeof(checksum)) ); + IPv4_SendPacket(Conn->Interface, Conn->RemoteIP.v4, IP4PROT_TCP, 0, buffer); break; case 6: @@ -126,11 +138,11 @@ void TCP_SendPacket( tTCPConnection *Conn, size_t Length, tTCPHeader *Data ) Uint32 buf[4+4+1+1]; memcpy(buf, Conn->Interface->Address, 16); memcpy(&buf[4], &Conn->RemoteIP, 16); - buf[8] = htonl(Length); + buf[8] = htonl(packlen); 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 + Header->Checksum = htons( IPv4_Checksum(checksum, sizeof(checksum)) ); // Combine the two IPv6_SendPacket(Conn->Interface, Conn->RemoteIP.v6, IP4PROT_TCP, Length, Data); break; } @@ -176,107 +188,104 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe } // Check Servers + for( srv = gTCP_Listeners; srv; srv = srv->Next ) { - for( srv = gTCP_Listeners; srv; srv = srv->Next ) + // Check if the server is active + if(srv->Port == 0) continue; + // Check the interface + if(srv->Interface && srv->Interface != Interface) continue; + // Check the destination port + if(srv->Port != htons(hdr->DestPort)) continue; + + Log_Log("TCP", "TCP_GetPacket: Matches server %p", srv); + // Is this in an established connection? + for( conn = srv->Connections; conn; conn = conn->Next ) { - // Check if the server is active - if(srv->Port == 0) continue; - // Check the interface - if(srv->Interface && srv->Interface != Interface) continue; - // Check the destination port - if(srv->Port != htons(hdr->DestPort)) continue; - - Log_Log("TCP", "TCP_GetPacket: Matches server %p", srv); - // Is this in an established connection? - for( conn = srv->Connections; conn; conn = conn->Next ) - { - // Check that it is coming in on the same interface - if(conn->Interface != Interface) continue; - - // Check Source Port - Log_Log("TCP", "TCP_GetPacket: conn->RemotePort(%i) == hdr->SourcePort(%i)", - conn->RemotePort, ntohs(hdr->SourcePort)); - if(conn->RemotePort != ntohs(hdr->SourcePort)) continue; - - // Check Source IP - Log_Debug("TCP", "TCP_GetPacket: conn->RemoteIP(%s)", - IPStack_PrintAddress(conn->Interface->Type, &conn->RemoteIP)); - Log_Debug("TCP", " == Address(%s)", - IPStack_PrintAddress(conn->Interface->Type, Address)); - 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! - TCP_INT_HandleConnectionPacket(conn, hdr, Length); - - return; - } + // Check that it is coming in on the same interface + if(conn->Interface != Interface) continue; - Log_Log("TCP", "TCP_GetPacket: Opening Connection"); - // Open a new connection (well, check that it's a SYN) - if(hdr->Flags != TCP_FLAG_SYN) { - Log_Log("TCP", "TCP_GetPacket: Packet is not a SYN"); - return ; - } - - // TODO: Check for halfopen max - - conn = calloc(1, sizeof(tTCPConnection)); - conn->State = TCP_ST_SYN_RCVD; - conn->LocalPort = srv->Port; - conn->RemotePort = ntohs(hdr->SourcePort); - conn->Interface = Interface; - - switch(Interface->Type) - { - case 4: conn->RemoteIP.v4 = *(tIPv4*)Address; break; - case 6: conn->RemoteIP.v6 = *(tIPv6*)Address; break; - } - - conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE ); - - conn->NextSequenceRcv = ntohl( hdr->SequenceNumber ) + 1; - conn->NextSequenceSend = rand(); - - // Create node - conn->Node.NumACLs = 1; - conn->Node.ACLs = &gVFS_ACL_EveryoneRW; - conn->Node.ImplPtr = conn; - conn->Node.ImplInt = srv->NextID ++; - conn->Node.Type = &gTCP_ClientNodeType; // TODO: Special type for the server end? - - // Hmm... Theoretically, this lock will never have to wait, - // as the interface is locked to the watching thread, and this - // runs in the watching thread. But, it's a good idea to have - // it, just in case - // Oh, wait, there is a case where a wildcard can be used - // (srv->Interface == NULL) so having the lock is a good idea - SHORTLOCK(&srv->lConnections); - if( !srv->Connections ) - srv->Connections = conn; - else - srv->ConnectionsTail->Next = conn; - srv->ConnectionsTail = conn; - if(!srv->NewConnections) - srv->NewConnections = conn; - VFS_MarkAvaliable( &srv->Node, 1 ); - SHORTREL(&srv->lConnections); - - // Send the SYN ACK - hdr->Flags |= TCP_FLAG_ACK; - hdr->AcknowlegementNumber = htonl(conn->NextSequenceRcv); - hdr->SequenceNumber = htonl(conn->NextSequenceSend); - hdr->DestPort = hdr->SourcePort; - hdr->SourcePort = htons(srv->Port); - hdr->DataOffset = (sizeof(tTCPHeader)/4) << 4; - TCP_SendPacket( conn, sizeof(tTCPHeader), hdr ); - conn->NextSequenceSend ++; + // Check Source Port + Log_Log("TCP", "TCP_GetPacket: conn->RemotePort(%i) == hdr->SourcePort(%i)", + conn->RemotePort, ntohs(hdr->SourcePort)); + if(conn->RemotePort != ntohs(hdr->SourcePort)) continue; + + // Check Source IP + Log_Debug("TCP", "TCP_GetPacket: conn->RemoteIP(%s)", + IPStack_PrintAddress(conn->Interface->Type, &conn->RemoteIP)); + Log_Debug("TCP", " == Address(%s)", + IPStack_PrintAddress(conn->Interface->Type, Address)); + 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! + TCP_INT_HandleConnectionPacket(conn, hdr, Length); + + return; + } + + Log_Log("TCP", "TCP_GetPacket: Opening Connection"); + // Open a new connection (well, check that it's a SYN) + if(hdr->Flags != TCP_FLAG_SYN) { + Log_Log("TCP", "TCP_GetPacket: Packet is not a SYN"); return ; } + + // TODO: Check for halfopen max + + conn = calloc(1, sizeof(tTCPConnection)); + conn->State = TCP_ST_SYN_RCVD; + conn->LocalPort = srv->Port; + conn->RemotePort = ntohs(hdr->SourcePort); + conn->Interface = Interface; + + switch(Interface->Type) + { + case 4: conn->RemoteIP.v4 = *(tIPv4*)Address; break; + case 6: conn->RemoteIP.v6 = *(tIPv6*)Address; break; + } + + conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE ); + + conn->NextSequenceRcv = ntohl( hdr->SequenceNumber ) + 1; + conn->NextSequenceSend = rand(); + + // Create node + conn->Node.NumACLs = 1; + conn->Node.ACLs = &gVFS_ACL_EveryoneRW; + conn->Node.ImplPtr = conn; + conn->Node.ImplInt = srv->NextID ++; + conn->Node.Type = &gTCP_ClientNodeType; // TODO: Special type for the server end? + + // Hmm... Theoretically, this lock will never have to wait, + // as the interface is locked to the watching thread, and this + // runs in the watching thread. But, it's a good idea to have + // it, just in case + // Oh, wait, there is a case where a wildcard can be used + // (srv->Interface == NULL) so having the lock is a good idea + SHORTLOCK(&srv->lConnections); + if( !srv->Connections ) + srv->Connections = conn; + else + srv->ConnectionsTail->Next = conn; + srv->ConnectionsTail = conn; + if(!srv->NewConnections) + srv->NewConnections = conn; + VFS_MarkAvaliable( &srv->Node, 1 ); + SHORTREL(&srv->lConnections); + + // Send the SYN ACK + hdr->Flags |= TCP_FLAG_ACK; + hdr->AcknowlegementNumber = htonl(conn->NextSequenceRcv); + hdr->SequenceNumber = htonl(conn->NextSequenceSend); + hdr->DestPort = hdr->SourcePort; + hdr->SourcePort = htons(srv->Port); + hdr->DataOffset = (sizeof(tTCPHeader)/4) << 4; + TCP_SendPacket( conn, hdr, 0, NULL ); + conn->NextSequenceSend ++; + return ; } - // Check Open Connections { for( conn = gTCP_OutbountCons; conn; conn = conn->Next ) @@ -358,7 +367,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head Header->WindowSize = htons(TCP_WINDOW_SIZE); Header->Flags = TCP_FLAG_ACK; Header->DataOffset = (sizeof(tTCPHeader)/4) << 4; - TCP_SendPacket( Connection, sizeof(tTCPHeader), Header ); + TCP_SendPacket( Connection, Header, 0, NULL ); if( Header->Flags & TCP_FLAG_ACK ) { @@ -412,7 +421,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv); Header->SequenceNumber = htonl(Connection->NextSequenceSend); Header->Flags |= TCP_FLAG_ACK; - TCP_SendPacket( Connection, sizeof(tTCPHeader), Header ); + TCP_SendPacket( Connection, Header, 0, NULL ); return ; } @@ -459,7 +468,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head 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 ); + TCP_SendPacket( Connection, Header, 0, NULL ); //Connection->NextSequenceSend ++; } // Check if the packet is in window @@ -568,7 +577,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head Header->SequenceNumber = htonl(Connection->NextSequenceSend); Header->WindowSize = htons(TCP_WINDOW_SIZE); Header->Flags = TCP_FLAG_ACK; - TCP_SendPacket( Connection, sizeof(tTCPHeader), Header ); + TCP_SendPacket( Connection, Header, 0, NULL ); break ; } @@ -594,7 +603,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head Header->SequenceNumber = htonl(Connection->NextSequenceSend); Header->WindowSize = htons(TCP_WINDOW_SIZE); Header->Flags = TCP_FLAG_ACK; - TCP_SendPacket( Connection, sizeof(tTCPHeader), Header ); + TCP_SendPacket( Connection, Header, 0, NULL ); } break; @@ -1139,7 +1148,7 @@ void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, const voi Debug_HexDump("TCP_INT_SendDataPacket: Data = ", Data, Length); #endif - TCP_SendPacket( Connection, sizeof(tTCPHeader)+Length, packet ); + TCP_SendPacket( Connection, packet, Length, Data ); Connection->NextSequenceSend += Length; } @@ -1211,7 +1220,7 @@ void TCP_StartConnection(tTCPConnection *Conn) hdr.WindowSize = htons(TCP_WINDOW_SIZE); // Max hdr.Checksum = 0; // TODO - TCP_SendPacket( Conn, sizeof(tTCPHeader), &hdr ); + TCP_SendPacket( Conn, &hdr, 0, NULL ); Conn->NextSequenceSend ++; Conn->State = TCP_ST_SYN_SENT; @@ -1312,7 +1321,7 @@ void TCP_Client_Close(tVFS_Node *Node) packet.SequenceNumber = htonl(conn->NextSequenceSend); packet.Flags = TCP_FLAG_FIN; - TCP_SendPacket( conn, sizeof(tTCPHeader), &packet ); + TCP_SendPacket( conn, &packet, 0, NULL ); } switch( conn->State ) diff --git a/KernelLand/Modules/IPStack/udp.c b/KernelLand/Modules/IPStack/udp.c index 0f6ec3df..8b0904c2 100644 --- a/KernelLand/Modules/IPStack/udp.c +++ b/KernelLand/Modules/IPStack/udp.c @@ -144,7 +144,7 @@ void UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, */ void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, Uint16 Port, const void *Data, size_t Length) { - tUDPHeader *hdr; + tUDPHeader hdr; if(Channel->Interface && Channel->Interface->Type != AddrType) return ; @@ -152,17 +152,17 @@ void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, U { case 4: // Create the packet - hdr = malloc(sizeof(tUDPHeader)+Length); - hdr->SourcePort = htons( Channel->LocalPort ); - hdr->DestPort = htons( Port ); - hdr->Length = htons( sizeof(tUDPHeader) + Length ); - hdr->Checksum = 0; // Checksum can be zero on IPv4 - memcpy(hdr->Data, Data, Length); + hdr.SourcePort = htons( Channel->LocalPort ); + hdr.DestPort = htons( Port ); + hdr.Length = htons( sizeof(tUDPHeader) + Length ); + hdr.Checksum = 0; // Checksum can be zero on IPv4 // Pass on the the IPv4 Layer + tIPStackBuffer *buffer = IPStack_Buffer_CreateBuffer(2 + IPV4_BUFFERS); + IPStack_Buffer_AppendSubBuffer(buffer, Length, 0, Data, NULL, NULL); + IPStack_Buffer_AppendSubBuffer(buffer, sizeof(hdr), 0, &hdr, NULL, NULL); // TODO: What if Channel->Interface is NULL here? - IPv4_SendPacket(Channel->Interface, *(tIPv4*)Address, IP4PROT_UDP, 0, sizeof(tUDPHeader)+Length, hdr); - // Free allocated packet - free(hdr); + IPv4_SendPacket(Channel->Interface, *(tIPv4*)Address, IP4PROT_UDP, 0, buffer); + IPStack_Buffer_DestroyBuffer(buffer); break; } }