arp -- Internet and Ethernet address resolution protocol


ARP is a protocol used to dynamically map between Internet (IP) and IEEE MAC addresses. It is used by all the Ethernet-style interface drivers running the Internet protocols.

ARP caches Internet-IEEE address mappings. When an interface requests a mapping for an address not in the cache, ARP queues the message which requires the mapping and broadcasts a message on the associated network requesting the address mapping. If a response is provided, the new mapping is cached and any pending message is transmitted. ARP will queue at most one packet while waiting for a mapping request to be responded to; only the most recently ``transmitted'' packet is kept. The ARP protocol is implemented by a STREAMS driver to do the protocol negotiation.

To facilitate communications with systems which do not use ARP, a mechanism is provided for manipulating the entries in the arp cache. Since the arp cache is stored in the routing table, this requires use of the routing stream driver (see route(ADMP).

An arp ``route'' consists of an IP destination and a link-level next hop address. To add an ARP entry, issue an RTM_ADD message to the routing stream interface. Both the destination and gateway address fields must be present. The destination address is defined as follows (see sys/netinet/if_ether.h):

struct sockaddr_inarp {
	u_char  sin_len;		/* not used */
	u_char  sin_family;		/* AF_INET */
	u_short sin_port;		/* not used */
	struct  in_addr sin_addr;	/* IP address */
	struct  in_addr sin_srcaddr;	/* not used */
	u_short sin_tos;		/* not used */
	u_short sin_other;		/* set to SIN_PROXY to publish */
#define SIN_PROXY 1
The gateway is a link-level address and is defined using the following structure (see sys/net/if_dl.h):
 * Structure of a Link-Level sockaddr:
struct sockaddr_dl {
        u_short sdl_family;     /* AF_DL */
        u_short sdl_index;      /* if != 0, index for interface */
        u_char  sdl_type;       /* if type (see net/if_types.h) */
        u_char  sdl_alen;       /* link address length (normally 6) */
        char    sdl_data[10];   /* address */
#define LLADDR(s) ((caddr_t)((s)->sdl_data))
To retrieve all ARP entries, code similar to that shown in route(ADMP) can be used. The gi_arg field of the rt_giarg structure should be set to RTF_LLINFO. This ensures that only routes with valid link-level information (i.e. ARP entries) are retrieved.

The following sample code shows how to add an ARP entry:

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stream.h>
#include <sys/time.h>
#include <sys/stropts.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <net/if_arp.h>
#include <netinet/if_ether.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>

struct sockaddr_inarp blank_sin = {AF_INET}, sin_m; struct sockaddr_dl blank_sdl = {AF_LINK}, sdl_m; struct { struct rt_msghdr m_rtm; char m_space[512]; } m_rtmsg;

setarp(ia, ha, len) struct in_addr *ia; /* IP address */ u_char *ha; /* hardware address */ int len; /* hardware address length (6) */ { int s; int r; struct rt_msghdr *rtm = &m_rtmsg.m_rtm ; struct timeval time; struct strioctl si;

s = open(_PATH_ROUTE, O_WRONLY, 0); /* open routing stream */ if (s < 0) { perror("_PATH_ROUTE"); return s; } (void) ioctl(s, I_SRDOPT, RMSGD); /* message discard mode */

si.ic_cmd = RTSTR_USELOOPBACK; /* don't want my msgs */ si.ic_dp = (char *)0; si.ic_len = 0; si.ic_timout = -1; (void) ioctl(s, I_STR, &si);

/* copy in IP and arp addresses */ sin_m = blank_sin; sdl_m = blank_sdl; bcopy((char *)ia, &sin_m.sin_addr.s_addr, sizeof(struct in_addr)); bcopy((char *)ha, sdl_m.sdl_data, len); sdl_m.sdl_alen = len;

/* add the entry */ (void) gettimeofday(&time, (struct timezone *)0); r = rtmsg(s, RTM_ADD, &sin_m, &sdl_m, time.tv_sec + 20 * 60); if (r < 0 && errno != EEXIST) { perror("RTM_ADD"); close(s); return r; } close(s); return 0; }

static int seq = 0;

rtmsg(s, msg, sin, sdl, expire) int s; int msg; struct sockaddr_inarp *sin; struct sockaddr_dl *sdl; int expire; { char *cp = (char *)m_rtmsg.m_space; struct rt_msghdr *rtm = &m_rtmsg.m_rtm ; int r = 0; struct strioctl si;

/* initialize message header */ bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); rtm->rtm_flags = 0; rtm->rtm_version = RTM_VERSION; rtm->rtm_addrs |= RTA_GATEWAY|RTA_DST; rtm->rtm_rmx.rmx_expire = expire; rtm->rtm_inits = RTV_EXPIRE; rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); sin->sin_other = 0;

#define NEXTADDR(w, s) \ if (rtm->rtm_addrs & (w)) { \ bcopy((char *)s, cp, sizeof(*s)); cp += sizeof(*s);}

NEXTADDR(RTA_DST, sin); NEXTADDR(RTA_GATEWAY, sdl); rtm->rtm_msglen = cp - (char *)&m_rtmsg ; rtm->rtm_seq = ++seq; rtm->rtm_type = msg;

si.ic_cmd = RTSTR_SEND; si.ic_dp = (char *)&m_rtmsg ; si.ic_len = rtm->rtm_msglen; si.ic_timout = 0;

r = ioctl(s, I_STR, (char *)&si); if (r < 0) return r; return 0; }

The RTSTR_USELOOPBACK ioctl indicates that the process does not desire to receive routing messages generated as a result of its own operations.

To denote an ARP entry as being permanent, the rt_expire field in the route structure should be set to zero. A non-zero value is treated as the time in seconds that the entry should be considered valid.

An ARP entry may be ``published.'' This will cause ARP to answer requests for the entry even if its IP address is not one of the local addresses of the system. An entry is published by setting the sin_other field of the sockaddr_inarp structure to the value SIN_PROXY. ARP watches passively for hosts impersonating the local host (that is, a host that responds to an ARP mapping request for the local host's address).


arp: duplicate IP address %x sent from ethernet address:address
ARP has discovered another host on the local network which responds to mapping requests for its own Internet address.

arp: invalid opcode %d
ARP received an arp op-code that was not a request or a reply.

arp: broadcast IP address
ARP received a request or reply whose source or destination address was a broadcast address.

arp: info overwritten for %x by %s
ARP received a reply that changed the MAC address associated with an existing completed entry. This may indicate a hardware change on a remote system.
An ioctl operation may fail with the errno set to one of the following:

when no argument/NULL argument is passed to the driver.

when the associated file descriptor is no longer open/valid.

insufficient STREAMS resources were available to return the ARP table.



See also

arp(ADMN), ifconfig(ADMN), inet(ADMP), route(ADMP), streamio(M)

Standards conformance

arp is conformant with:

RFC 826 (STD 37), RFC 1042 (STD 43)

© 2003 Caldera International, Inc. All rights reserved.
SCO OpenServer Release 5.0.7 -- 11 February 2003