Modules/IPStack - Add ICMPv6 (not tested), fix TCP packet caching
authorJohn Hodge <[email protected]>
Wed, 19 Mar 2014 14:11:30 +0000 (22:11 +0800)
committerJohn Hodge <[email protected]>
Wed, 19 Mar 2014 14:11:30 +0000 (22:11 +0800)
KernelLand/Modules/IPStack/Makefile
KernelLand/Modules/IPStack/icmpv6.c [new file with mode: 0644]
KernelLand/Modules/IPStack/icmpv6.h [new file with mode: 0644]
KernelLand/Modules/IPStack/ipv6.h
KernelLand/Modules/IPStack/tcp.c
KernelLand/Modules/IPStack/tcp.h

index 0d8f582..ca0b9aa 100644 (file)
@@ -5,7 +5,7 @@ OBJ := main.o interface.o adapters.o
 OBJ += buffer.o
 OBJ += link.o hwaddr_cache.o
 OBJ += ipv4.o icmp.o arp.o
-OBJ += ipv6.o
+OBJ += ipv6.o icmpv6.o
 OBJ += firewall.o routing.o
 OBJ += udp.o tcp.o
 NAME := IPStack
diff --git a/KernelLand/Modules/IPStack/icmpv6.c b/KernelLand/Modules/IPStack/icmpv6.c
new file mode 100644 (file)
index 0000000..571323e
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Acess2 IP Stack
+ *
+ * icmpv6.c
+ * - Internet Control Message Protocol v6
+ */
+#include "ipstack.h"
+#include "ipv6.h"
+#include "ipv4.h"      // For the IP Checksum
+#include "icmpv6.h"
+#include "link.h"
+#include "hwaddr_cache.h"
+#include "include/adapters_int.h"
+
+// === GLOBALS ===
+void   ICMPv6_GetPacket(tInterface *Interface, void *Address, int Length, const void *Buffer);
+ int   ICMPv6_ND_GetOpt(size_t Length, const void *Buffer, Uint8 OptID, const void **Ptr);
+
+// === CODE ===
+void ICMPv6_Initialise(void)
+{
+       
+}
+
+void ICMPv6_GetPacket(tInterface *Interface, void *Address, int Length, const void *Buffer)
+{
+       if( Length < sizeof(tICMPv6_Header))
+               return ;
+       const tICMPv6_Header    *hdr = Buffer;
+       
+       // Validate checksum
+       if( IPv4_Checksum(Buffer, Length) != 0 )
+               return ;
+
+       if( hdr->Type == ICMPV6_INFO_NEIGHBOUR_ADVERTISMENT )
+       {
+               if( Length < sizeof(tICMPv6_Header) + sizeof(tICMPv6_NA) )
+                       return ;
+               // TODO: Check that IP.HopLimt == 255
+               const tICMPv6_NA        *na = (const void*)(hdr+1);
+               if( !(na->Flags & (1 << 1)) ) {
+                       // Unsolicited, TODO
+                       return ;
+               }
+               if( na->Flags & (1 << 2) ) {
+                       // Override, force update
+               }
+               const tICMPv6_Opt_LinkAddr      *la = NULL;
+               if( ICMPv6_ND_GetOpt(Length-sizeof(*hdr)+sizeof(*na), na+1, ICMPV6_OPTION_SRCLINK, (const void**)&la) )
+                       return ;
+               if( !la ) {
+                       LOG("No link address on neighbor advertisement");
+                       return;
+               }
+               
+               HWCache_Set(Interface->Adapter, 6, Address, (const tMacAddr*)la->Address);
+       }
+       else {
+               // Return unhandled?
+       }
+       
+       switch(hdr->Type)
+       {
+       case ICMPV6_INFO_ROUTER_SOLICITATION:
+               // TODO: If routing is active, send out RA
+               break;
+       case ICMPV6_INFO_ROUTER_ADVERTISEMENT: {
+               // TODO: If routing INACTIVE, and interface is ::/0, set address
+               break; }
+       case ICMPV6_INFO_NEIGHBOUR_SOLICITATION:
+               if( Length < sizeof(tICMPv6_Header) + sizeof(tICMPv6_NS) )
+                       return ;
+               // TODO: Check that IP.HopLimt == 255
+               break;
+       case ICMPV6_INFO_NEIGHBOUR_ADVERTISMENT:
+               //HWCache_Set(Interface->Adapter, 
+               break;
+       }
+}
+
+int ICMPv6_ND_GetOpt(size_t Length, const void *Buffer, Uint8 OptID, const void **Ptr)
+{
+       const struct {
+               Uint8   Type;
+               Uint8   Length;
+               Uint16  _resvd1;
+               Uint32  _resvd2;
+       }       *opts = Buffer;
+       
+       while( Length >= sizeof(*opts))
+       {
+               if( opts->Length == 0 )
+                       return 1;
+               if( opts->Length * 8 > Length )
+                       return 1;
+               
+               if( opts->Type == OptID ) {
+                       *Ptr = opts;
+                       return 0;
+               }
+               opts += opts->Length;
+       }
+       return 0;
+}
+
+void ICMPv6_SendNS(tInterface *Interface, const void *Address)
+{
+       const Uint8     *addr8 = Address;
+       struct {
+               tIPv6Header     ip;
+               tICMPv6_Header  icmp;
+               tICMPv6_NS      ns;
+               tICMPv6_Opt_LinkAddr    linkaddr;
+               Uint8   our_mac[6];
+       } PACKED pkt;
+       // Custom-crafted IPv6 header
+       pkt.ip.Version = 6;
+       pkt.ip.TrafficClass = 0;
+       pkt.ip.FlowLabel = 0;
+       pkt.ip.Head = htonl(pkt.ip.Head);
+       pkt.ip.PayloadLength = htons(sizeof(pkt)-sizeof(pkt.ip));
+       pkt.ip.NextHeader = IPV6PROT_ICMPV6;
+       pkt.ip.HopLimit = 255;  // Max value
+       pkt.ip.Source = *(tIPv6*)Interface->Address;
+       pkt.ip.Destination = (tIPv6){.B={0xFF,0x02, 0,0, 0,0, 0,0,  0,0, 0,1,0xFF,addr8[13], addr8[14],addr8[15]}};
+       
+       pkt.icmp.Type = ICMPV6_INFO_NEIGHBOUR_SOLICITATION;
+       pkt.icmp.Code = 0;
+       pkt.icmp.Checksum = 0;  // populated later
+
+       pkt.ns.Reserved = 0;
+       pkt.ns.TargetAddress = *(const tIPv6*)Address;
+       
+       pkt.linkaddr.Type = ICMPV6_OPTION_SRCLINK;
+       pkt.linkaddr.Length = 1;        // 1 * 8 bytes
+       memcpy(pkt.our_mac, Interface->Adapter->HWAddr, 6);
+
+       pkt.icmp.Checksum = IPv4_Checksum(&pkt, sizeof(pkt));
+
+
+       tMacAddr        to = {.B={0x33, 0x33, addr8[12], addr8[13], addr8[14], addr8[15]}};
+
+       tIPStackBuffer *buffer = IPStack_Buffer_CreateBuffer(2);
+       IPStack_Buffer_AppendSubBuffer(buffer, sizeof(pkt), 0, &pkt, NULL, NULL);
+       Link_SendPacket(Interface->Adapter, IPV6_ETHERNET_ID, to, buffer);
+       IPStack_Buffer_DestroyBuffer(buffer);
+}
diff --git a/KernelLand/Modules/IPStack/icmpv6.h b/KernelLand/Modules/IPStack/icmpv6.h
new file mode 100644 (file)
index 0000000..bda70b1
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Acess2 IP Stack
+ * - By John Hodge (thePowersGang)
+ *
+ * icmpv6.c
+ * - Internet Control Message Protocol v6
+ */
+#ifndef _ICMPV6_H_
+#define _ICMPV6_H_
+
+#define IPV6PROT_ICMPV6        58
+
+typedef struct {
+       Uint8   Type;
+       Uint8   Code;
+       Uint16  Checksum;
+} PACKED tICMPv6_Header;
+
+typedef struct {
+       Uint32  Reserved;
+} PACKED tICMPv6_RS;
+
+typedef struct {
+       Uint8   CurHopLimit;
+       Uint8   Flags;  // M:O:6
+       Uint16  RouterLifetime; // Seconds, life time as a default router (wtf does that mean?)
+       Uint32  ReachableTime;
+       Uint32  RetransTimer;   // Miliseconds, time between transmissions of RAs from this router
+       Uint8   Options[];
+} PACKED tICMPv6_RA;
+
+typedef struct {
+       Uint32  Reserved;
+       tIPv6   TargetAddress;
+       Uint8   Options[];
+} PACKED tICMPv6_NS;
+
+typedef struct {
+       Uint32  Flags;
+       tIPv6   TargetAddress;
+       Uint8   Options[];
+} PACKED tICMPv6_NA;
+
+typedef struct {
+       Uint32  Reserved;
+       tIPv6   TargetAddress;
+       tIPv6   DestinationAddress;
+       Uint8   Options[];
+} PACKED tICMPv6_Redirect;
+
+typedef struct {
+       Uint8   Type;   // 1,2
+       Uint8   Length; // Length of field in units of 8 bytes (incl header), typically 1
+       Uint8   Address[];
+} PACKED tICMPv6_Opt_LinkAddr;
+
+typedef struct {
+       Uint8   Type;   // 3
+       Uint8   Length; // Length of field in units of 8 bytes (incl header), typically
+       Uint8   PrefixLength;
+       Uint8   Flags;  // L:A:6 - 
+       Uint32  ValidLifetime;
+       Uint32  PreferredLifetime;
+       Uint32  _reserved2;
+       tIPv6   Prefix[];
+} PACKED tICMPv6_Opt_Prefix;
+
+typedef struct {
+       Uint8   Type;   // 4
+       Uint8   Length;
+       Uint16  _rsvd1;
+       Uint32  _rsvd2;
+       Uint8   Data[]; // All or part of the redirected message (not exceeding MTU)
+} PACKED tICMPv6_Opt_Redirect;
+
+typedef struct {
+       Uint8   Type;   // 4
+       Uint8   Length;
+       Uint16  _resvd1;
+       Uint32  MTU;
+} PACKED tICMPv6_Opt_MTU;
+
+enum {
+       ICMPV6_ERR_UNREACHABLE,
+       ICMPV6_ERR_PACKET_TOO_BIG,
+       ICMPV6_ERR_TIME_EXCEEDED,
+       ICMPV6_ERR_PARAMETER_PROBLEM,
+};
+enum {
+       ICMPV6_INFO_ECHO_REQUEST = 128,
+       ICMPV6_INFO_ECHO_REPLY,
+
+       ICMPV6_INFO_ROUTER_SOLICITATION = 133,
+       ICMPV6_INFO_ROUTER_ADVERTISEMENT,
+       ICMPV6_INFO_NEIGHBOUR_SOLICITATION,
+       ICMPV6_INFO_NEIGHBOUR_ADVERTISMENT,
+       ICMPV6_INFO_REDIRECT,
+};
+
+enum {
+       ICMPV6_OPTION_SRCLINK = 1,
+       ICMPV6_OPTION_TGTLINK,
+       ICMPV6_OPTION_PREFIX,
+       ICMPV6_OPTION_REDIRECTED_HDR,
+       ICMPV6_OPTION_MTU,
+};
+
+#endif
+
index ee17c01..35cd742 100644 (file)
@@ -6,6 +6,7 @@
 #define _IPV6_H_
 
 #include "ipstack.h"
