7 * \defgroup uiparp uIP Address Resolution Protocol
10 * The Address Resolution Protocol ARP is used for mapping between IP
11 * addresses and link level addresses such as the Ethernet MAC
12 * addresses. ARP uses broadcast queries to ask for the link level
13 * address of a known IP address and the host which is configured with
14 * the IP address for which the query was meant, will respond with its
17 * \note This ARP implementation only supports Ethernet.
22 * Implementation of the ARP Address Resolution Protocol.
23 * \author Adam Dunkels <adam@dunkels.com>
28 * Copyright (c) 2001-2003, Adam Dunkels.
29 * All rights reserved.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. The name of the author may not be used to endorse or promote
40 * products derived from this software without specific prior
43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
44 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
45 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
47 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
49 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
50 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
51 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
52 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
53 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55 * This file is part of the uIP TCP/IP stack.
62 #include "uip_netif.h"
69 #define UIP_LOG(m) uip_log(__FILE__,__LINE__,m)
72 #endif /* UIP_LOGGING == 1 */
74 #if UIP_STATISTICS == 1
75 struct uip_stats uip_stat
;
79 #endif /* UIP_STATISTICS == 1 */
82 #define ARP_TRY_HARD 0x01
84 #define ARP_MAXAGE 240
85 #define ARP_MAXPENDING 2
90 #define ARP_HWTYPE_ETH 1
92 #define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8)
93 #define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff)
95 #define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8))
96 #define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8))
106 struct uip_ip_addr ipaddr
;
107 struct uip_eth_addr ethaddr
;
108 enum arp_state state
;
112 static const struct uip_eth_addr ethbroadcast
= {{0xff,0xff,0xff,0xff,0xff,0xff}};
113 static struct arp_entry arp_table
[UIP_ARPTAB_SIZE
];
114 /*-----------------------------------------------------------------------------------*/
116 * Initialize the ARP module.
119 /*-----------------------------------------------------------------------------------*/
124 for(i
= 0; i
< UIP_ARPTAB_SIZE
; ++i
) {
125 arp_table
[i
].state
= ARP_STATE_EMPTY
;
126 arp_table
[i
].time
= 0;
129 /*-----------------------------------------------------------------------------------*/
131 * Periodic ARP processing function.
133 * This function performs periodic timer processing in the ARP module
134 * and should be called at regular intervals. The recommended interval
135 * is 10 seconds between the calls.
138 /*-----------------------------------------------------------------------------------*/
144 for(i
=0;i
<UIP_ARPTAB_SIZE
;i
++) {
146 if(arp_table
[i
].state
==ARP_STATE_STABLE
&& arp_table
[i
].time
>=ARP_MAXAGE
) {
147 arp_table
[i
].state
= ARP_STATE_EXPIRED
;
148 } else if(arp_table
[i
].state
==ARP_STATE_PENDING
) {
149 if(arp_table
[i
].time
>=ARP_MAXPENDING
) arp_table
[i
].state
= ARP_STATE_EXPIRED
;
152 if(arp_table
[i
].state
==ARP_STATE_EXPIRED
) arp_table
[i
].state
= ARP_STATE_EMPTY
;
156 static s8_t
uip_arp_findentry(struct uip_ip_addr
*ipaddr
,u8_t flags
)
158 s8_t old_pending
= UIP_ARPTAB_SIZE
, old_stable
= UIP_ARPTAB_SIZE
;
159 s8_t empty
= UIP_ARPTAB_SIZE
;
160 u8_t i
= 0,age_pending
= 0,age_stable
= 0;
162 /* Walk through the ARP mapping table and try to find an entry to
163 update. If none is found, the IP -> MAC address mapping is
164 inserted in the ARP table. */
165 for(i
= 0; i
< UIP_ARPTAB_SIZE
; ++i
) {
166 if(empty
==UIP_ARPTAB_SIZE
&& arp_table
[i
].state
==ARP_STATE_EMPTY
) {
168 } else if(arp_table
[i
].state
==ARP_STATE_PENDING
) {
169 if(ipaddr
&& ip_addr_cmp(ipaddr
,&arp_table
[i
].ipaddr
)) return i
;
170 else if(arp_table
[i
].time
>=age_pending
) {
172 age_pending
= arp_table
[i
].time
;
174 } else if(arp_table
[i
].state
==ARP_STATE_STABLE
) {
175 if(ipaddr
&& ip_addr_cmp(ipaddr
,&arp_table
[i
].ipaddr
)) return i
;
176 else if(arp_table
[i
].time
>=age_stable
) {
178 age_stable
= arp_table
[i
].time
;
182 if(empty
==UIP_ARPTAB_SIZE
&& !(flags
&ARP_TRY_HARD
)) return UIP_ERR_MEM
;
184 if(empty
<UIP_ARPTAB_SIZE
) i
= empty
;
185 else if(old_stable
<UIP_ARPTAB_SIZE
) i
= old_stable
;
186 else if(old_pending
<UIP_ARPTAB_SIZE
) i
= old_pending
;
187 else return UIP_ERR_MEM
;
189 arp_table
[i
].time
= 0;
190 arp_table
[i
].state
= ARP_STATE_EMPTY
;
191 if(ipaddr
!=NULL
) ip_addr_set(&arp_table
[i
].ipaddr
,ipaddr
);
196 /*-----------------------------------------------------------------------------------*/
197 static s8_t
uip_arp_update(struct uip_netif
*netif
,struct uip_ip_addr
*ipaddr
, struct uip_eth_addr
*ethaddr
,u8_t flags
)
201 if(ip_addr_isany(ipaddr
) ||
202 ip_addr_isbroadcast(ipaddr
,netif
) ||
203 ip_addr_ismulticast(ipaddr
)) return UIP_ERR_ARG
;
205 i
= uip_arp_findentry(ipaddr
,flags
);
208 arp_table
[i
].time
= 0;
209 arp_table
[i
].state
= ARP_STATE_STABLE
;
210 for(k
=0;k
<netif
->hwaddr_len
;k
++) arp_table
[i
].ethaddr
.addr
[k
] = ethaddr
->addr
[k
];
214 /*-----------------------------------------------------------------------------------*/
216 * ARP processing for incoming IP packets
218 * This function should be called by the device driver when an IP
219 * packet has been received. The function will check if the address is
220 * in the ARP cache, and if so the ARP cache entry will be
221 * refreshed. If no ARP cache entry was found, a new one is created.
223 * This function expects an IP packet with a prepended Ethernet header
224 * in the uip_buf[] buffer, and the length of the packet in the global
227 /*-----------------------------------------------------------------------------------*/
229 uip_arp_ipin(struct uip_netif
*netif
,struct uip_pbuf
*p
)
231 struct uip_ethip_hdr
*hdr
;
234 if(!ip_addr_netcmp(&hdr
->ip
.src
,&netif
->ip_addr
,&netif
->netmask
)) return;
236 uip_arp_update(netif
,&hdr
->ip
.src
,&hdr
->ethhdr
.src
,0);
239 /*-----------------------------------------------------------------------------------*/
241 * ARP processing for incoming ARP packets.
243 * This function should be called by the device driver when an ARP
244 * packet has been received. The function will act differently
245 * depending on the ARP packet type: if it is a reply for a request
246 * that we previously sent out, the ARP cache will be filled in with
247 * the values from the ARP reply. If the incoming ARP packet is an ARP
248 * request for our IP address, an ARP reply packet is created and put
249 * into the uip_buf[] buffer.
251 * When the function returns, the value of the global variable uip_len
252 * indicates whether the device driver should send out a packet or
253 * not. If uip_len is zero, no packet should be sent. If uip_len is
254 * non-zero, it contains the length of the outbound packet that is
255 * present in the uip_buf[] buffer.
257 * This function expects an ARP packet with a prepended Ethernet
258 * header in the uip_buf[] buffer, and the length of the packet in the
259 * global variable uip_len.
261 /*-----------------------------------------------------------------------------------*/
263 uip_arp_arpin(struct uip_netif
*netif
,struct uip_eth_addr
*ethaddr
,struct uip_pbuf
*p
)
266 struct uip_ip_addr sipaddr
,dipaddr
;
267 struct uip_arp_hdr
*hdr
;
269 if(p
->tot_len
<sizeof(struct uip_arp_hdr
)) {
276 *(struct uip_ip_addr2
*)((void*)&sipaddr
) = hdr
->sipaddr
;
277 *(struct uip_ip_addr2
*)((void*)&dipaddr
) = hdr
->dipaddr
;
279 if(netif
->ip_addr
.addr
==0) for_us
= 0;
280 else for_us
= ip_addr_cmp(&dipaddr
,&netif
->ip_addr
);
282 if(for_us
) uip_arp_update(netif
,&sipaddr
,&hdr
->shwaddr
,ARP_TRY_HARD
);
283 else uip_arp_update(netif
,&sipaddr
,&hdr
->shwaddr
,0);
285 switch(htons(hdr
->opcode
)) {
288 hdr
->opcode
= htons(ARP_REPLY
);
289 hdr
->dipaddr
= hdr
->sipaddr
;
290 hdr
->sipaddr
= *(struct uip_ip_addr2
*)((void*)&netif
->ip_addr
);
292 for(i
=0;i
<netif
->hwaddr_len
;i
++) {
293 hdr
->dhwaddr
.addr
[i
] = hdr
->shwaddr
.addr
[i
];
294 hdr
->shwaddr
.addr
[i
] = ethaddr
->addr
[i
];
295 hdr
->ethhdr
.dest
.addr
[i
] = hdr
->dhwaddr
.addr
[i
];
296 hdr
->ethhdr
.src
.addr
[i
] = ethaddr
->addr
[i
];
299 hdr
->hwtype
= htons(ARP_HWTYPE_ETH
);
300 ARPH_HWLEN_SET(hdr
,netif
->hwaddr_len
);
302 hdr
->protocol
= htons(UIP_ETHTYPE_IP
);
303 ARPH_PROTOLEN_SET(hdr
,sizeof(struct uip_ip_addr
));
305 netif
->linkoutput(netif
,p
);
307 UIP_LOG("uip_arp_arpin: ip packet not for us.\n");
313 UIP_LOG("uip_arp_arpin: ARP unknown opcode type.\n");
318 /*-----------------------------------------------------------------------------------*/
320 * Prepend Ethernet header to an outbound IP packet and see if we need
321 * to send out an ARP request.
323 * This function should be called before sending out an IP packet. The
324 * function checks the destination IP address of the IP packet to see
325 * what Ethernet MAC address that should be used as a destination MAC
326 * address on the Ethernet.
328 * If the destination IP address is in the local network (determined
329 * by logical ANDing of netmask and our IP address), the function
330 * checks the ARP cache to see if an entry for the destination IP
331 * address is found. If so, an Ethernet header is prepended and the
332 * function returns. If no ARP cache entry is found for the
333 * destination IP address, the packet in the uip_buf[] is replaced by
334 * an ARP request packet for the IP address. The IP packet is dropped
335 * and it is assumed that they higher level protocols (e.g., TCP)
336 * eventually will retransmit the dropped packet.
338 * If the destination IP address is not on the local network, the IP
339 * address of the default router is used instead.
341 * When the function returns, a packet is present in the uip_buf[]
342 * buffer, and the length of the packet is in the global variable
345 /*-----------------------------------------------------------------------------------*/
346 s8_t
uip_arp_out(struct uip_netif
*netif
,struct uip_ip_addr
*ipaddr
,struct uip_pbuf
*q
)
349 struct uip_eth_addr
*dest
,*srcaddr
,mcastaddr
;
350 struct uip_eth_hdr
*ethhdr
;
352 if(uip_pbuf_header(q
,sizeof(struct uip_eth_hdr
))!=0) {
353 UIP_LOG("uip_arp_out: could not allocate room for header.\n");
358 if(ip_addr_isbroadcast(ipaddr
,netif
)) {
359 dest
= (struct uip_eth_addr
*)ðbroadcast
;
360 } else if(ip_addr_ismulticast(ipaddr
)) {
361 /* Hash IP multicast address to MAC address.*/
362 mcastaddr
.addr
[0] = 0x01;
363 mcastaddr
.addr
[1] = 0x00;
364 mcastaddr
.addr
[2] = 0x5e;
365 mcastaddr
.addr
[3] = ip4_addr2(ipaddr
) & 0x7f;
366 mcastaddr
.addr
[4] = ip4_addr3(ipaddr
);
367 mcastaddr
.addr
[5] = ip4_addr4(ipaddr
);
368 /* destination Ethernet address is multicast */
371 if(!ip_addr_netcmp(ipaddr
,&netif
->ip_addr
,&netif
->netmask
)) {
372 if(netif
->gw
.addr
!=0) ipaddr
= &netif
->gw
;
373 else return UIP_ERR_RTE
;
375 return uip_arp_arpquery(netif
,ipaddr
,q
);
378 srcaddr
= (struct uip_eth_addr
*)netif
->hwaddr
;
380 for(i
=0;i
<netif
->hwaddr_len
;i
++) {
381 ethhdr
->dest
.addr
[i
] = dest
->addr
[i
];
382 ethhdr
->src
.addr
[i
] = srcaddr
->addr
[i
];
385 ethhdr
->type
= htons(UIP_ETHTYPE_IP
);
386 return netif
->linkoutput(netif
,q
);
388 /*-----------------------------------------------------------------------------------*/
390 s8_t
uip_arp_arpquery(struct uip_netif
*netif
,struct uip_ip_addr
*ipaddr
,struct uip_pbuf
*q
)
393 s8_t err
= UIP_ERR_MEM
;
394 struct uip_eth_addr
*srcaddr
= (struct uip_eth_addr
*)netif
->hwaddr
;
396 if(ip_addr_isbroadcast(ipaddr
,netif
) ||
397 ip_addr_ismulticast(ipaddr
) ||
398 ip_addr_isany(ipaddr
)) return UIP_ERR_ARG
;
400 i
= uip_arp_findentry(ipaddr
,ARP_TRY_HARD
);
403 if(arp_table
[i
].state
==ARP_STATE_EMPTY
) arp_table
[i
].state
= ARP_STATE_PENDING
;
404 if(arp_table
[i
].state
==ARP_STATE_PENDING
|| q
==NULL
) err
= uip_arp_arprequest(netif
,ipaddr
);
407 if(arp_table
[i
].state
==ARP_STATE_STABLE
) {
409 struct uip_eth_hdr
*hdr
= q
->payload
;
410 for(k
=0;k
<netif
->hwaddr_len
;k
++) {
411 hdr
->dest
.addr
[k
] = arp_table
[i
].ethaddr
.addr
[k
];
412 hdr
->src
.addr
[k
] = srcaddr
->addr
[k
];
415 hdr
->type
= htons(UIP_ETHTYPE_IP
);
416 err
= netif
->linkoutput(netif
,q
);
417 } else if(arp_table
[i
].state
==ARP_STATE_PENDING
) {
418 UIP_LOG("uip_arp_query: Ethernet destination address unknown, queueing disabled, packet dropped.\n");
424 s8_t
uip_arp_arprequest(struct uip_netif
*netif
,struct uip_ip_addr
*ipaddr
)
427 s8_t err
= UIP_ERR_MEM
;
428 struct uip_arp_hdr
*hdr
;
430 struct uip_eth_addr
*srcaddr
= (struct uip_eth_addr
*)netif
->hwaddr
;
432 p
= uip_pbuf_alloc(UIP_PBUF_LINK
,sizeof(struct uip_arp_hdr
),UIP_PBUF_RAM
);
433 if(p
==NULL
) return err
;
436 hdr
->opcode
= htons(ARP_REQUEST
);
438 for(k
=0;k
<netif
->hwaddr_len
;k
++) {
439 hdr
->shwaddr
.addr
[k
] = srcaddr
->addr
[k
];
440 hdr
->dhwaddr
.addr
[k
] = 0;
443 hdr
->dipaddr
= *(struct uip_ip_addr2
*)((void*)ipaddr
);
444 hdr
->sipaddr
= *(struct uip_ip_addr2
*)((void*)&netif
->ip_addr
);
446 hdr
->hwtype
= htons(ARP_HWTYPE_ETH
);
447 ARPH_HWLEN_SET(hdr
,netif
->hwaddr_len
);
449 hdr
->protocol
= htons(UIP_ETHTYPE_IP
);
450 ARPH_PROTOLEN_SET(hdr
,sizeof(struct uip_ip_addr
));
451 for(k
=0;k
<netif
->hwaddr_len
;k
++) {
452 hdr
->ethhdr
.dest
.addr
[k
] = 0xff;
453 hdr
->ethhdr
.src
.addr
[k
] = srcaddr
->addr
[k
];
455 hdr
->ethhdr
.type
= htons(UIP_ETHTYPE_ARP
);
457 err
= netif
->linkoutput(netif
,p
);