3 |
* Address Resolution Protocol module for IP over Ethernet |
* Address Resolution Protocol module for IP over Ethernet |
4 |
* |
* |
5 |
* $Log$ |
* $Log$ |
6 |
|
* Revision 1.13 2002/11/29 16:02:11 likewise |
7 |
|
* More complete ARP protocol implementation. |
8 |
|
* |
9 |
* Revision 1.12 2002/11/28 09:26:18 likewise |
* Revision 1.12 2002/11/28 09:26:18 likewise |
10 |
* All ARP queueing code is now conditionally compiled-in. |
* All ARP queueing code is now conditionally compiled-in. |
11 |
* |
* |
107 |
/** the time an ARP entry stays pending after first request, (2 * 10) seconds = 20 seconds. */ |
/** the time an ARP entry stays pending after first request, (2 * 10) seconds = 20 seconds. */ |
108 |
#define ARP_MAXPENDING 2 |
#define ARP_MAXPENDING 2 |
109 |
|
|
110 |
/** dis/enable existing ARP entries updates on any ARP traffic */ |
/** |
111 |
#ifndef ETHARP_SNOOP_UPDATES |
* |
112 |
# define ETHARP_SNOOP_UPDATES 0 |
* - If enabled, cache entries are generated for every kind of ARP/IP traffic. |
113 |
|
* This enhances behaviour for sending to a dynamic set of hosts, for example |
114 |
|
* if acting as a gateway. |
115 |
|
* - If disabled, cache entries are generated only for IP destination addresses |
116 |
|
* in use by lwIP or applications. This enhances performance if sending to a small, |
117 |
|
* reasonably static number of hosts. Typically for embedded devices. |
118 |
|
*/ |
119 |
|
#ifndef ETHARP_ALWAYS_INSERT |
120 |
|
# define ETHARP_ALWAYS_INSERT 1 |
121 |
#endif |
#endif |
122 |
|
|
123 |
#define HWTYPE_ETHERNET 1 |
#define HWTYPE_ETHERNET 1 |
152 |
static struct etharp_entry arp_table[ARP_TABLE_SIZE]; |
static struct etharp_entry arp_table[ARP_TABLE_SIZE]; |
153 |
static u8_t ctime; |
static u8_t ctime; |
154 |
|
|
155 |
static struct pbuf *update_arp_entry(struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags); |
static struct pbuf *update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags); |
156 |
#define ARP_INSERT_FLAG 1 |
#define ARP_INSERT_FLAG 1 |
157 |
|
|
158 |
/** |
/** |
182 |
u8_t i; |
u8_t i; |
183 |
|
|
184 |
++ctime; |
++ctime; |
185 |
|
DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); |
186 |
/* remove expired entries from the ARP table */ |
/* remove expired entries from the ARP table */ |
187 |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
188 |
if((arp_table[i].state == ETHARP_STATE_STABLE) && |
if((arp_table[i].state == ETHARP_STATE_STABLE) && |
189 |
(ctime - arp_table[i].ctime >= ARP_MAXAGE)) { |
(ctime - arp_table[i].ctime >= ARP_MAXAGE)) { |
190 |
DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %u.\n", i)); |
DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %u.\n", i)); |
191 |
arp_table[i].state = ETHARP_STATE_EMPTY; |
arp_table[i].state = ETHARP_STATE_EMPTY; |
192 |
|
#if ARP_QUEUEING |
193 |
|
/* remove any queued packet */ |
194 |
|
pbuf_free(arp_table[i].p); |
195 |
|
arp_table[i].p = NULL; |
196 |
|
#endif |
197 |
} else if((arp_table[i].state == ETHARP_STATE_PENDING) && |
} else if((arp_table[i].state == ETHARP_STATE_PENDING) && |
198 |
(ctime - arp_table[i].ctime >= ARP_MAXPENDING)) { |
(ctime - arp_table[i].ctime >= ARP_MAXPENDING)) { |
199 |
DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u - dequeueing %p.\n", i, arp_table[i].p)); |
DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u - dequeueing %p.\n", i, arp_table[i].p)); |
247 |
} |
} |
248 |
|
|
249 |
/** |
/** |
250 |
* Update (or insert) an entry in the ARP cache. |
* Update (or insert) a IP/MAC address pair in the ARP cache. |
251 |
* |
* |
252 |
* @param ipaddr IP address of the inserted ARP entry. |
* @param ipaddr IP address of the inserted ARP entry. |
253 |
* @param ethaddr Ethernet address of the inserted ARP entry. |
* @param ethaddr Ethernet address of the inserted ARP entry. |
254 |
* @param flags Defines behaviour: |
* @param flags Defines behaviour: |
255 |
* - ARP_INSERT_FLAG Allows ARP to insert this as a new item. If not specified, |
* - ARP_INSERT_FLAG Allows ARP to insert this as a new item. If not specified, |
256 |
* only existing ARP entries will be updated. |
* only existing ARP entries will be updated. |
257 |
|
* |
258 |
* @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. |
259 |
* You should sent it and must call pbuf_free(). |
* You should sent it and must call pbuf_free() afterwards. |
260 |
* |
* |
261 |
* @see pbuf_free() |
* @see pbuf_free() |
262 |
*/ |
*/ |
263 |
static struct pbuf * |
static struct pbuf * |
264 |
update_arp_entry(struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags) |
update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags) |
265 |
{ |
{ |
266 |
u8_t i, k; |
u8_t i, k; |
267 |
struct eth_hdr *ethhdr; |
struct eth_hdr *ethhdr; |
268 |
#if ARP_QUEUEING |
/* do not update for 0.0.0.0 addresses */ |
269 |
struct pbuf *p; |
if (ipaddr->addr == 0) return NULL; |
|
#endif |
|
|
|
|
270 |
/* Walk through the ARP mapping table and try to find an entry to |
/* Walk through the ARP mapping table and try to find an entry to |
271 |
update. If none is found, the IP -> MAC address mapping is |
update. If none is found, the IP -> MAC address mapping is |
272 |
inserted in the ARP table. */ |
inserted in the ARP table. */ |
274 |
/* Check if the source IP address of the incoming packet matches |
/* Check if the source IP address of the incoming packet matches |
275 |
the IP address in this ARP table entry. */ |
the IP address in this ARP table entry. */ |
276 |
if(ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
if(ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
277 |
|
/* pending entry? */ |
278 |
/* check those entries that are already in use. */ |
if(arp_table[i].state == ETHARP_STATE_PENDING) { |
279 |
|
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: pending entry %u goes stable\n", i)); |
280 |
|
/* A pending entry was found, mark it stable */ |
281 |
|
arp_table[i].state = ETHARP_STATE_STABLE; |
282 |
|
/* fall-through to next if */ |
283 |
|
} |
284 |
|
/* stable entry? (possible just marked to become stable) */ |
285 |
if(arp_table[i].state == ETHARP_STATE_STABLE) { |
if(arp_table[i].state == ETHARP_STATE_STABLE) { |
286 |
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: updating stable entry %u\n", i)); |
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: updating stable entry %u\n", i)); |
287 |
/* An old entry found, update this and return. */ |
/* An old entry found, update this and return. */ |
288 |
for(k = 0; k < 6; ++k) { |
for(k = 0; k < 6; ++k) { |
289 |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
290 |
} |
} |
291 |
|
/* time stamp */ |
292 |
arp_table[i].ctime = ctime; |
arp_table[i].ctime = ctime; |
|
return NULL; |
|
|
} |
|
|
else if(arp_table[i].state == ETHARP_STATE_PENDING) { |
|
|
/* A pending entry was found, so we fill this in and return |
|
|
the queued packet (if any). */ |
|
|
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: pending entry %u made stable\n", i)); |
|
|
for(k = 0; k < 6; ++k) { |
|
|
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
|
|
} |
|
|
arp_table[i].ctime = ctime; |
|
|
arp_table[i].state = ETHARP_STATE_STABLE; |
|
293 |
#if ARP_QUEUEING |
#if ARP_QUEUEING |
|
p = arp_table[i].p; |
|
294 |
// queued packet present? */ |
// queued packet present? */ |
295 |
if(p != NULL) { |
if(arp_table[i].p != NULL) { |
|
/* remove queued packet from ARP entry (must be freed by the caller) */ |
|
|
arp_table[i].p = NULL; |
|
296 |
|
|
297 |
/* fill-in Ethernet header */ |
/* fill-in Ethernet header */ |
298 |
ethhdr = p->payload; |
ethhdr = arp_table[i].p->payload; |
|
|
|
299 |
for(k = 0; k < 6; ++k) { |
for(k = 0; k < 6; ++k) { |
300 |
ethhdr->dest.addr[k] = ethaddr->addr[k]; |
ethhdr->dest.addr[k] = ethaddr->addr[k]; |
301 |
} |
} |
|
|
|
302 |
ethhdr->type = htons(ETHTYPE_IP); |
ethhdr->type = htons(ETHTYPE_IP); |
303 |
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: returning queued packet %p\n", p)); |
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: sending queued IP packet.\n")); |
304 |
|
/* send the queued IP packet */ |
305 |
|
netif->linkoutput(netif, arp_table[i].p); |
306 |
|
/* free the queued IP packet */ |
307 |
|
pbuf_free(arp_table[i].p); |
308 |
|
/* remove queued packet from ARP entry (must be freed by the caller) */ |
309 |
|
arp_table[i].p = NULL; |
310 |
} |
} |
|
/* return queued packet, if any */ |
|
|
return p; |
|
|
#else |
|
|
/* ARP queueing disabled */ |
|
|
return NULL; |
|
311 |
#endif |
#endif |
312 |
|
return NULL; |
313 |
} |
} |
314 |
} |
} /* if */ |
315 |
} |
} /* for */ |
316 |
|
|
317 |
/* no matching ARP entry was found */ |
/* no matching ARP entry was found */ |
318 |
|
ASSERT("update_arp_entry: i == ARP_TABLE_SIZE", i == ARP_TABLE_SIZE); |
319 |
|
|
320 |
/* allowed to insert an entry? */ |
/* allowed to insert an entry? */ |
321 |
if (flags & ARP_INSERT_FLAG) |
if ((ETHARP_ALWAYS_INSERT) || (flags & ARP_INSERT_FLAG)) |
322 |
{ |
{ |
323 |
/* find an empty or old entry. */ |
/* find an empty or old entry. */ |
324 |
i = find_arp_entry(); |
i = find_arp_entry(); |
326 |
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: no available entry found\n")); |
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: no available entry found\n")); |
327 |
return NULL; |
return NULL; |
328 |
} |
} |
329 |
|
/* see if find_arp_entry() gave us an old stable, or empty entry to re-use */ |
330 |
if (arp_table[i].state == ETHARP_STATE_STABLE) { |
if (arp_table[i].state == ETHARP_STATE_STABLE) { |
331 |
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: overwriting old stable entry %u\n", i)); |
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: overwriting old stable entry %u\n", i)); |
332 |
|
/* stable entries should have no queued packets (TODO: allow later) */ |
333 |
|
ASSERT("update_arp_entry: arp_table[i].p != NULL", arp_table[i].p != NULL); |
334 |
|
} else { |
335 |
|
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: filling empty entry %u with state %u\n", i, arp_table[i].stat)); |
336 |
|
ASSERT("update_arp_entry: arp_table[i].state == ETHARP_STATE_EMPTY", arp_table[i].state == ETHARP_STATE_EMPTY); |
337 |
} |
} |
338 |
else { |
/* set IP address */ |
|
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: using empty entry %u\n", i)); |
|
|
} |
|
339 |
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
340 |
|
/* set Ethernet hardware address */ |
341 |
for(k = 0; k < 6; ++k) { |
for(k = 0; k < 6; ++k) { |
342 |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
343 |
} |
} |
344 |
|
/* time-stamp */ |
345 |
arp_table[i].ctime = ctime; |
arp_table[i].ctime = ctime; |
346 |
|
/* mark as stable */ |
347 |
arp_table[i].state = ETHARP_STATE_STABLE; |
arp_table[i].state = ETHARP_STATE_STABLE; |
348 |
|
/* no queued packet */ |
349 |
arp_table[i].p = NULL; |
arp_table[i].p = NULL; |
350 |
} |
} |
351 |
|
else |
352 |
|
{ |
353 |
|
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: no matching stable entry to update\n", i)); |
354 |
|
} |
355 |
return NULL; |
return NULL; |
356 |
} |
} |
357 |
|
|
358 |
/** |
/** |
359 |
* Updates the ARP table and may return any queued packet to be sent. |
* Updates the ARP table using the given packet. |
360 |
* |
* |
361 |
* Should be called for all incoming packets of IP kind. It updates |
* Uses the incoming IP packet's source address to update the |
362 |
* the ARP table for the local network. The function does not alter |
* ARP cache for the local network. The function does not alter |
363 |
* the packet in any way and does not free it. After this function has |
* or free the packet. This function must be called before the |
364 |
* been called, the packet p must be given to the IP layer. |
* packet p is passed to the IP layer. |
365 |
* |
* |
366 |
* @param netif The lwIP network interface on which the IP packet pbuf arrived. |
* @param netif The lwIP network interface on which the IP packet pbuf arrived. |
|
* |
|
367 |
* @param pbuf The IP packet that arrived on netif. |
* @param pbuf The IP packet that arrived on netif. |
368 |
* |
* |
369 |
* @return If non-NULL, a pbuf that was queued on an ARP entry. The device |
* @return NULL |
|
* driver must transmit this packet onto the network, and call pbuf_free() |
|
|
* for the pbuf. |
|
370 |
* |
* |
371 |
* @see pbuf_free() |
* @see pbuf_free() |
372 |
*/ |
*/ |
375 |
{ |
{ |
376 |
struct ethip_hdr *hdr; |
struct ethip_hdr *hdr; |
377 |
|
|
378 |
hdr = p->payload; |
/* Only insert an entry if the source IP address of the |
|
|
|
|
/* Only insert/update an entry if the source IP address of the |
|
379 |
incoming IP packet comes from a host on the local network. */ |
incoming IP packet comes from a host on the local network. */ |
380 |
|
hdr = p->payload; |
381 |
/* source is on local network? */ |
/* source is on local network? */ |
382 |
if(!ip_addr_maskcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) { |
if(!ip_addr_maskcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) { |
383 |
/* do nothing */ |
/* do nothing */ |
384 |
return NULL; |
return NULL; |
385 |
} |
} |
386 |
|
|
387 |
DEBUGF(ETHARP_DEBUG, ("etharp_ip_input: updating ETHARP table.\n")); |
DEBUGF(ETHARP_DEBUG, ("etharp_ip_input: updating ETHARP table.\n")); |
388 |
/* update ARP table, may insert */ |
/* update ARP table, ask to insert entry */ |
389 |
return update_arp_entry(&(hdr->ip.src), &(hdr->eth.src), ARP_INSERT_FLAG); |
update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), ARP_INSERT_FLAG); |
390 |
|
return NULL; |
391 |
} |
} |
392 |
|
|
393 |
|
|
394 |
/** |
/** |
395 |
* Updates the ARP table and returns an ARP reply or a queued IP packet. |
* Responds to ARP requests, updates ARP entries and sends queued IP packets. |
396 |
* |
* |
397 |
* Should be called for incoming ARP packets. The pbuf in the argument |
* Should be called for incoming ARP packets. The pbuf in the argument |
398 |
* is freed by this function. The returned pbuf is to be sent and then |
* is freed by this function. |
|
* freed by the caller. |
|
399 |
* |
* |
400 |
* @param netif The lwIP network interface on which the ARP packet pbuf arrived. |
* @param netif The lwIP network interface on which the ARP packet pbuf arrived. |
401 |
* @param pbuf The ARP packet that arrived on netif. Is freed by this function. |
* @param pbuf The ARP packet that arrived on netif. Is freed by this function. |
402 |
* @param ethaddr Ethernet address of netif. |
* @param ethaddr Ethernet address of netif. |
403 |
* |
* |
404 |
* @return pbuf to be sent and freed by the caller. |
* @return NULL |
405 |
* |
* |
406 |
* @see pbuf_free() |
* @see pbuf_free() |
407 |
*/ |
*/ |
409 |
etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) |
etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) |
410 |
{ |
{ |
411 |
struct etharp_hdr *hdr; |
struct etharp_hdr *hdr; |
|
struct pbuf *q; |
|
412 |
u8_t i; |
u8_t i; |
413 |
|
|
414 |
/* drop short ARP packets */ |
/* drop short ARP packets */ |
415 |
if(p->tot_len < sizeof(struct etharp_hdr)) { |
if(p->tot_len < sizeof(struct etharp_hdr)) { |
416 |
DEBUGF(ETHARP_DEBUG, ("etharp_etharp_input: packet too short (%d/%d)\n", p->tot_len, sizeof(struct etharp_hdr))); |
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: packet too short (%d/%d)\n", p->tot_len, sizeof(struct etharp_hdr))); |
417 |
pbuf_free(p); |
pbuf_free(p); |
418 |
return NULL; |
return NULL; |
419 |
} |
} |
424 |
/* ARP request? */ |
/* ARP request? */ |
425 |
case ARP_REQUEST: |
case ARP_REQUEST: |
426 |
/* ARP request. If it asked for our address, we send out a |
/* ARP request. If it asked for our address, we send out a |
427 |
reply. */ |
reply. In any case, we time-stamp any existing ARP entry, |
428 |
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP request\n")); |
and possiby send out an IP packet that was queued on it. */ |
429 |
|
|
430 |
|
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: incoming ARP request\n")); |
431 |
|
/* we are not configured? */ |
432 |
|
if(netif->ip_addr.addr == 0) { |
433 |
|
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n")); |
434 |
|
pbuf_free(p); |
435 |
|
return NULL; |
436 |
|
} |
437 |
|
/* update the ARP cache */ |
438 |
|
update_arp_entry(netif, &(hdr->sipaddr), &(hdr->shwaddr), 0); |
439 |
/* ARP request for our address? */ |
/* ARP request for our address? */ |
440 |
if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) { |
if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) { |
441 |
|
|
442 |
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP request for our address\n")); |
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: replying to ARP request for our IP address\n")); |
443 |
/* re-use pbuf to send ARP reply */ |
/* re-use pbuf to send ARP reply */ |
444 |
hdr->opcode = htons(ARP_REPLY); |
hdr->opcode = htons(ARP_REPLY); |
445 |
|
|
461 |
|
|
462 |
hdr->ethhdr.type = htons(ETHTYPE_ARP); |
hdr->ethhdr.type = htons(ETHTYPE_ARP); |
463 |
/* return ARP reply */ |
/* return ARP reply */ |
464 |
return p; |
netif->linkoutput(netif, p); |
465 |
|
} else { |
466 |
|
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP request, but not for us.\n")); |
467 |
} |
} |
|
#if ETHARP_SNOOP_UPDATES |
|
|
/* request, NOT for our address */ |
|
|
else { |
|
|
/* update_arp_entry() can return a pbuf that has previously been |
|
|
queued waiting for this IP address to become ARP stable. */ |
|
|
q = update_arp_entry(&(hdr->sipaddr), &(hdr->shwaddr), 0); |
|
|
pbuf_free(p); |
|
|
p = NULL; |
|
|
return q; |
|
|
} |
|
|
#endif |
|
468 |
break; |
break; |
469 |
case ARP_REPLY: |
case ARP_REPLY: |
470 |
/* ARP reply. We insert or update the ARP table. */ |
/* ARP reply. We insert or update the ARP table. */ |
473 |
/* DHCP needs to know about ARP replies */ |
/* DHCP needs to know about ARP replies */ |
474 |
dhcp_arp_reply(&hdr->sipaddr); |
dhcp_arp_reply(&hdr->sipaddr); |
475 |
#endif |
#endif |
476 |
/* for our address? */ |
/* ARP reply directed to us? */ |
477 |
if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) { |
if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) { |
478 |
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP reply for us\n")); |
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP reply for us\n")); |
479 |
/* update_arp_entry() can return a pbuf that has previously been |
/* update_the ARP cache, ask to insert */ |
480 |
queued waiting for this IP address to become ARP stable. */ |
update_arp_entry(netif, &(hdr->sipaddr), &(hdr->shwaddr), ARP_INSERT_FLAG); |
481 |
q = update_arp_entry(&(hdr->sipaddr), &(hdr->shwaddr), ARP_INSERT_FLAG); |
/* ARP reply not directed to us */ |
482 |
/* free incoming ARP reply pbuf */ |
} else { |
483 |
pbuf_free(p); |
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP reply, but NOT for us\n")); |
484 |
p = NULL; |
/* update the destination address pair */ |
485 |
return q; |
update_arp_entry(netif, &(hdr->sipaddr), &(hdr->shwaddr), 0); |
486 |
} |
/* update the destination address pair */ |
487 |
#if ETHARP_SNOOP_UPDATES |
update_arp_entry(netif, &(hdr->dipaddr), &(hdr->dhwaddr), 0); |
|
/* ARP reply, NOT for our address */ |
|
|
else { |
|
|
/* update_arp_entry() can return a pbuf that has previously been |
|
|
queued waiting for this IP address to become ARP stable. */ |
|
|
q = update_arp_entry(&(hdr->sipaddr), &(hdr->shwaddr), 0); |
|
|
pbuf_free(p); |
|
|
p = NULL; |
|
|
return q; |
|
488 |
} |
} |
|
#endif |
|
489 |
break; |
break; |
490 |
default: |
default: |
491 |
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: unknown type %d\n", htons(hdr->opcode))); |
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: unknown type %d\n", htons(hdr->opcode))); |
492 |
break; |
break; |
493 |
} |
} |
494 |
|
/* free ARP packet */ |
495 |
pbuf_free(p); |
pbuf_free(p); |
496 |
|
p = NULL; |
497 |
|
/* nothing to send, we did it! */ |
498 |
return NULL; |
return NULL; |
499 |
} |
} |
500 |
|
|
527 |
{ |
{ |
528 |
struct eth_addr *dest, *srcaddr, mcastaddr; |
struct eth_addr *dest, *srcaddr, mcastaddr; |
529 |
struct eth_hdr *ethhdr; |
struct eth_hdr *ethhdr; |
|
struct pbuf *p; |
|
530 |
u8_t i; |
u8_t i; |
531 |
|
|
532 |
/* Make room for Ethernet header. */ |
/* Make room for Ethernet header. */ |
571 |
/* destination IP address is an IP unicast address */ |
/* destination IP address is an IP unicast address */ |
572 |
else { |
else { |
573 |
/* destination IP network address not on local network? */ |
/* destination IP network address not on local network? */ |
574 |
|
/* this occurs if the packet is routed to the default gateway on this interface */ |
575 |
if(!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { |
if(!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { |
576 |
/* gateway available? */ |
/* gateway available? */ |
577 |
if (netif->gw.addr != 0) |
if (netif->gw.addr != 0) |
578 |
{ |
{ |
579 |
/* use the default gateway IP address */ |
/* use the gateway IP address */ |
580 |
ipaddr = &(netif->gw); |
ipaddr = &(netif->gw); |
581 |
} |
} |
582 |
|
/* no gateway available? */ |
583 |
else |
else |
584 |
{ |
{ |
585 |
/* IP destination address outside local network, but no gateway available */ |
/* IP destination address outside local network, but no gateway available */ |
598 |
} |
} |
599 |
/* could not find the destination Ethernet address in ARP cache? */ |
/* could not find the destination Ethernet address in ARP cache? */ |
600 |
if (dest == NULL) { |
if (dest == NULL) { |
601 |
/* query for the IP address using ARP request */ |
/* ARP query for the IP address, submit this IP packet for queueing */ |
602 |
p = etharp_query(netif, ipaddr, q); |
etharp_query(netif, ipaddr, q); |
603 |
/* return the ARP request */ |
/* return nothing */ |
604 |
return p; |
return NULL; |
605 |
} |
} |
606 |
/* destination Ethernet address resolved from ARP cache*/ |
/* destination Ethernet address resolved from ARP cache */ |
607 |
else |
else |
608 |
{ |
{ |
609 |
/* fallthrough */ |
/* fallthrough */ |
614 |
if (dest != NULL) { |
if (dest != NULL) { |
615 |
/* A valid IP->MAC address mapping was found, so we construct the |
/* A valid IP->MAC address mapping was found, so we construct the |
616 |
Ethernet header for the outgoing packet. */ |
Ethernet header for the outgoing packet. */ |
|
|
|
617 |
ethhdr = q->payload; |
ethhdr = q->payload; |
618 |
|
|
619 |
for(i = 0; i < 6; i++) { |
for(i = 0; i < 6; i++) { |
646 |
etharp_output_sent(struct pbuf *p) |
etharp_output_sent(struct pbuf *p) |
647 |
{ |
{ |
648 |
struct etharp_hdr *hdr; |
struct etharp_hdr *hdr; |
649 |
hdr=p->payload; |
hdr = p->payload; |
650 |
if (hdr->opcode == htons(ARP_REQUEST)) { |
if (hdr->opcode == htons(ARP_REQUEST)) { |
651 |
pbuf_free(p); |
pbuf_free(p); |
652 |
p = NULL; |
p = NULL; |
667 |
* @param q If non-NULL, a pbuf that must be queued on the |
* @param q If non-NULL, a pbuf that must be queued on the |
668 |
* ARP entry for the ipaddr IP address. |
* ARP entry for the ipaddr IP address. |
669 |
* |
* |
670 |
* @return pbuf containing the ARP request, NULL on failure. |
* @return NULL. |
671 |
* |
* |
672 |
* @note Might be used in the future by manual IP configuration |
* @note Might be used in the future by manual IP configuration |
673 |
* as well. |
* as well. |
674 |
* |
* |
675 |
|
* TODO: enqueue q here if possible (BEWARE: possible other packet already |
676 |
|
* queued. |
677 |
|
* TODO: The host requirements RFC states that ARP should save at least one |
678 |
|
* packet, and this should be the _latest_ packet. |
679 |
|
* TODO: use the ctime field to see how long ago an ARP request was sent, |
680 |
|
* possibly retry. |
681 |
*/ |
*/ |
682 |
struct pbuf *etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) |
struct pbuf *etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) |
683 |
{ |
{ |
689 |
srcaddr = (struct eth_addr *)netif->hwaddr; |
srcaddr = (struct eth_addr *)netif->hwaddr; |
690 |
/* bail out if this IP address is pending */ |
/* bail out if this IP address is pending */ |
691 |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
692 |
if(arp_table[i].state == ETHARP_STATE_PENDING && |
if(ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
693 |
ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
if (arp_table[i].state == ETHARP_STATE_PENDING) { |
694 |
DEBUGF(ETHARP_DEBUG, ("etharp_query: request already pending\n")); |
DEBUGF(ETHARP_DEBUG, ("etharp_query: requested IP already pending\n")); |
695 |
/* TODO: enqueue q here if possible (BEWARE: possible other packet already |
/* break out of for-loop */ |
696 |
queued. */ |
break; |
697 |
/* TODO: The host requirements RFC states that ARP should save at least one |
} |
698 |
packet, and this should be the _latest_ packet. */ |
else if (arp_table[i].state == ETHARP_STATE_STABLE) { |
699 |
/* TODO: use the ctime field to see how long ago an ARP request was sent, |
DEBUGF(ETHARP_DEBUG, ("etharp_query: requested IP already stable\n")); |
700 |
possibly retry. */ |
return NULL; |
701 |
return NULL; |
} |
702 |
} |
} |
703 |
} |
} |
704 |
i = find_arp_entry(); |
/* queried address not yet pending in ARP table? */ |
705 |
/* bail out if no ARP entries are available */ |
if (i == ARP_TABLE_SIZE) |
|
if(i == ARP_TABLE_SIZE) |
|
706 |
{ |
{ |
707 |
DEBUGF(ETHARP_DEBUG, ("etharp_query: no more ARP table entries available.\n")); |
DEBUGF(ETHARP_DEBUG, ("etharp_query: IP address non-pending\n")); |
708 |
return NULL; |
/* find an available entry */ |
709 |
|
i = find_arp_entry(); |
710 |
|
/* bail out if no ARP entries are available */ |
711 |
|
if(i == ARP_TABLE_SIZE) |
712 |
|
{ |
713 |
|
DEBUGF(ETHARP_DEBUG, ("etharp_query: no more ARP table entries available.\n")); |
714 |
|
return NULL; |
715 |
|
} |
716 |
|
DEBUGF(ETHARP_DEBUG, ("etharp_query: created ARP table entry.\n")); |
717 |
|
/* i is available, create ARP entry */ |
718 |
|
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
719 |
|
arp_table[i].ctime = ctime; |
720 |
|
arp_table[i].state = ETHARP_STATE_PENDING; |
721 |
|
arp_table[i].p = NULL; |
722 |
} |
} |
|
|
|
|
/* i is an available ARP table entry */ |
|
723 |
/* allocate a pbuf for the outgoing ARP request packet */ |
/* allocate a pbuf for the outgoing ARP request packet */ |
724 |
p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM); |
p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM); |
725 |
/* could allocate pbuf? */ |
/* could allocate pbuf? */ |
726 |
if (p != NULL) { |
if (p != NULL) { |
727 |
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
DEBUGF(ETHARP_DEBUG, ("etharp_query: sending ARP request.\n")); |
728 |
arp_table[i].ctime = ctime; |
hdr = p->payload; |
729 |
arp_table[i].state = ETHARP_STATE_PENDING; |
hdr->opcode = htons(ARP_REQUEST); |
730 |
#if ARP_QUEUEING |
for(i = 0; i < 6; ++i) |
731 |
/* any pbuf to queue? */ |
{ |
732 |
if (q != NULL) { |
hdr->dhwaddr.addr[i] = 0x00; |
733 |
/* copy PBUF_REF referenced payloads to PBUF_RAM */ |
hdr->shwaddr.addr[i] = srcaddr->addr[i]; |
|
q = pbuf_unref(q); |
|
|
/* pbufs are queued, increase the reference count */ |
|
|
pbuf_ref_chain(q); |
|
734 |
} |
} |
735 |
/* remember pbuf to queue, if any */ |
ip_addr_set(&(hdr->dipaddr), ipaddr); |
736 |
arp_table[i].p = q; |
ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr)); |
|
#else |
|
|
arp_table[i].p = NULL; |
|
|
#endif |
|
|
} |
|
|
/* could not allocate pbuf for ARP request */ |
|
|
else { |
|
|
return NULL; |
|
|
} |
|
|
/* p is the allocated pbuf */ |
|
|
|
|
|
hdr = p->payload; |
|
|
hdr->opcode = htons(ARP_REQUEST); |
|
|
|
|
|
for(i = 0; i < 6; ++i) |
|
|
{ |
|
|
hdr->dhwaddr.addr[i] = 0x00; |
|
|
hdr->shwaddr.addr[i] = srcaddr->addr[i]; |
|
|
} |
|
|
|
|
|
ip_addr_set(&(hdr->dipaddr), ipaddr); |
|
|
ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr)); |
|
|
|
|
|
hdr->hwtype = htons(HWTYPE_ETHERNET); |
|
|
ARPH_HWLEN_SET(hdr, 6); |
|
737 |
|
|
738 |
hdr->proto = htons(ETHTYPE_IP); |
hdr->hwtype = htons(HWTYPE_ETHERNET); |
739 |
ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr)); |
ARPH_HWLEN_SET(hdr, 6); |
740 |
|
|
741 |
for(i = 0; i < 6; ++i) |
hdr->proto = htons(ETHTYPE_IP); |
742 |
{ |
ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr)); |
743 |
hdr->ethhdr.dest.addr[i] = 0xff; |
for(i = 0; i < 6; ++i) |
744 |
hdr->ethhdr.src.addr[i] = srcaddr->addr[i]; |
{ |
745 |
|
hdr->ethhdr.dest.addr[i] = 0xff; |
746 |
|
hdr->ethhdr.src.addr[i] = srcaddr->addr[i]; |
747 |
|
} |
748 |
|
hdr->ethhdr.type = htons(ETHTYPE_ARP); |
749 |
|
/* send ARP query */ |
750 |
|
netif->linkoutput(netif, p); |
751 |
|
/* free ARP query packet */ |
752 |
|
pbuf_free(p); |
753 |
|
p = NULL; |
754 |
|
} else { |
755 |
|
DEBUGF(ETHARP_DEBUG, ("etharp_query: could not allocate pbuf for ARP request.\n")); |
756 |
} |
} |
757 |
|
#if ARP_QUEUEING |
758 |
hdr->ethhdr.type = htons(ETHTYPE_ARP); |
/* any pbuf to queue and queue is empty? */ |
759 |
return p; |
if ((q != NULL) && (arp_table[i].p == NULL)) { |
760 |
|
/* copy PBUF_REF referenced payloads to PBUF_RAM */ |
761 |
|
q = pbuf_unref(q); |
762 |
|
/* pbufs are queued, increase the reference count */ |
763 |
|
pbuf_ref_chain(q); |
764 |
|
/* remember pbuf to queue, if any */ |
765 |
|
arp_table[i].p = q; |
766 |
|
DEBUGF(ETHARP_DEBUG, ("etharp_query: queued packet on ARP entry.\n")); |
767 |
|
} |
768 |
|
#endif |
769 |
|
return NULL; |
770 |
} |
} |