+#include "include/buffer.h"
 
 typedef struct sIPv6Header     tIPv6Header;
 
index 8f16da8..ac58ec3 100644 (file)
@@ -2,7 +2,7 @@
  * Acess2 IP Stack
  * - TCP Handling
  */
-#define DEBUG  0
+#define DEBUG  1
 #include "ipstack.h"
 #include "ipv4.h"
 #include "ipv6.h"
@@ -52,6 +52,7 @@ size_t        TCP_Client_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void
 void   TCP_Client_Close(tVFS_Node *Node);
 // --- Helpers
  int   WrapBetween(Uint32 Lower, Uint32 Value, Uint32 Higher, Uint32 MaxValue);
+Uint32 GetRelative(Uint32 Base, Uint32 Value);
 
 // === TEMPLATES ===
 tSocketFile    gTCP_ServerFile = {NULL, "tcps", TCP_Server_Init};
@@ -119,7 +120,7 @@ void TCP_int_SendPacket(tInterface *Interface, const void *Dest, tTCPHeader *Hea
 
        LOG("Sending %i+%i to %s:%i", sizeof(*Header), Length,
                IPStack_PrintAddress(Interface->Type, Dest),
-               ntohs(Header->RemotePort)
+               ntohs(Header->DestPort)
                );
 
        Header->Checksum = 0;
@@ -289,6 +290,7 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe
                conn->NextSequenceRcv = ntohl( hdr->SequenceNumber ) + 1;
                conn->HighestSequenceRcvd = conn->NextSequenceRcv;
                conn->NextSequenceSend = rand();
+               conn->LastACKSequence = ntohl( hdr->SequenceNumber );
                
                conn->Node.ImplInt = srv->NextID ++;
                
@@ -516,7 +518,9 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head
 
                        #if 1
                        // - Only send an ACK if we've had a burst
-                       if( Connection->NextSequenceRcv > (Uint32)(TCP_DACK_THRESHOLD + Connection->LastACKSequence) )
+                       Uint32  bytes_since_last_ack = Connection->NextSequenceRcv - Connection->LastACKSequence;
+                       LOG("bytes_since_last_ack = 0x%x", bytes_since_last_ack);
+                       if( bytes_since_last_ack > TCP_DACK_THRESHOLD )
                        {
                                TCP_INT_SendACK(Connection, "DACK Burst");
                                // - Extend TCP deferred ACK timer
@@ -529,14 +533,13 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head
                        #endif
                }
                // Check if the packet is in window
-               else if( WrapBetween(Connection->NextSequenceRcv, sequence_num,
-                               Connection->NextSequenceRcv+TCP_WINDOW_SIZE, 0xFFFFFFFF) )
+               else if( sequence_num - Connection->NextSequenceRcv < TCP_WINDOW_SIZE )
                {
                        Uint8   *dataptr = (Uint8*)Header + (Header->DataOffset>>4)*4;
-                       #if CACHE_FUTURE_PACKETS_IN_BYTES
-                       Uint32  index;
-                       
-                       index = sequence_num % TCP_WINDOW_SIZE;
+                       Uint32  index = sequence_num % TCP_WINDOW_SIZE;
+                       Uint32  max = Connection->NextSequenceRcv % TCP_WINDOW_SIZE;
+                       if( !(Connection->FuturePacketValidBytes[index/8] & (1 << (index%8))) )
+                               TCP_INT_SendACK(Connection, "Lost packet");
                        for( int i = 0; i < dataLen; i ++ )
                        {
                                Connection->FuturePacketValidBytes[index/8] |= 1 << (index%8);
@@ -544,52 +547,15 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head
                                // Do a wrap increment
                                index ++;
                                if(index == TCP_WINDOW_SIZE)    index = 0;
+                               if(index == max)        break;
                        }
-                       #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
+                       Uint32  rel_highest = Connection->HighestSequenceRcvd - Connection->NextSequenceRcv;
+                       Uint32  rel_this = index - Connection->NextSequenceRcv;
+                       LOG("Updating highest this(0x%x) > highest(%x)", rel_this, rel_highest);
+                       if( rel_this > rel_highest )
                        {
-                               free(pkt);      // TODO: Find some way to remove this
+                               Connection->HighestSequenceRcvd = index;
                        }
-                       SHORTREL( &Connection->lFuturePackets );
-                       #endif
                }
                // Badly out of sequence packet
                else
@@ -716,17 +682,18 @@ int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t
  */
 void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection)
 {
-       #if CACHE_FUTURE_PACKETS_IN_BYTES
        // Calculate length of contiguous bytes
-        int    length = Connection->HighestSequenceRcvd - Connection->NextSequenceRcv;
+       const int       length = Connection->HighestSequenceRcvd - Connection->NextSequenceRcv;
        Uint32  index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE;
-       LOG("length=%i, index=%i", length, index);
+       size_t  runlength = length;
+       LOG("length=%i, index=0x%x", length, index);
        for( int i = 0; i < length; i ++ )
        {
                 int    bit = index % 8;
                Uint8   bitfield_byte = Connection->FuturePacketValidBytes[index / 8];
                if( (bitfield_byte & (1 << bit)) == 0 ) {
-                       length = i;
+                       runlength = i;
+                       LOG("Hit missing, break");
                        break;
                }
 
@@ -743,90 +710,51 @@ void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection)
        }
        
        index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE;
