#include "arp.h"
#include "link.h"
#include "ipv4.h" // For IPv4_Netmask
+#include "include/adapters_int.h" // for MAC addr
+#include <semaphore.h>
+#include <timers.h>
#define ARPv6 0
-#define ARP_CACHE_SIZE 64
+#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
void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer);
// === GLOBALS ===
+ int giARP_WaitingThreads;
struct sARP_Cache4 {
tIPv4 IP;
tMacAddr MAC;
} *gaARP_Cache4;
int giARP_Cache4Space;
tMutex glARP_Cache4;
+tSemaphore gARP_Cache4Semaphore;
#if ARPv6
struct sARP_Cache6 {
tIPv6 IP;
int giARP_Cache6Space;
tMutex glARP_Cache6;
#endif
-volatile int giARP_LastUpdateID = 0;
// === 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
#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)
{
- int lastID;
int i;
struct sArpRequest4 req;
- Sint64 timeout;
ENTER("pInterface xAddress", Interface, Address);
LEAVE('-');
return gaARP_Cache4[i].MAC;
}
+ giARP_WaitingThreads ++;
Mutex_Release( &glARP_Cache4 );
- lastID = giARP_LastUpdateID;
-
// Create request
Log_Log("ARP4", "Asking for address %i.%i.%i.%i",
Address.B[0], Address.B[1], Address.B[2], Address.B[3]
req.HWSize = 6;
req.SWSize = 4;
req.Request = htons(1);
- req.SourceMac = Interface->Adapter->MacAddr;
+ memcpy(&req.SourceMac, Interface->Adapter->HWAddr, 6); // TODO: Remove hard size
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
+ // Assumes only a header and footer at link layer
+ tIPStackBuffer *buffer = IPStack_Buffer_CreateBuffer(3);
IPStack_Buffer_AppendSubBuffer(buffer, sizeof(struct sArpRequest4), 0, &req, NULL, NULL);
// Send Request
Link_SendPacket(Interface->Adapter, 0x0806, req.DestMac, buffer);
+ // Clean up
IPStack_Buffer_DestroyBuffer(buffer);
- timeout = now() + Interface->TimeoutDelay;
-
// Wait for a reply
+ Time_ScheduleTimer(NULL, Interface->TimeoutDelay);
for(;;)
{
- while(lastID == giARP_LastUpdateID && now() < timeout) {
- Threads_Yield();
- }
-
- if( now() >= timeout ) {
+ if( Semaphore_Wait(&gARP_Cache4Semaphore, 1) != 1 )
+ {
+ giARP_WaitingThreads --;
Log_Log("ARP4", "Timeout");
- break; // Timeout
+ break;
}
-
- lastID = giARP_LastUpdateID;
+ 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],
else
i = oldest;
}
-
- 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
- );
+
+ 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();
- giARP_LastUpdateID ++;
+ 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);
}
req4->DestIP = req4->SourceIP;
req4->DestMac = req4->SourceMac;
req4->SourceIP = *(tIPv4*)iface->Address;;
- req4->SourceMac = Adapter->MacAddr;
+ memcpy(&req4->SourceMac, Adapter->HWAddr, 6); // TODO: Remove hard size
req4->Request = htons(2);
Log_Debug("ARP", "Sending back us (%02x:%02x:%02x:%02x:%02x:%02x)",
req4->SourceMac.B[0], req4->SourceMac.B[1],
// 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);
+ IPStack_Buffer_AppendSubBuffer(buffer, sizeof(struct sArpRequest4), 0, req4, NULL, NULL);
Link_SendPacket(Adapter, 0x0806, req4->DestMac, buffer);
IPStack_Buffer_DestroyBuffer(buffer);
}