Skip to content
opencode-agent[bot] edited this page May 10, 2026 · 1 revision

Address Resolution Protocol (ARP)

Resolves IPv4 addresses to hardware (MAC) addresses and maintains a timed cache of these mappings.

Overview

ARP is a critical network layer protocol in JNode that maps Layer 3 (IPv4) addresses to Layer 2 (hardware/MAC) addresses. Every time the network stack needs to send a packet to an IP address on the local network, ARP must first resolve the target IP to a MAC address. JNode's ARP implementation lives in net/src/net/org/jnode/net/arp/ and supports both ARP and RARP (Reverse ARP) operations.

ARP is registered as a NetworkLayer in the network stack, sitting between the device driver (Ethernet) and upper protocols like IPv4. It uses a time-limited cache to store discovered IP-to-MAC mappings, reducing broadcast storm frequency.

Key Components

Class Role
ARPNetworkLayer Main network layer; handles packet receive, cache lookups, and request transmission
ARPCache Thread-safe cache mapping IPv4 addresses to MAC addresses with TTL
ARPCacheEntry Individual cache entry with creation time, lifetime, and dynamic/static flag
ARPHeader Packet structure: HTYPE, PTYPE, OPERATION, sender/target HW+Protocol addresses
ARPOperation Enum: ARP_REQUEST, ARP_REPLY, RARP_REQUEST, RARP_REPLY
ARPStatistics Packet counters: requests, replies, errors
RARPNetworkLayer Handles RARP requests (bootstrapping from hardware address)

How It Works

Cache Lookup

When upper layers (e.g., IPv4) need a hardware address for a destination IP, they call ARPNetworkLayer.getHardwareAddress():

public HardwareAddress getHardwareAddress(ProtocolAddress address, ProtocolAddress myAddress,
                                          Device device, long timeout) throws TimeoutException, NetworkException {
    // 1. If target IP equals our IP, return our own MAC address
    if (address.equals(myAddress)) {
        return getAPI(device).getAddress();
    }

    // 2. Poll cache until resolved or timeout
    while (true) {
        final HardwareAddress hwAddress = cache.get(address);
        if (hwAddress != null) {
            return hwAddress;
        }
        // 3. Send ARP request every ARP_REQUEST_DELAY (1500ms)
        if ((now - lastReq) >= ARP_REQUEST_DELAY) {
            request(address, myAddress, device);
        } else {
            cache.waitForChanges(Math.min(timeout, ARP_REQUEST_DELAY));
        }
    }
}

Packet Receive Flow

When an ARP packet arrives via the device driver, receive() is invoked:

  1. Parse the ARPHeader from the SocketBuffer
  2. Update the cache with the sender's IP-MAC mapping (cache.set())
  3. Dispatch by operation type:
    • ARP_REQUEST → check if target IP is ours; if so, send ARP_REPLY
    • ARP_REPLY → cache is already updated; signal waiting threads
    • RARP_REQUEST / RARP_REPLY → log (minimal RARP support)

ARP Request Construction

private void request(ProtocolAddress address, ProtocolAddress myAddress, Device device) {
    final ARPHeader hdr = new ARPHeader(
        srcHwAddr, myAddress,       // sender HW + IP
        trgHwAddr, address,         // target HW + IP
        ARPOperation.ARP_REQUEST,
        hwtype, ptype,
        EthernetConstants.ETH_ALEN, // 6
        4                           // IPv4 = 4 bytes
    );
    // Prefix header to socket buffer, transmit to broadcast address
}

Cache Implementation

ARPCache maintains two synchronized HashMap views (IPv4→MAC and MAC→IPv4) with a 10-minute TTL per entry:

private final Map<ProtocolAddress, ARPCacheEntry> protocolToNetworkAddresses =
    new HashMap<ProtocolAddress, ARPCacheEntry>();

public synchronized void set(HardwareAddress hw, ProtocolAddress ip, boolean dynamic) {
    final ARPCacheEntry entry = new ARPCacheEntry(hw, ip, dynamic);
    protocolToNetworkAddresses.put(ip, entry);
    networkToProtocolAddresses.put(hw, entry);
    notifyAll(); // wake up waiting getHardwareAddress callers
}

public synchronized HardwareAddress get(ProtocolAddress ip) {
    final ARPCacheEntry entry = protocolToNetworkAddresses.get(ip);
    if (entry != null && entry.isExpired()) {
        // remove and return null
    }
    return (entry != null) ? entry.getHwAddress() : null;
}

Gotchas

  • Cache TTL is fixed: ARP_CACHE_LIFETIME = 10 * 60 * 1000 (10 minutes). The comment in ARPCacheEntry notes it should be configurable.
  • ARP_REQUEST_DELAY (1500ms): Requests are throttled; rapid lookups wait on cache.waitForChanges() rather than spamming the network.
  • getType() bug: ARPOperation.getType() is broken — it always returns the first enum value in the loop instead of the matching one. This means RARP_REQUEST and RARP_REPLY operations are misidentified.
  • RARP minimal support: RARP requests are logged but not processed. The RARPNetworkLayer class exists but is not fully implemented.
  • NoGratuitous ARP: JNode does not send gratuitous ARPs when addresses are assigned; neighbors may not update their caches when the local host's MAC-IP binding changes.

Related Pages

Clone this wiki locally