3 |
* Address Resolution Protocol module for IP over Ethernet |
* Address Resolution Protocol module for IP over Ethernet |
4 |
* |
* |
5 |
* $Log$ |
* $Log$ |
6 |
|
* Revision 1.7 2002/11/13 08:56:11 likewise |
7 |
|
* Implemented conditional insertion of ARP entries to update_arp_entry using ARP_INSERT_FLAG. |
8 |
|
* |
9 |
* Revision 1.6 2002/11/11 14:34:29 likewise |
* Revision 1.6 2002/11/11 14:34:29 likewise |
10 |
* Changed static etharp_query() to support queueing packets. This fix missed in last commit. |
* Changed static etharp_query() to support queueing packets. This fix missed in last commit. |
11 |
* |
* |
56 |
* Author: Adam Dunkels <adam@sics.se> |
* Author: Adam Dunkels <adam@sics.se> |
57 |
* |
* |
58 |
*/ |
*/ |
59 |
|
|
60 |
|
/* |
61 |
|
* TODO: |
62 |
|
* |
63 |
|
RFC 3220 4.6 IP Mobility Support for IPv4 January 2002 |
64 |
|
|
65 |
|
- A Gratuitous ARP [45] is an ARP packet sent by a node in order |
66 |
|
to spontaneously cause other nodes to update an entry in their |
67 |
|
ARP cache. A gratuitous ARP MAY use either an ARP Request or |
68 |
|
an ARP Reply packet. In either case, the ARP Sender Protocol |
69 |
|
Address and ARP Target Protocol Address are both set to the IP |
70 |
|
address of the cache entry to be updated, and the ARP Sender |
71 |
|
Hardware Address is set to the link-layer address to which this |
72 |
|
cache entry should be updated. When using an ARP Reply packet, |
73 |
|
the Target Hardware Address is also set to the link-layer |
74 |
|
address to which this cache entry should be updated (this field |
75 |
|
is not used in an ARP Request packet). |
76 |
|
|
77 |
|
In either case, for a gratuitous ARP, the ARP packet MUST be |
78 |
|
transmitted as a local broadcast packet on the local link. As |
79 |
|
specified in [36], any node receiving any ARP packet (Request |
80 |
|
or Reply) MUST update its local ARP cache with the Sender |
81 |
|
Protocol and Hardware Addresses in the ARP packet, if the |
82 |
|
receiving node has an entry for that IP address already in its |
83 |
|
ARP cache. This requirement in the ARP protocol applies even |
84 |
|
for ARP Request packets, and for ARP Reply packets that do not |
85 |
|
match any ARP Request transmitted by the receiving node [36]. |
86 |
|
* |
87 |
|
My suggestion would be to send a ARP request for our newly obtained |
88 |
|
address upon configuration of an Ethernet interface. |
89 |
|
|
90 |
|
*/ |
91 |
|
|
92 |
#include "lwip/opt.h" |
#include "lwip/opt.h" |
93 |
#include "lwip/debug.h" |
#include "lwip/debug.h" |
102 |
# include "lwip/dhcp.h" |
# include "lwip/dhcp.h" |
103 |
#endif |
#endif |
104 |
|
|
105 |
/** the time an ARP entry stays valid after its last update */ |
/** the time an ARP entry stays valid after its last update, (120 * 10) seconds = 20 minutes. */ |
106 |
#define ARP_MAXAGE 120 /* 120 * 10 seconds = 20 minutes. */ |
#define ARP_MAXAGE 120 |
107 |
/** the maximum time waiting for ARP reply to a ARP request */ |
/** the time an ARP entry stays pending after first request, (2 * 10) seconds = 20 seconds. */ |
108 |
#define ARP_MAXPENDING 2 /* 2 * 10 seconds = 20 seconds. */ |
#define ARP_MAXPENDING 2 |
109 |
|
|
110 |
#define HWTYPE_ETHERNET 1 |
#define HWTYPE_ETHERNET 1 |
111 |
|
|
173 |
static struct etharp_entry arp_table[ARP_TABLE_SIZE]; |
static struct etharp_entry arp_table[ARP_TABLE_SIZE]; |
174 |
static u8_t ctime; |
static u8_t ctime; |
175 |
|
|
176 |
static struct pbuf *insert_arp_entry(struct ip_addr *ipaddr, struct eth_addr *ethaddr); |
static struct pbuf *update_arp_entry(struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags); |
177 |
|
#define ARP_INSERT_FLAG 1 |
178 |
|
|
179 |
/** |
/** |
180 |
* Initializes ARP module. |
* Initializes ARP module. |
187 |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
188 |
arp_table[i].state = ETHARP_STATE_EMPTY; |
arp_table[i].state = ETHARP_STATE_EMPTY; |
189 |
} |
} |
190 |
|
/* reset ARP current time */ |
191 |
ctime = 0; |
ctime = 0; |
192 |
} |
} |
193 |
|
|
260 |
} |
} |
261 |
|
|
262 |
/** |
/** |
263 |
* Insert an entry into the ARP cache, or update an existing one. |
* Update (or insert) an entry in the ARP cache. |
264 |
* |
* |
265 |
* @param ipaddr IP address of the inserted ARP entry. |
* @param ipaddr IP address of the inserted ARP entry. |
266 |
* @param ethaddr Ethernet address of the inserted ARP entry. |
* @param ethaddr Ethernet address of the inserted ARP entry. |
267 |
* |
* @param flags Defines behaviour: |
268 |
|
* - ARP_INSERT_FLAG Allows ARP to insert this as a new item. If not specified, |
269 |
|
* only existing ARP entries will be updated. |
270 |
* @return pbuf If non-NULL, a packet that was queued on a pending entry. |
* @return pbuf If non-NULL, a packet that was queued on a pending entry. |
271 |
* You should sent it and must call pbuf_free(). |
* You should sent it and must call pbuf_free(). |
272 |
* |
* |
273 |
* @see pbuf_free() |
* @see pbuf_free() |
274 |
*/ |
*/ |
275 |
static struct pbuf * |
static struct pbuf * |
276 |
insert_arp_entry(struct ip_addr *ipaddr, struct eth_addr *ethaddr) |
update_arp_entry(struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags) |
277 |
{ |
{ |
278 |
u8_t i, k; |
u8_t i, k; |
279 |
struct pbuf *p; |
struct pbuf *p; |
289 |
|
|
290 |
/* check those entries that are already in use. */ |
/* check those entries that are already in use. */ |
291 |
if(arp_table[i].state == ETHARP_STATE_STABLE) { |
if(arp_table[i].state == ETHARP_STATE_STABLE) { |
292 |
DEBUGF(ETHARP_DEBUG, ("insert_arp_entry: updating stable entry %u\n", i)); |
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: updating stable entry %u\n", i)); |
293 |
/* An old entry found, update this and return. */ |
/* An old entry found, update this and return. */ |
294 |
for(k = 0; k < 6; ++k) { |
for(k = 0; k < 6; ++k) { |
295 |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
299 |
} |
} |
300 |
else if(arp_table[i].state == ETHARP_STATE_PENDING) { |
else if(arp_table[i].state == ETHARP_STATE_PENDING) { |
301 |
/* A pending entry was found, so we fill this in and return |
/* A pending entry was found, so we fill this in and return |
302 |
the queued packet (if any). */ |
the queued packet (if any). */ |
303 |
DEBUGF(ETHARP_DEBUG, ("insert_arp_entry: pending entry %u made stable\n", i)); |
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: pending entry %u made stable\n", i)); |
304 |
for(k = 0; k < 6; ++k) { |
for(k = 0; k < 6; ++k) { |
305 |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
306 |
} |
} |
320 |
} |
} |
321 |
|
|
322 |
ethhdr->type = htons(ETHTYPE_IP); |
ethhdr->type = htons(ETHTYPE_IP); |
323 |
DEBUGF(ETHARP_DEBUG, ("insert_arp_entry: returning queued packet %p\n", p)); |
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: returning queued packet %p\n", p)); |
324 |
} |
} |
325 |
/* return queued packet, if any */ |
/* return queued packet, if any */ |
326 |
return p; |
return p; |
327 |
} |
} |
328 |
} |
} |
329 |
} |
} |
330 |
/* no matching ARP entry was found. find an empty or old entry. */ |
/* no matching ARP entry was found */ |
331 |
i = find_arp_entry(); |
/* allowed to insert an entry? */ |
332 |
if(i == ARP_TABLE_SIZE) { |
if (flags & ARP_INSERT_FLAG) |
333 |
DEBUGF(ETHARP_DEBUG, ("insert_arp_entry: no available entry found\n")); |
{ |
334 |
return NULL; |
/* find an empty or old entry. */ |
335 |
} |
i = find_arp_entry(); |
336 |
|
if(i == ARP_TABLE_SIZE) { |
337 |
|
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: no available entry found\n")); |
338 |
|
return NULL; |
339 |
|
} |
340 |
|
|
341 |
if (arp_table[i].state == ETHARP_STATE_STABLE) { |
if (arp_table[i].state == ETHARP_STATE_STABLE) { |
342 |
DEBUGF(ETHARP_DEBUG, ("insert_arp_entry: overwriting old stable entry %u\n", i)); |
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: overwriting old stable entry %u\n", i)); |
343 |
} |
} |
344 |
else { |
else { |
345 |
DEBUGF(ETHARP_DEBUG, ("insert_arp_entry: using empty entry %u\n", i)); |
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: using empty entry %u\n", i)); |
346 |
} |
} |
347 |
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
348 |
for(k = 0; k < 6; ++k) { |
for(k = 0; k < 6; ++k) { |
349 |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
350 |
|
} |
351 |
|
arp_table[i].ctime = ctime; |
352 |
|
arp_table[i].state = ETHARP_STATE_STABLE; |
353 |
|
arp_table[i].p = NULL; |
354 |
} |
} |
|
arp_table[i].ctime = ctime; |
|
|
arp_table[i].state = ETHARP_STATE_STABLE; |
|
|
arp_table[i].p = NULL; |
|
|
|
|
355 |
return NULL; |
return NULL; |
356 |
} |
} |
357 |
|
|
389 |
return NULL; |
return NULL; |
390 |
} |
} |
391 |
DEBUGF(ETHARP_DEBUG, ("etharp_ip_input: updating ETHARP table.\n")); |
DEBUGF(ETHARP_DEBUG, ("etharp_ip_input: updating ETHARP table.\n")); |
392 |
/* update ARP table */ |
/* update ARP table, may insert */ |
393 |
return insert_arp_entry(&(hdr->ip.src), &(hdr->eth.src)); |
return update_arp_entry(&(hdr->ip.src), &(hdr->eth.src), ARP_INSERT_FLAG); |
394 |
} |
} |
395 |
|
|
396 |
|
|
475 |
if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) { |
if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) { |
476 |
struct pbuf *q; |
struct pbuf *q; |
477 |
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP reply for us\n")); |
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP reply for us\n")); |
478 |
/* insert_arp_entry() can return a pbuf that has previously been |
/* update_arp_entry() can return a pbuf that has previously been |
479 |
queued waiting for this IP address to become ARP stable. */ |
queued waiting for this IP address to become ARP stable. */ |
480 |
q = insert_arp_entry(&(hdr->sipaddr), &(hdr->shwaddr)); |
q = update_arp_entry(&(hdr->sipaddr), &(hdr->shwaddr), ARP_INSERT_FLAG); |
481 |
/* free incoming ARP reply pbuf */ |
/* free incoming ARP reply pbuf */ |
482 |
pbuf_free(p); |
pbuf_free(p); |
483 |
p = NULL; |
p = NULL; |