From 5ee801f4fb22bba3298f10273027e67f53692e4c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 15 Mar 2014 16:02:53 +0800 Subject: [PATCH] Modules/IPStack - Abstract HW addr cache, IPv6 TX (no ND yet) --- KernelLand/Modules/IPStack/Makefile | 4 +- KernelLand/Modules/IPStack/arp.c | 265 +------------------ KernelLand/Modules/IPStack/hwaddr_cache.c | 306 ++++++++++++++++++++++ KernelLand/Modules/IPStack/hwaddr_cache.h | 14 + KernelLand/Modules/IPStack/ipstack.h | 3 +- KernelLand/Modules/IPStack/ipv4.c | 54 +--- KernelLand/Modules/IPStack/ipv6.c | 78 ++++-- KernelLand/Modules/IPStack/ipv6.h | 2 +- KernelLand/Modules/IPStack/main.c | 20 ++ KernelLand/Modules/IPStack/routing.c | 8 +- KernelLand/Modules/IPStack/tcp.c | 2 +- 11 files changed, 424 insertions(+), 332 deletions(-) create mode 100644 KernelLand/Modules/IPStack/hwaddr_cache.c create mode 100644 KernelLand/Modules/IPStack/hwaddr_cache.h diff --git a/KernelLand/Modules/IPStack/Makefile b/KernelLand/Modules/IPStack/Makefile index 3ea5f7e7..0d8f5821 100644 --- a/KernelLand/Modules/IPStack/Makefile +++ b/KernelLand/Modules/IPStack/Makefile @@ -3,8 +3,8 @@ 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 diff --git a/KernelLand/Modules/IPStack/arp.c b/KernelLand/Modules/IPStack/arp.c index 5b9303b9..d9422f03 100644 --- a/KernelLand/Modules/IPStack/arp.c +++ b/KernelLand/Modules/IPStack/arp.c @@ -11,25 +11,12 @@ #include "include/adapters_int.h" // for MAC addr #include #include +#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 @@ -38,154 +25,24 @@ extern tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broad // === 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] @@ -206,119 +63,8 @@ tMacAddr ARP_Resolve4(tInterface *Interface, tIPv4 Address) // 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 @@ -376,7 +122,8 @@ 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]); - 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; @@ -434,7 +181,7 @@ void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffe switch( req4->SWSize ) { case 4: - ARP_UpdateCache4( req4->SourceIP, From ); + HWCache_Set(Adapter, 4, &req4->SourceIP, &From); break; #if ARPv6 case 6: @@ -442,7 +189,7 @@ void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffe Log_Debug("ARP", "Recieved undersized packet (IPv6)"); return ; } - ARP_UpdateCache6( req6->SourceIP, From ); + HWCache_Set(Adapter, 6, &req6->SourceIP, &From ); break; #endif default: diff --git a/KernelLand/Modules/IPStack/hwaddr_cache.c b/KernelLand/Modules/IPStack/hwaddr_cache.c new file mode 100644 index 00000000..1a4f4205 --- /dev/null +++ b/KernelLand/Modules/IPStack/hwaddr_cache.c @@ -0,0 +1,306 @@ +/* + * 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 +#include +#include // *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); +} diff --git a/KernelLand/Modules/IPStack/hwaddr_cache.h b/KernelLand/Modules/IPStack/hwaddr_cache.h new file mode 100644 index 00000000..1f6218b0 --- /dev/null +++ b/KernelLand/Modules/IPStack/hwaddr_cache.h @@ -0,0 +1,14 @@ +/* + */ +#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 + diff --git a/KernelLand/Modules/IPStack/ipstack.h b/KernelLand/Modules/IPStack/ipstack.h index 5ea5dc97..ddcdde96 100644 --- a/KernelLand/Modules/IPStack/ipstack.h +++ b/KernelLand/Modules/IPStack/ipstack.h @@ -120,8 +120,9 @@ static const tMacAddr cMAC_ZERO = {{0x00,0x00,0x00,0x00,0x00,0x00}}; 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 diff --git a/KernelLand/Modules/IPStack/ipv4.c b/KernelLand/Modules/IPStack/ipv4.c index 11cbc152..82bdae65 100644 --- a/KernelLand/Modules/IPStack/ipv4.c +++ b/KernelLand/Modules/IPStack/ipv4.c @@ -6,6 +6,7 @@ #include "ipstack.h" #include "link.h" #include "ipv4.h" +#include "hwaddr_cache.h" #include "firewall.h" // === CONSTANTS === @@ -16,8 +17,6 @@ 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(); @@ -74,7 +73,7 @@ int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, tIPS 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", @@ -196,10 +195,6 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff // 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); @@ -215,6 +210,13 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff } 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, @@ -241,44 +243,16 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff // 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] ) { diff --git a/KernelLand/Modules/IPStack/ipv6.c b/KernelLand/Modules/IPStack/ipv6.c index 090e4c03..2ac05747 100644 --- a/KernelLand/Modules/IPStack/ipv6.c +++ b/KernelLand/Modules/IPStack/ipv6.c @@ -6,6 +6,7 @@ #include "link.h" #include "ipv6.h" #include "firewall.h" +#include "hwaddr_cache.h" // === IMPORTS === extern tInterface *gIP_Interfaces; @@ -52,9 +53,34 @@ int IPv6_RegisterCallback(int ID, tIPCallback Callback) * \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; } /** @@ -117,6 +143,7 @@ void IPv6_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff if(nextHeader == 0) { // TODO: Parse the options (actually, RFC2460 doesn't specify any) + // Two Defined: Pad1 and PadN } // Routing Options else if(nextHeader == 43) @@ -125,7 +152,7 @@ void IPv6_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff } 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) @@ -145,6 +172,21 @@ void IPv6_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff } 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, @@ -168,30 +210,18 @@ void IPv6_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff // 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); diff --git a/KernelLand/Modules/IPStack/ipv6.h b/KernelLand/Modules/IPStack/ipv6.h index d2e4f28d..ee17c01a 100644 --- a/KernelLand/Modules/IPStack/ipv6.h +++ b/KernelLand/Modules/IPStack/ipv6.h @@ -37,6 +37,6 @@ struct sIPv6Header #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 diff --git a/KernelLand/Modules/IPStack/main.c b/KernelLand/Modules/IPStack/main.c index bc920f1f..82373ece 100644 --- a/KernelLand/Modules/IPStack/main.c +++ b/KernelLand/Modules/IPStack/main.c @@ -108,6 +108,26 @@ int IPStack_CompareAddress(int AddressType, const void *Address1, const void *Ad 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 ) diff --git a/KernelLand/Modules/IPStack/routing.c b/KernelLand/Modules/IPStack/routing.c index ed3814bb..24bb8fa2 100644 --- a/KernelLand/Modules/IPStack/routing.c +++ b/KernelLand/Modules/IPStack/routing.c @@ -27,8 +27,8 @@ tRoute *_Route_FindExactRoute(int Type, void *Network, int Subnet, int Metric); // - 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); @@ -444,7 +444,7 @@ tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, v /** * \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); @@ -487,7 +487,7 @@ tRoute *_Route_FindInterfaceRoute(int AddressType, void *Address) /** */ -tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address) +tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, const void *Address) { tRoute *rt; tRoute *best = NULL; diff --git a/KernelLand/Modules/IPStack/tcp.c b/KernelLand/Modules/IPStack/tcp.c index 4ef4bb36..fcff0143 100644 --- a/KernelLand/Modules/IPStack/tcp.c +++ b/KernelLand/Modules/IPStack/tcp.c @@ -148,7 +148,7 @@ void TCP_SendPacket( tTCPConnection *Conn, tTCPHeader *Header, size_t Length, co 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; } } -- 2.20.1