+       Connection->NextSequenceRcv += runlength;
        
        // Write data to to the ring buffer
-       if( TCP_WINDOW_SIZE - index > length )
+       if( TCP_WINDOW_SIZE - index > runlength )
        {
                // Simple case
-               RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData + index, length );
+               RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData + index, runlength );
        }
        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 );
+               RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData, endLen - runlength );
        }
        
        // Mark (now saved) bytes as invalid
        // - Align index
-       while(index % 8 && length > 0)
+       while(index % 8 && runlength > 0)
        {
                Connection->FuturePacketData[index] = 0;
                Connection->FuturePacketValidBytes[index/8] &= ~(1 << (index%8));
                index ++;
                if(index > TCP_WINDOW_SIZE)
                        index -= TCP_WINDOW_SIZE;
-               length --;
+               runlength --;
        }
-       while( length > 7 )
+       while( runlength > 7 )
        {
                Connection->FuturePacketData[index] = 0;
                Connection->FuturePacketValidBytes[index/8] = 0;
-               length -= 8;
+               runlength -= 8;
                index += 8;
                if(index > TCP_WINDOW_SIZE)
                        index -= TCP_WINDOW_SIZE;
        }
-       while(length)
+       while( runlength > 0)
        {
                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->Data, pkt->Length);
