Address Resolution Protocol Information (ARP)

Every network adapter has a unique hardware address burned into its ROM. When data is sent over the network, the media access control (MAC) header in an Ethernet frame will contain both the source and destination hardware addresses (also known as MAC addresses) for the packet. TCP/IP then uses address resolution to map a network interface's IP address to its physical hardware address.

The Address Resolution Protocol (ARP) is a support protocol and is part of the network layer of the TCP/IP OSI stack. ARP is responsible not only for performing the IP address to hardware mapping, but also for making requests and forwarding packets to the default gateway on the network.

The ARP Table

Pocket PC devices use an internal cache to store information about the mapping of IP addresses to physical MAC addresses. This cache is known as the ARP Map Table, and can be examined using the IPHelper API functions. To do so, you can use the following:

DWORD GetIpNetTable(MIB_IPNETTABLE *pIpNetTable, ULONG *pdwSize,
   BOOL bOrder);

The first parameter, pIpNetTable, is a pointer to a buffer that will contain the map table when the function returns. The pdwSize parameter is used to specify a pointer to a variable that contains the size of the buffer pIpNetTable. If the buffer is too small, the function will return an error and put the proper size into this variable. Finally, the bOrder parameter should be set to TRUE if you want the map table to be sorted in ascending order of IP addresses.

The map table returned from GetIpNetTable() is in the format of a MIB_IPNETTABLE structure. This structure contains the total number of IP address mappings, along with an array of MIB_IPNETROW structures that contain the actual ARP map information per address. The MIB_IPNETTABLE structure is defined as follows:

typedef struct _MIB_IPNETTABLE {
   DWORD dwNumEntries;

Each mapping entry is in the format of a MIB_IPNETROW structure:

typedef struct _MIB_IPNETROW {
   DWORD dwIndex;
   DWORD dwPhysAddrLen;
   DWORD dwAddr;
   DWORD dwType;

The first field, dwIndex, specifies the index of the network adapter. The next two fields define the hardware MAC address?dwPhysAddrLen specifies the length, in bytes, of bPhysAddr, which contains the actual physical address. This is followed by the dwAddr field, which contains the IP address to which the hardware is mapped. Finally, dwType specifies the type of ARP address entry; it can be one of the values listed in Table 3.3.

Table 3.3. IP Address Entry Types




Other entry


Invalid entry


Dynamic entry


Static entry

If you want to delete all of the IP address mappings from your local ARP map table cache, you can simply call the FlushIpNetTable() function, which is defined as follows:

DWORD FlushIpNetTable(DWORD dwIfIndex);

The only parameter FlushIpNetTable() needs is the index to the network interface for which you wish to delete all mappings. If the cache is successfully flushed, the function will return a value of NO_ERROR.

ARP Table Entries

The IPHelper API functions also enable you to create, delete, or modify an ARP table mapping.

To create a new entry in the ARP table, you must first completely populate a MIB_IPNETROW structure with the mapping information, and then call the CreateIpNetEntry() function:

DWORD CreateIpNetEntry(MIB_IPNETROW *pArpEntry);

If the creation of the ARP entry was successful, CreateIpNetEntry() will return a NO_ERROR value.

To modify an existing entry, you can use the SetIpNetEntry() function, which is defined as follows:

DWORD SetIpNetEntry(MIB_IPNETROW *pArpEntry);

The only parameter that SetIpNetEntry() needs is a pointer to a MIB_IPNETROW structure containing the information you want to modify in the mapping.

Finally, to delete an entry, use the following:

DWORD DeleteIpNetEntry(MIB_IPNETROW *pArpEntry);

Once again, the parameter pArpEntry is a pointer to a MIB_IPNETROW structure. The structure only needs to have its dwIndex and dwAddr fields completed to successfully delete an entry.

Sending an ARP Message

To determine the physical address of another device on the network, all you need to do is send that device an ARP request message using the SendARP() function, which is defined as follows:

DWORD SendARP(IPAddr DestIP, IPAddr SrcIP, ULONG *pMacAddr,
   ULONG *PhyAddrLen);

The first parameter, DestIP, is the address of the host from which you want to get the MAC address. The next parameter, SrcIP, is your own device's IP address. Because this is an optional parameter, it can be set to 0. The last two parameters point to buffers that contain the MAC address and the size of the destination IP when the function returns.

ARP Proxy Entries

ARP proxies, while rarely used on a handheld device, can be useful when you have multiple network interfaces and need the capability to route packets between two separate subnets. Essentially, using an ARP proxy (PARP) is a way to trick IP into correctly routing packets over multiple subnets.

For example, when a device needs to send a packet of data to a destination, it will first transmit an ARP request (using SendARP()) on the same subnet as itself. The request basically asks, "Who has the IP address x.x.x.x mapped to its hardware?" The device that has mapped the requested IP address will then respond with a message containing its MAC address. From this point forward, all packets to that IP address are sent to the MAC address of the device that responded.

Setting up an ARP proxy enables your adapter to respond and forward those requests. To create an ARP proxy, you can call the CreateProxyArpEntry() function, which is defined as follows:

DWORD CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask,
  DWORD dwIfIndex);

The first parameter is the IP address that you want to act as an ARP proxy. Next, dwMask is the subnet mask for the IP address specified by dwAddress. The last parameter, dwIfIndex, is the index of the interface you want to proxy.

If the function successfully creates the proxy, it will return a value of NO_ERROR.

To delete an ARP proxy entry, you need to call the following function. Notice that the DeleteProxyArpEntry() function takes exactly the same parameters as your initial call to CreateProxyArpEntry(). The function is defined as follows:

DWORD DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask,
  DWORD dwIfIndex);