// makes a room for a new entry, get rid of // the least recently used entry (LRU) public void PurgeLRUEntry() { if (arpEntries.Count == 0) { return; } // can use a LRU list to avoid O(n) // but this is a kind of a small table... IDictionaryEnumerator dicEnum = arpEntries.GetEnumerator(); dicEnum.MoveNext(); // get the first entry ArpEntry lruElement = (ArpEntry)dicEnum.Value; while (dicEnum.MoveNext()) { ArpEntry current = (ArpEntry)dicEnum.Value; if (current.EntryAge < lruElement.EntryAge) { lruElement = current; } } RemoveEntry(lruElement); }
// add a new entry // return false if there is no more room public bool AddEntry(ArpEntry e) { // if no more room, make one if (arpEntries.Count >= maxEntries) { PurgeLRUEntry(); } e.EntryAge = this.defaultAge; arpEntries.Add(e.IPAddress, e); DebugPrint("Added entry {0}\n", e); return(true); }
// an upper layer interface to get the mac // to a target IP. The upper protocol must // provide the Mux for the target IP. // if we have it then we return true + macAddress // and refresh the age to create a LRU list public bool Lookup(IPv4 targetIP, out EthernetAddress macAddress) { ArpEntry e = arpEntries[targetIP] as ArpEntry; if (e != null) { e.EntryAge = Age; macAddress = e.MacAddress; return(true); } macAddress = EthernetAddress.Zero; return(false); }
private void RemoveEntry(ArpEntry e) { arpEntries.Remove(e.IPAddress); DebugPrint("Removed entry for {0}\n", e); }
// Original note from Yaron: // ARP logic: see RFC 826 http://www.faqs.org/rfcs/rfc826.html // public void ProcessIncomingPacket(Bytes packet, IAdapter adapter) { //Get the ARP packet info located after the ethernet header ArpHeader arpHeader = new ArpHeader(packet, 14); DebugPrint("ARP: ProcessIncomingPacket\n"); //do some checks to make sure the packet is copacetic if (arpHeader.htype != 0x1) { DebugPrint("ARP: ProcessIncomingPacket got wrong hardware type? 0x{0,8:x}\n", arpHeader.htype); //delete packet; return; } if (arpHeader.ptype != 0x0800) { DebugPrint("ARP: ProcessIncomingPacket got wrong protocol? 0x{0,8:x}\n", arpHeader.ptype); //delete packet; return; } //ethernet address should be 6 bytes if (arpHeader.hlen != 6) { DebugPrint("ARP: ProcessIncomingPacket got wrong hw length? 0x{0,8:x}\n", arpHeader.hlen); //delete packet; return; } if (arpHeader.plen != 4) { DebugPrint("ARP: ProcessIncomingPacket got wrong protocol address length? 0x{0,8:x}\n", arpHeader.plen); //delete packet; return; } DebugPrint("Incoming packet\n"); bool merged = false; bool updated = false; ArpEntry target = arpTable.Lookup(arpHeader.senderIPAddr); if (target != null && target.Dynamic == true) { DebugPrint("ARP UPDATE\n"); // we have it already - just update the details... target.MacAddress = arpHeader.senderEthernetAddr; target.EntryAge = arpTable.Age; merged = true; updated = true; } if (merged == false) { DebugPrint("ARP ADDITION\n"); arpTable.AddEntry(new ArpEntry(arpHeader.senderIPAddr, arpHeader.senderEthernetAddr, true)); merged = true; UpdatePendingRequests(arpHeader.senderIPAddr, arpHeader.senderEthernetAddr); } //Is this a local address bool forSelf = IP.IsLocalAddress(arpHeader.destIPAddr); if (forSelf == false) { //delete packet; return; } // now figure out the opcode if (arpHeader.op == ARP_REQUEST) { DebugPrint("Handling request ({0},{1}) ---> ({2},{3} \npkt dest {4} {5})\n", arpHeader.senderIPAddr, arpHeader.senderEthernetAddr, arpHeader.destIPAddr, adapter.HardwareAddress, arpHeader.destIPAddr, arpHeader.destEthernetAddr ); int dataLength = EthernetHeader.Size + ArpHeader.Size; VTable.Assert(packet.Length >= dataLength); Bytes data = Bitter.SplitOff(ref packet, EthernetHeader.Size); EthernetHeader.Write(packet, adapter.HardwareAddress, arpHeader.senderEthernetAddr, EthernetHeader.PROTOCOL_ARP); //use arp header to format reply ArpHeader.Write(data, adapter.HardwareAddress, arpHeader.destIPAddr, ArpHeader.ARP_REPLY, arpHeader.senderEthernetAddr, arpHeader.senderIPAddr); adapter.PopulateTxRing(packet, data); } else { // otherwise we are done DebugPrint( "Handling reply ({2},{3}) <--- ({0},{1})\n", arpHeader.senderIPAddr, arpHeader.senderEthernetAddr, arpHeader.destIPAddr, arpHeader.destEthernetAddr ); //delete packet; } if (merged && !updated) { DebugPrint(arpTable.ToString()); } }