-               if( Connection->HighestSequenceRcvd == Connection->NextSequenceRcv )
-                       Connection->HighestSequenceRcvd += pkt->Length;
-               Connection->NextSequenceRcv += pkt->Length;
-               free(pkt);
+               runlength --;
        }
-       #endif
 }
 
 void TCP_int_SendDelayedACK(void *ConnPtr)
@@ -1259,6 +1187,8 @@ void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, const voi
 
        // - Stop Delayed ACK timer (as this data packet ACKs)
        Time_RemoveTimer(Connection->DeferredACKTimer);
+
+       // TODO: Don't exceed window size
        
        packet->SourcePort = htons(Connection->LocalPort);
        packet->DestPort = htons(Connection->RemotePort);
@@ -1534,3 +1464,10 @@ int WrapBetween(Uint32 Lower, Uint32 Value, Uint32 Higher, Uint32 MaxValue)
        
        return 0;
 }
+Uint32 GetRelative(Uint32 Base, Uint32 Value)
+{
+       if( Value < Base )
+               return Value - Base + 0xFFFFFFFF;
+       else
+               return Value - Base;
+}
index c1ceb65..43828f1 100644 (file)
@@ -156,14 +156,9 @@ struct sTCPConnection
         * \todo Convert this to a ring buffer and a bitmap of valid bytes
         * \{
         */
-       #if CACHE_FUTURE_PACKETS_IN_BYTES
        Uint32  HighestSequenceRcvd;    //!< Highest sequence number (within window) recieved
        Uint8   *FuturePacketData;      //!< Future packet data (indexed by sequence number)
        Uint8   *FuturePacketValidBytes;        //!< Valid byte bitmap (WINDOW_SIZE/8 bytes)
-       #else
-       tShortSpinlock  lFuturePackets; //!< Future packets spinlock
-       tTCPStoredPacket        *FuturePackets; //!< Out of sequence packets
-       #endif
        /**
         * \}
         */

UCC git Repository :: git.ucc.asn.au