IPStack - Working on implementing IPv6
authorJohn Hodge <[email protected]>
Mon, 21 Mar 2011 08:19:36 +0000 (16:19 +0800)
committerJohn Hodge <[email protected]>
Mon, 21 Mar 2011 08:19:36 +0000 (16:19 +0800)
Modules/IPStack/ipv6.c

index 9368c3e..d728325 100644 (file)
@@ -5,6 +5,7 @@
 #include "ipstack.h"
 #include "link.h"
 #include "ipv6.h"
+#include "firewall.h"
 
 // === IMPORTS ===
 extern tInterface      *gIP_Interfaces;
@@ -12,9 +13,13 @@ extern Uint32        IPv4_Netmask(int FixedBits);
 
 // === PROTOTYPES ===
  int   IPv6_Initialise();
+ int   IPv6_RegisterCallback(int ID, tIPCallback Callback);
 void   IPv6_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer);
 tInterface     *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast);
 
+// === GLOBALS ===
+tIPCallback    gaIPv6_Callbacks[256];
+
 // === CODE ===
 /**
  * \brief Initialise the IPv6 handling code
@@ -25,6 +30,19 @@ int IPv6_Initialise()
        return 1;
 }
 
+/**
+ * \brief Registers a callback
+ * \param ID   8-bit packet type ID
+ * \param Callback     Callback function
+ */
+int IPv6_RegisterCallback(int ID, tIPCallback Callback)
+{
+       if( ID < 0 || ID > 255 )        return 0;
+       if( gaIPv6_Callbacks[ID] )      return 0;
+       gaIPv6_Callbacks[ID] = Callback;
+       return 1;
+}
+
 /**
  * \fn void IPv6_int_GetPacket(tInterface *Interface, tMacAddr From, int Length, void *Buffer)
  * \brief Process an IPv6 Packet
@@ -33,9 +51,14 @@ int IPv6_Initialise()
  * \param Length       Packet length
  * \param Buffer       Packet data
  */
-void IPv6_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer)
+void IPv6_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
 {
+       tInterface      *iface;
        tIPv6Header     *hdr = Buffer;
+        int    ret, dataLength;
+       char    *dataPtr;
+       Uint8   nextHeader;
+       
        if(Length < sizeof(tIPv6Header))        return;
        
        hdr->Head = ntohl(hdr->Head);
@@ -44,6 +67,7 @@ void IPv6_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Bu
        if( hdr->Version != 6 )
                return;
        
+       #if 1
        Log_Debug("IPv6", "hdr = {");
        Log_Debug("IPv6", " .Version       = %i", hdr->Version );
        Log_Debug("IPv6", " .TrafficClass  = %i", hdr->TrafficClass );
@@ -54,7 +78,114 @@ void IPv6_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Bu
        Log_Debug("IPv6", " .Source        = %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", hdr->Source );
        Log_Debug("IPv6", " .Destination   = %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", hdr->Destination );
        Log_Debug("IPv6", "}");
+       #endif
+       
+       // No checksum in IPv6
        
+       // Check Packet length
+       if( ntohs(hdr->PayloadLength)+sizeof(tIPv6Header) > Length) {
+               Log_Log("IPv6", "hdr->PayloadLength(%i) > Length(%i)", ntohs(hdr->PayloadLength), Length);
+               return;
+       }
+       
+       // Process Options
+       nextHeader = hdr->NextHeader;
+       dataPtr = hdr->Data;
+       dataLength = hdr->PayloadLength;
+       for( ;; )
+       {
+               struct {
+                       Uint8   NextHeader;
+                       Uint8   Length; // In 8-byte chunks, with 0 being 8 bytes long
+                       Uint8   Data[];
+               }       *optionHdr;
+               optionHdr = (void*)dataPtr;
+               // Hop-by-hop options
+               if(nextHeader == 0)
+               {
+                       // TODO: Parse the options (actually, RFC2460 doesn't specify any)
+               }
+               // Routing Options
+               else if(nextHeader == 43)
+               {
+                       // TODO: Routing Header options
+               }
+               else
+               {
+                       break;  // Unknown, pass on
+               }
+               nextHeader = optionHdr->NextHeader;
+               dataPtr += (optionHdr->Length + 1) * 8; // 8-octet length (0 = 8 bytes long)
+       }
+       
+       // Get Interface (allowing broadcasts)
+       iface = IPv6_GetInterface(Adapter, hdr->Destination, 1);
+       
+       // Firewall rules
+       if( iface ) {
+               // Incoming Packets
+               ret = IPTables_TestChain("INPUT",
+                       6, &hdr->Source, &hdr->Destination,
+                       hdr->NextHeader, 0,
+                       hdr->PayloadLength, hdr->Data
+                       );
+       }
+       else {
+               // Routed packets
+               ret = IPTables_TestChain("FORWARD",
+                       6, &hdr->Source, &hdr->Destination,
+                       hdr->NextHeader, 0,
+                       hdr->PayloadLength, hdr->Data
+                       );
+       }
+       
+       switch(ret)
+       {
+       // 0 - Allow
+       case 0: break;
+       // 1 - Silent Drop
+       case 1:
+               Log_Debug("IPv6", "Silently dropping packet");
+               return ;
+       // Unknown, silent drop
+       default:
+               return ;
+       }
+       
+       // Routing
+       if(!iface)
+       {
+               #if 0
+               tMacAddr        to;
+               tRoute  *rt;
+               
+               Log_Debug("IPv6", "Route the packet");
+               // Drop the packet if the TTL is zero
+               if( hdr->HopLimit == 0 ) {
+                       Log_Warning("IPv6", "TODO: Sent ICMP-Timeout when TTL exceeded");
+                       return ;
+               }
+               
+               hdr->HopLimit --;
+               
+               rt = IPStack_FindRoute(6, NULL, &hdr->Destination);     // Get the route (gets the interface)
+               //to = ARP_Resolve6(rt->Interface, hdr->Destination);   // Resolve address
+               
+               // Send packet
+               Log_Log("IPv6", "Forwarding packet");
+               Link_SendPacket(rt->Interface->Adapter, IPV6_ETHERNET_ID, to, Length, Buffer);
+               #endif
+               
+               return ;
+       }
+       
+       // Send it on
+       if( !gaIPv6_Callbacks[hdr->NextHeader] ) {
+               Log_Log("IPv6", "Unknown Protocol %i", hdr->NextHeader);
+               return ;
+       }
+       
+       gaIPv6_Callbacks[hdr->NextHeader]( iface, &hdr->Source, hdr->PayloadLength, hdr->Data );
 }
 
 /**
@@ -73,6 +204,7 @@ tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast)
        for( iface = gIP_Interfaces; iface; iface = iface->Next)
        {
                tIPv6   *thisAddr;
+               
                // Check for this adapter
                if( iface->Adapter != Adapter ) continue;
                
@@ -87,6 +219,7 @@ tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast)
                if( !Broadcast )        continue;
                
                // Check for broadcast
+               // - Check first DWORDs
                if( iface->SubnetBits > 32 && Address.L[0] != thisAddr->L[0] )
                        continue;
                if( iface->SubnetBits > 64 && Address.L[1] != thisAddr->L[1] )
@@ -94,6 +227,7 @@ tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast)
                if( iface->SubnetBits > 96 && Address.L[2] != thisAddr->L[2] )
                        continue;
                
+               // Check final DWORD
                j = iface->SubnetBits / 32;
                i = iface->SubnetBits % 32;
                netmask = IPv4_Netmask( iface->SubnetBits % 32 );

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