OBJ := main.o interface.o adapters.o
OBJ += buffer.o
-OBJ += link.o arp.o
-OBJ += ipv4.o icmp.o
+OBJ += link.o hwaddr_cache.o
+OBJ += ipv4.o icmp.o arp.o
OBJ += ipv6.o
OBJ += firewall.o routing.o
OBJ += udp.o tcp.o
#include "include/adapters_int.h" // for MAC addr
#include <semaphore.h>
#include <timers.h>
+#include "hwaddr_cache.h"
#define ARPv6 0
#define ARP_CACHE_SIZE 128
#define ARP_MAX_AGE (60*60*1000) // 1Hr
-typedef struct sARP_CacheEnt
-{
- void *Layer3Addr;
- tMacAddr L2Addr;
- Sint64 LastUpdate;
- Sint64 LastUsed;
-} tARP_CacheEnt;
-typedef struct sARP_Cache
-{
- size_t AddrSize;
- int nCacheEnts;
- tARP_CacheEnt Cache[];
-} tARP_Cache;
-
// === IMPORTS ===
extern tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast);
#if ARPv6
// === PROTOTYPES ===
int ARP_Initialise();
-tMacAddr ARP_Resolve4(tInterface *Interface, tIPv4 Address);
void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer);
// === GLOBALS ===
- int giARP_WaitingThreads;
-struct sARP_Cache4 {
- tIPv4 IP;
- tMacAddr MAC;
- Sint64 LastUpdate;
- Sint64 LastUsed;
-} *gaARP_Cache4;
- int giARP_Cache4Space;
-tMutex glARP_Cache4;
-tSemaphore gARP_Cache4Semaphore;
-#if ARPv6
-struct sARP_Cache6 {
- tIPv6 IP;
- tMacAddr MAC;
- Sint64 LastUpdate;
- Sint64 LastUsed;
-} *gaARP_Cache6;
- int giARP_Cache6Space;
-tMutex glARP_Cache6;
-#endif
// === CODE ===
-tARP_Cache *ARP_int_CreateCache(unsigned int NumCacheEntries, size_t AddrSize)
-{
- size_t len = sizeof(tARP_Cache) + NumCacheEntries * (sizeof(tARP_CacheEnt) + AddrSize);
- tARP_Cache *ret = calloc(len, 1);
-
- ret->nCacheEnts = NumCacheEntries;
- ret->AddrSize = AddrSize;
-
- char *addr_storage_pos = (void*)&ret->Cache[NumCacheEntries];
-
- for( int i = 0; i < NumCacheEntries; i ++ )
- {
- ret->Cache[i].Layer3Addr = addr_storage_pos;
- addr_storage_pos += AddrSize;
- }
-
- return ret;
-}
/**
* \fn int ARP_Initialise()
* \brief Initalise the ARP section
*/
int ARP_Initialise()
{
- gaARP_Cache4 = malloc( ARP_CACHE_SIZE * sizeof(struct sARP_Cache4) );
- memset( gaARP_Cache4, 0, ARP_CACHE_SIZE * sizeof(struct sARP_Cache4) );
- giARP_Cache4Space = ARP_CACHE_SIZE;
-
- #if ARPv6
- gaARP_Cache6 = malloc( ARP_CACHE_SIZE * sizeof(struct sARP_Cache6) );
- memset( gaARP_Cache6, 0, ARP_CACHE_SIZE * sizeof(struct sARP_Cache6) );
- giARP_Cache6Space = ARP_CACHE_SIZE;
- #endif
-
Link_RegisterType(0x0806, ARP_int_GetPacket);
- Semaphore_Init(&gARP_Cache4Semaphore, 0, 0, "ARP4", "Cache Changes");
return 1;
}
-tMacAddr ARP_Resolve(tInterface *Interface, void *Address)
-{
- switch(Interface->Type)
- {
- case AF_INET4:
- return ARP_Resolve4(Interface, *(tIPv4*)Address);
-// case AF_INET6:
-// ret = ARP_int_CacheLookup(Interface, 16, Address);
-// if(ret == cMAC_ZERO) {
-// // TODO: Send ICMPv6 ND requests
-// }
-// return ret;
- }
- return cMAC_ZERO;
-}
-
-/**
- * \brief Resolves a MAC address from an IPv4 address
- */
-tMacAddr ARP_Resolve4(tInterface *Interface, tIPv4 Address)
+void ARP_Request4(tInterface *Interface, tIPv4 Address)
{
- int i;
struct sArpRequest4 req;
-
- ENTER("pInterface xAddress", Interface, Address);
-
- // Check for broadcast
- if( Address.L == -1 )
- {
- LOG("Broadcast");
- LEAVE('-');
- return cMAC_BROADCAST;
- }
-
- // Check routing tables if not on this subnet
- if( IPStack_CompareAddress(4, &Address, Interface->Address, Interface->SubnetBits) == 0 )
- {
- tRoute *route = IPStack_FindRoute(4, Interface, &Address);
- // If the next hop is defined, use it
- // - 0.0.0.0 as the next hop means "no next hop / direct"
- if( route && ((tIPv4*)route->NextHop)->L != 0 )
- {
- // Recursion: see /Recursion/
- LOG("Recursing with %s", IPStack_PrintAddress(4, route->NextHop));
- LEAVE('-');
- return ARP_Resolve4(Interface, *(tIPv4*)route->NextHop);
- }
- // No route, fall though
- }
- else
- {
- Uint32 netmask;
- // Check for broadcast
- netmask = IPv4_Netmask(Interface->SubnetBits);
- if( (Address.L & ~netmask) == (0xFFFFFFFF & ~netmask) )
- {
- LOG("Local Broadcast");
- LEAVE('-');
- return cMAC_BROADCAST;
- }
- }
-
- // Check ARP Cache
- Mutex_Acquire( &glARP_Cache4 );
- for( i = 0; i < giARP_Cache4Space; i++ )
- {
- if(gaARP_Cache4[i].IP.L != Address.L) continue;
-
- // Check if the entry needs to be refreshed
- if( now() - gaARP_Cache4[i].LastUpdate > ARP_MAX_AGE ) break;
-
- Mutex_Release( &glARP_Cache4 );
- LOG("Return %x:%x:%x:%x:%x:%x",
- gaARP_Cache4[i].MAC.B[0], gaARP_Cache4[i].MAC.B[1],
- gaARP_Cache4[i].MAC.B[2], gaARP_Cache4[i].MAC.B[3],
- gaARP_Cache4[i].MAC.B[4], gaARP_Cache4[i].MAC.B[5]
- );
- LEAVE('-');
- return gaARP_Cache4[i].MAC;
- }
- giARP_WaitingThreads ++;
- Mutex_Release( &glARP_Cache4 );
-
// Create request
Log_Log("ARP4", "Asking for address %i.%i.%i.%i",
Address.B[0], Address.B[1], Address.B[2], Address.B[3]
// Send Request
Link_SendPacket(Interface->Adapter, 0x0806, req.DestMac, buffer);
-
- // Wait for a reply
- Time_ScheduleTimer(NULL, Interface->TimeoutDelay);
- for(;;)
- {
- if( Semaphore_Wait(&gARP_Cache4Semaphore, 1) != 1 )
- {
- giARP_WaitingThreads --;
- Log_Log("ARP4", "Timeout");
- break;
- }
- Log_Debug("ARP4", "Cache change");
-
- Mutex_Acquire( &glARP_Cache4 );
- for( i = 0; i < giARP_Cache4Space; i++ )
- {
- if(gaARP_Cache4[i].IP.L != Address.L) continue;
-
- giARP_WaitingThreads --;
- Mutex_Release( &glARP_Cache4 );
- Log_Debug("ARP4", "Return %02x:%02x:%02x:%02x:%02x:%02x",
- gaARP_Cache4[i].MAC.B[0], gaARP_Cache4[i].MAC.B[1],
- gaARP_Cache4[i].MAC.B[2], gaARP_Cache4[i].MAC.B[3],
- gaARP_Cache4[i].MAC.B[4], gaARP_Cache4[i].MAC.B[5]);
- return gaARP_Cache4[i].MAC;
- }
- Mutex_Release( &glARP_Cache4 );
- }
- {
- tMacAddr ret = {{0,0,0,0,0,0}};
- return ret;
- }
}
-/**
- * \brief Updates the ARP Cache entry for an IPv4 Address
- */
-void ARP_UpdateCache4(tIPv4 SWAddr, tMacAddr HWAddr)
-{
- int i;
- int free = -1;
- int oldest = 0;
-
- // Find an entry for the IP address in the cache
- Mutex_Acquire(&glARP_Cache4);
- for( i = giARP_Cache4Space; i--; )
- {
- if(gaARP_Cache4[oldest].LastUpdate > gaARP_Cache4[i].LastUpdate) {
- oldest = i;
- }
- if( gaARP_Cache4[i].IP.L == SWAddr.L ) break;
- if( gaARP_Cache4[i].LastUpdate == 0 && free == -1 ) free = i;
- }
- // If there was no match, we need to make one
- if(i == -1) {
- if(free != -1)
- i = free;
- else
- i = oldest;
- }
-
- if( memcmp(&gaARP_Cache4[i].MAC, &HWAddr, sizeof(HWAddr)) != 0 )
- {
- Log_Log("ARP4", "Caching %i.%i.%i.%i (%02x:%02x:%02x:%02x:%02x:%02x) in %i",
- SWAddr.B[0], SWAddr.B[1], SWAddr.B[2], SWAddr.B[3],
- HWAddr.B[0], HWAddr.B[1], HWAddr.B[2], HWAddr.B[3], HWAddr.B[4], HWAddr.B[5],
- i
- );
-
- gaARP_Cache4[i].IP = SWAddr;
- gaARP_Cache4[i].MAC = HWAddr;
- gaARP_Cache4[i].LastUpdate = now();
- Semaphore_Signal(&gARP_Cache4Semaphore, giARP_WaitingThreads);
- }
- Mutex_Release(&glARP_Cache4);
-}
-
-#if ARPv6
-/**
- * \brief Updates the ARP Cache entry for an IPv6 Address
- */
-void ARP_UpdateCache6(tIPv6 SWAddr, tMacAddr HWAddr)
-{
- int i;
- int free = -1;
- int oldest = 0;
-
- // Find an entry for the MAC address in the cache
- Mutex_Acquire(&glARP_Cache6);
- for( i = giARP_Cache6Space; i--; )
- {
- if(gaARP_Cache6[oldest].LastUpdate > gaARP_Cache6[i].LastUpdate) {
- oldest = i;
- }
- if( MAC_EQU(gaARP_Cache6[i].MAC, HWAddr) ) break;
- if( gaARP_Cache6[i].LastUpdate == 0 && free == -1 ) free = i;
- }
- // If there was no match, we need to make one
- if(i == -1) {
- if(free != -1)
- i = free;
- else
- i = oldest;
- gaARP_Cache6[i].MAC = HWAddr;
- }
-
- gaARP_Cache6[i].IP = SWAddr;
- gaARP_Cache6[i].LastUpdate = now();
- giARP_LastUpdateID ++;
- Mutex_Release(&glARP_Cache6);
-}
-#endif
-
/**
* \fn void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
* \brief Called when an ARP packet is recieved
req4->SourceMac.B[0], req4->SourceMac.B[1],
req4->SourceMac.B[2], req4->SourceMac.B[3],
req4->SourceMac.B[4], req4->SourceMac.B[5]);
- ARP_UpdateCache4(req4->SourceIP, req4->SourceMac);
+ // Someone has ARPed us, let's cache them
+ HWCache_Set(Adapter, 4, &req4->SourceIP, &req4->SourceMac);
req4->DestIP = req4->SourceIP;
req4->DestMac = req4->SourceMac;
switch( req4->SWSize )
{
case 4:
- ARP_UpdateCache4( req4->SourceIP, From );
+ HWCache_Set(Adapter, 4, &req4->SourceIP, &From);
break;
#if ARPv6
case 6:
Log_Debug("ARP", "Recieved undersized packet (IPv6)");
return ;
}
- ARP_UpdateCache6( req6->SourceIP, From );
+ HWCache_Set(Adapter, 6, &req6->SourceIP, &From );
break;
#endif
default:
--- /dev/null
+/*
+ * Acess2 IP Stack
+ *
+ * hwaddr_resolution.c
+ * - Resolution/caching of hardware addresses
+ */
+#define DEBUG 1
+#include "ipstack.h"
+#include "icmp.h"
+#include "include/adapters_int.h"
+#include "hwaddr_cache.h"
+#include <timers.h>
+#include <semaphore.h>
+#include <limits.h> // *INT_MAX
+
+typedef struct sHWAdddrCache tHWAddrCache;
+typedef struct sHWAdddrCachedAddr tHWAddrCachedAddr;
+
+struct sHWAdddrCache {
+ const tInterface *Interface;
+ tMutex Lock;
+ const int MaxSize;
+ int nAddrs;
+ tHWAddrCachedAddr *First;
+};
+
+struct sHWAdddrCachedAddr {
+ tHWAddrCachedAddr *Next;
+ unsigned int WaitingCount; // While >0, cache will not be reused
+ tSemaphore WaitingSem;
+ void *L3Addr;
+ tMacAddr *HWAddr;
+};
+
+#define PRImacaddr "%02x:%02x:%02x:%02x:%02x:%02x"
+#define FMTmacaddr(a) (a).B[0],(a).B[1],(a).B[2],(a).B[3],(a).B[4],(a).B[5]
+
+// Cache is sorted by usage (most recently used at top)
+
+// === CODE ===
+tHWAddrCache *HWCache_int_GetCache(tAdapter *Adapter, int AddrType)
+{
+ static tHWAddrCache cache_v6 = {.MaxSize=64};
+ static tHWAddrCache cache_v4 = {.MaxSize=64};
+ switch(AddrType)
+ {
+ case 4: return &cache_v4;
+ case 6: return &cache_v6;
+ default:
+ return NULL;
+ }
+}
+
+bool memiszero(const void *mem, size_t length)
+{
+ const Uint8 *mem8 = mem;
+ while( length -- )
+ {
+ if(*mem8 != 0) return false;
+ mem8 ++;
+ }
+ return true;
+}
+
+tMacAddr HWCache_Resolve(tInterface *Interface, const void *DestAddr)
+{
+ const size_t addrsize = IPStack_GetAddressSize(Interface->Type);
+ tHWAddrCache *cache = HWCache_int_GetCache(Interface->Adapter, Interface->Type);
+
+ LOG("DestAddr=%s", IPStack_PrintAddress(Interface->Type, DestAddr));
+
+ // Detect sending packets outside of the local network
+ if( IPStack_CompareAddress(Interface->Type, DestAddr, Interface->Address, Interface->SubnetBits) == 0 )
+ {
+ // Off-net, use a route
+ tRoute *route = IPStack_FindRoute(Interface->Type, Interface, DestAddr);
+ // If a route exists and the gateway isn't empty, use the gateway
+ if( route )
+ {
+ if( !memiszero(route->NextHop, addrsize) )
+ {
+ // Update DestAddr to gateway address
+ DestAddr = route->NextHop;
+ LOG("Via gateway");
+ }
+ else
+ {
+ // Zero gateway means force direct
+ LOG("Force direct");
+ }
+ }
+ else
+ {
+ // No route to host
+ LOG("No route to host");
+ return cMAC_ZERO;
+ }
+ }
+ // Local broadcast
+ else if( IPStack_AddressIsBroadcast(Interface->Type, DestAddr, Interface->SubnetBits) )
+ {
+ // Broadcast, send to bcast mac
+ LOG("Broadcast");
+ return cMAC_BROADCAST;
+ }
+ else
+ {
+ // Fall through
+ }
+ LOG("DestAddr(2)=%s", IPStack_PrintAddress(Interface->Type, DestAddr));
+
+ Mutex_Acquire(&cache->Lock);
+ // 1. Search cache for this address
+ tHWAddrCachedAddr **pnp = &cache->First, *ca;
+ tHWAddrCachedAddr *last = NULL;
+ for( ca = cache->First; ca; ca = ca->Next )
+ {
+ LOG("ca = %p (%s => "PRImacaddr")",
+ ca, IPStack_PrintAddress(Interface->Type, ca->L3Addr),
+ FMTmacaddr(*ca->HWAddr)
+ );
+ if( memcmp(ca->L3Addr, DestAddr, addrsize) == 0 )
+ break;
+ last = ca;
+ pnp = &ca->Next;
+ }
+ if( ca )
+ {
+ // Move to front, return
+ if( cache->First != ca )
+ {
+ ASSERT(pnp != &cache->First);
+ *pnp = ca->Next;
+
+ ca->Next = cache->First;
+ cache->First = ca;
+ LOG("%p(%s) bumped", ca, IPStack_PrintAddress(Interface->Type, ca->L3Addr));
+ }
+
+ // If there's something waiting on this, odds are it's not populated
+ if( ca->WaitingCount > 0 )
+ {
+ ASSERT(ca->WaitingCount != UINT_MAX);
+ ca->WaitingCount ++;
+ Mutex_Release(&cache->Lock);
+
+ // Wait until populated
+ LOG("Waiting on %p", ca);
+ Semaphore_Wait(&ca->WaitingSem, 1);
+
+ Mutex_Acquire(&cache->Lock);
+ ASSERT(ca->WaitingCount > 0);
+ ca->WaitingCount --;
+ }
+ tMacAddr ret = *(tMacAddr*)ca->HWAddr;
+ Mutex_Release(&cache->Lock);
+
+ LOG("Cached "PRImacaddr, FMTmacaddr(ret));
+ return ret;
+ }
+ // 3. If not found:
+ if( cache->nAddrs >= cache->MaxSize )
+ {
+ ASSERTC(cache->nAddrs, ==, cache->MaxSize);
+ ASSERT(last);
+ // TODO: Need to pick the oldest entry with WaitingThreads==0
+ ASSERT(ca->WaitingCount == 0);
+ // Reuse the oldest item
+ ca = last;
+ LOG("Reuse entry for %p(%s)", ca, IPStack_PrintAddress(Interface->Type, ca->L3Addr));
+ }
+ else
+ {
+ cache->nAddrs ++;
+ ca = calloc( 1, sizeof(*ca) + addrsize + sizeof(tMacAddr) );
+ ca->L3Addr = ca+1;
+ ca->HWAddr = (void*)( (char*)ca->L3Addr + addrsize );
+ LOG("New entry %p", ca);
+ }
+ memcpy(ca->L3Addr, DestAddr, addrsize);
+ memset(ca->HWAddr, 0, sizeof(tMacAddr));
+
+ // Shift to front of list
+ if( cache->First != ca )
+ {
+ *pnp = ca->Next;
+ ca->Next = cache->First;
+ cache->First = ca;
+ }
+
+ // Mark cache entry as being waited upon
+ ASSERT(ca->WaitingCount == 0);
+ ca->WaitingCount = 1;
+ // Then release cache lock (so inbound packets can manipulate it)
+ Mutex_Release(&cache->Lock);
+
+ // Send a request for the address
+ switch(Interface->Type)
+ {
+ case 4: ARP_Request4(Interface, *(tIPv4*)DestAddr); break;
+ //case 6: ICMPv6_RequestND(Interface, DestAddr); break;
+ default:
+ ASSERTC(Interface->Type, ==, 4);
+ ASSERTC(Interface->Type, ==, 6);
+ break;
+ }
+
+ // Wait for up to 3000ms for the entry to populate
+ LOG("Waiting on new entry");
+ Time_ScheduleEvent(3000);
+ int rv = Semaphore_Wait(&ca->WaitingSem, 1);
+
+ // Lock, reduce waiting count, grab return, and release
+ Mutex_Acquire(&cache->Lock);
+ ASSERT(ca->WaitingCount > 0);
+ ca->WaitingCount --;
+ tMacAddr ret = *(tMacAddr*)ca->HWAddr;
+ Mutex_Release(&cache->Lock);
+
+ // NOTE: If entry wasn't populated, we'd return 0 anyway, this is
+ // just for logging purposes
+ if( rv != 1 )
+ {
+ // Interrupted, return zero MAC
+ LOG("Timeout/interrupt, return zero");
+ return cMAC_ZERO;
+ }
+
+ // Release `ca` (on error, HWAddr will be nul)
+ LOG("Requested "PRImacaddr, FMTmacaddr(ret));
+ return ret;
+}
+
+void HWCache_Set(tAdapter *Adapter, int AddrType, const void *L3Addr, const tMacAddr *HWAddr)
+{
+ const size_t addrsize = IPStack_GetAddressSize(AddrType);
+ tHWAddrCache *cache = HWCache_int_GetCache(Adapter, AddrType);
+ LOG("Set %s = "PRImacaddr,
+ IPStack_PrintAddress(AddrType, L3Addr),
+ FMTmacaddr(*HWAddr)
+ );
+ // 1. Locate an existing entry
+ Mutex_Acquire(&cache->Lock);
+ tHWAddrCachedAddr *last_unused = NULL;
+ tHWAddrCachedAddr **pnp = &cache->First;
+ for( tHWAddrCachedAddr *ca = cache->First; ca; ca = ca->Next )
+ {
+ ASSERT(ca->Next != ca);
+ ASSERT(!ca->Next || ca->Next->Next != ca);
+
+ LOG("ca = %p (%s => "PRImacaddr")",
+ ca, IPStack_PrintAddress(AddrType, ca->L3Addr), FMTmacaddr(*ca->HWAddr)
+ );
+ if( ca->WaitingCount == 0 )
+ last_unused = ca;
+ pnp = &ca->Next;
+
+ // 2. If found, set the cache and poke waiting threads
+ if( memcmp(L3Addr, ca->L3Addr, addrsize) == 0 )
+ {
+ if( ca->WaitingCount )
+ {
+ memcpy(ca->HWAddr, HWAddr, sizeof(tMacAddr));
+ Semaphore_Signal(&ca->WaitingSem, INT_MAX);
+ LOG("Found and cached");
+ }
+ else if( memcmp(HWAddr, ca->HWAddr, sizeof(tMacAddr)) )
+ {
+ LOG("Differs to cache");
+ }
+ else
+ {
+ LOG("Already known");
+ }
+ Mutex_Release(&cache->Lock);
+ return ;
+ }
+ }
+ // No existing entry, cache just in case
+ if( cache->nAddrs < cache->MaxSize )
+ {
+ // Create new
+ cache->nAddrs ++;
+ tHWAddrCachedAddr *ca = calloc(1,sizeof(tHWAddrCachedAddr)+addrsize+sizeof(tMacAddr));
+ *pnp = ca;
+ ca->L3Addr = ca+1;
+ ca->HWAddr = (void*)( (char*)ca->L3Addr + addrsize );
+ memcpy(ca->L3Addr, L3Addr, addrsize);
+ memcpy(ca->HWAddr, HWAddr, sizeof(tMacAddr));
+ LOG("Cache in new entry");
+ }
+ else if( last_unused )
+ {
+ tHWAddrCachedAddr *ca = last_unused;
+ memcpy(ca->L3Addr, L3Addr, addrsize);
+ memcpy(ca->HWAddr, HWAddr, sizeof(tMacAddr));
+ // Maintain position
+ LOG("Cache in old entry");
+ }
+ else
+ {
+ // None unused! What is this madness?
+ LOG("Not cached... cache being thrashed?");
+ }
+ Mutex_Release(&cache->Lock);
+}
--- /dev/null
+/*
+ */
+#ifndef _HWADDR_CACHE_H_
+#define _HWADDR_CACHE_H_
+
+extern tMacAddr HWCache_Resolve(tInterface *Interface, const void *L2Addr);
+extern void HWCache_Set(tAdapter *Adapter, int AddrType, const void *L2Addr, const tMacAddr *HWAddr);
+
+
+extern void ARP_Request4(tInterface *Interface, tIPv4 Address);
+extern void ICMPv6_RequestND(tInterface *Interface, const tIPv6 *Address);
+
+#endif
+
extern int IPStack_AddFile(tSocketFile *File);
extern int IPStack_GetAddressSize(int AddressType);
extern int IPStack_CompareAddress(int AddressType, const void *Address1, const void *Address2, int CheckBits);
+extern bool IPStack_AddressIsBroadcast(int AddrType, const void *Addr, int SubnetBits);
extern const char *IPStack_PrintAddress(int AddressType, const void *Address);
-extern tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address);
+extern tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, const void *Address);
#endif
#include "ipstack.h"
#include "link.h"
#include "ipv4.h"
+#include "hwaddr_cache.h"
#include "firewall.h"
// === CONSTANTS ===
extern tInterface *gIP_Interfaces;
extern void ICMP_Initialise();
extern int ICMP_Ping(tInterface *Interface, tIPv4 Addr);
-extern tMacAddr ARP_Resolve4(tInterface *Interface, tIPv4 Address);
-extern void ARP_UpdateCache4(tIPv4 SWAddr, tMacAddr HWAddr);
// === PROTOTYPES ===
int IPv4_Initialise();
length = IPStack_Buffer_GetLength(Buffer);
// --- Resolve destination MAC address
- to = ARP_Resolve4(Iface, Address);
+ to = HWCache_Resolve(Iface, &Address);
if( MAC_EQU(to, cMAC_ZERO) ) {
// No route to host
Log_Notice("IPv4", "No route to host %i.%i.%i.%i",
// Get Data and Data Length
dataLength = ntohs(hdr->TotalLength) - sizeof(tIPv4Header);
data = &hdr->Options[0];
-
- // Populate ARP cache from sniffing.
- // - Downside: Poisoning, polluting from routed packets
- //ARP_UpdateCache4(hdr->Source, From);
// Get Interface (allowing broadcasts)
iface = IPv4_GetInterface(Adapter, hdr->Destination, 1);
}
else {
// Routed packets
+ // Drop the packet if the TTL is zero
+ if( hdr->TTL == 0 ) {
+ Log_Warning("IPv4", "TODO: Send ICMP-Timeout when TTL exceeded");
+ return ;
+ }
+ hdr->TTL --;
+
ret = IPTables_TestChain("FORWARD",
4, &hdr->Source, &hdr->Destination,
hdr->Protocol, 0,
// Routing
if(!iface)
{
- #if 0
- tMacAddr to;
- tRoute *rt;
-
-
- // TODO: Put this in another thread to avoid delays in the RX thread
- Log_Debug("IPv4", "Route the packet");
- // Drop the packet if the TTL is zero
- if( hdr->TTL == 0 ) {
- Log_Warning("IPv4", "TODO: Send ICMP-Timeout when TTL exceeded");
- return ;
- }
-
- hdr->TTL --;
-
- rt = IPStack_FindRoute(4, NULL, &hdr->Destination); // Get the route (gets the interface)
- if( !rt || !rt->Interface )
- return ;
- to = ARP_Resolve4(rt->Interface, hdr->Destination); // Resolve address
- if( MAC_EQU(to, cMAC_ZERO) )
- return ;
-
- // Send packet
- Log_Log("IPv4", "Forwarding packet to %i.%i.%i.%i (via %i.%i.%i.%i)",
- hdr->Destination.B[0], hdr->Destination.B[1],
- 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]);
- Log_Warning("IPv4", "TODO: Implement forwarding with tIPStackBuffer");
-// Link_SendPacket(rt->Interface->Adapter, IPV4_ETHERNET_ID, to, Length, Buffer);
- #endif
-
+ //IPStack_RoutePacket(4, &hdr->Destination, Length, Buffer);
return ;
}
// Populate ARP cache from recieved packets
// - Should be safe
- ARP_UpdateCache4(hdr->Source, From);
+ if( IPStack_CompareAddress(4, &hdr->Source, iface->Address, iface->SubnetBits) )
+ {
+ HWCache_Set(Adapter, 4, &hdr->Source, &From);
+ }
// Send it on
if( !gaIPv4_Callbacks[hdr->Protocol] ) {
#include "link.h"
#include "ipv6.h"
#include "firewall.h"
+#include "hwaddr_cache.h"
// === IMPORTS ===
extern tInterface *gIP_Interfaces;
* \param Data Packet Data
* \return Boolean Success
*/
-int IPv6_SendPacket(tInterface *Iface, tIPv6 Destination, int Protocol, size_t Length, const void *Data)
+int IPv6_SendPacket(tInterface *Iface, tIPv6 Destination, int Protocol, tIPStackBuffer *Buffer)
{
- return 0;
+ size_t length = IPStack_Buffer_GetLength(Buffer);
+
+ // Resolve destination
+ tMacAddr to = HWCache_Resolve(Iface, &Destination);
+ if( MAC_EQU(to, cMAC_ZERO) ) {
+ // No route to host
+ return 0;
+ }
+
+ // Build up header
+ tIPv6Header hdr;
+ hdr.Version = 6;
+ hdr.TrafficClass = 0;
+ hdr.FlowLabel = 0;
+ hdr.Head = htonl(hdr.Head);
+ hdr.PayloadLength = htons(length);
+ hdr.NextHeader = Protocol; // TODO: Routing header?
+ hdr.HopLimit = 64; // TODO: Configurable TTL
+ hdr.Source = *(tIPv6*)Iface->Address;
+ hdr.Destination = Destination;
+
+ IPStack_Buffer_AppendSubBuffer(Buffer, sizeof(hdr), 0, &hdr, NULL, NULL);
+
+ Link_SendPacket(Iface->Adapter, IPV6_ETHERNET_ID, to, Buffer);
+
+ return 1;
}
/**
if(nextHeader == 0)
{
// TODO: Parse the options (actually, RFC2460 doesn't specify any)
+ // Two Defined: Pad1 and PadN
}
// Routing Options
else if(nextHeader == 43)
}
else
{
- break; // Unknown, pass on
+ break; // Unknown, pass to next layer
}
nextHeader = optionHdr->NextHeader;
dataPtr += (optionHdr->Length + 1) * 8; // 8-octet length (0 = 8 bytes long)
}
else {
// Routed packets
+
+ // If routing is disabled globally, or if it's disabled for v6 only, drop
+ if( false || false )
+ {
+ return ;
+ }
+ // TODO: Defer routing of packet
+ LOG("Route the packet");
+ // Drop the packet if the TTL is zero
+ if( hdr->HopLimit == 0 ) {
+ Log_Warning("IPv6", "TODO: Send ICMP-Timeout when TTL exceeded");
+ return ;
+ }
+ hdr->HopLimit --;
+
ret = IPTables_TestChain("FORWARD",
6, &hdr->Source, &hdr->Destination,
hdr->NextHeader, 0,
// 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 = ICMP6_ResolveHWAddr(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
-
+ // TODO: Use tIPStackBuffer instead, for refcounting
+ //IPStack_RoutePacket(6, &hdr->Destination, Length, Buffer);
return ;
}
+ // Populate cache
+ // - TODO: Populate when routing using source address match for iface
+ if( IPStack_CompareAddress(6, &hdr->Source, iface->Address, iface->SubnetBits) )
+ {
+ HWCache_Set(Adapter, 6, &hdr->Source, &From);
+ }
+
// Send it on
if( !gaIPv6_Callbacks[hdr->NextHeader] ) {
Log_Log("IPv6", "Unknown Protocol %i", hdr->NextHeader);
#define IPV6_ETHERNET_ID 0x86DD
extern int IPv6_RegisterCallback(int ID, tIPCallback Callback);
-extern int IPv6_SendPacket(tInterface *Iface, tIPv6 Destination, int Protocol, size_t Length, const void *Data);
+extern int IPv6_SendPacket(tInterface *Iface, tIPv6 Destination, int Protocol, tIPStackBuffer *Buffer);
#endif
return 0;
}
+bool IPStack_AddressIsBroadcast(int AddrType, const void *Addr, int SubnetBits)
+{
+ const size_t addrsize = IPStack_GetAddressSize(AddrType);
+ const Uint8 *addr = Addr;
+
+ ASSERTC( SubnetBits, >=, 0 );
+ ASSERTC( SubnetBits, <=, addrsize * 8 );
+ const size_t host_bits = addrsize*8 - SubnetBits;
+
+ for( int i = 0; i < host_bits/8; i ++ )
+ {
+ if( addr[addrsize-i-1] != 0xFF )
+ return false;
+ }
+ Uint8 mask = 0xFF >> (8-(host_bits%8));
+ if( (addr[addrsize-host_bits/8-1] & mask) != mask )
+ return false;
+ return true;
+}
+
const char *IPStack_PrintAddress(int AddressType, const void *Address)
{
switch( AddressType )
// - Route Management
tRoute *IPStack_Route_Create(int AddrType, void *Network, int SubnetBits, int Metric);
tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric);
-tRoute *_Route_FindInterfaceRoute(int AddressType, void *Address);
-tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address);
+tRoute *_Route_FindInterfaceRoute(int AddressType, const void *Address);
+tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, const void *Address);
// - Individual Routes
int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data);
/**
* \brief Locates what interface should be used to get directly to an address
*/
-tRoute *_Route_FindInterfaceRoute(int AddressType, void *Address)
+tRoute *_Route_FindInterfaceRoute(int AddressType, const void *Address)
{
tRoute *best = NULL, *rt;
int addrSize = IPStack_GetAddressSize(AddressType);
/**
*/
-tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address)
+tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, const void *Address)
{
tRoute *rt;
tRoute *best = NULL;
checksum[0] = htons( ~IPv4_Checksum(buf, sizeof(buf)) ); // Partial checksum
}
Header->Checksum = htons( IPv4_Checksum(checksum, sizeof(checksum)) ); // Combine the two
- IPv6_SendPacket(Conn->Interface, Conn->RemoteIP.v6, IP4PROT_TCP, Length, Data);
+ IPv6_SendPacket(Conn->Interface, Conn->RemoteIP.v6, IP4PROT_TCP, buffer);
break;
}
}