3 |
* Address Resolution Protocol module for IP over Ethernet |
* Address Resolution Protocol module for IP over Ethernet |
4 |
* |
* |
5 |
* $Log$ |
* $Log$ |
6 |
|
* Revision 1.6 2002/11/11 14:34:29 likewise |
7 |
|
* Changed static etharp_query() to support queueing packets. This fix missed in last commit. |
8 |
|
* |
9 |
* Revision 1.5 2002/11/08 22:14:24 likewise |
* Revision 1.5 2002/11/08 22:14:24 likewise |
10 |
* Fixed numerous bugs. Re-used etharp_query() in etharp_output(). Added comments and JavaDoc documentation. |
* Fixed numerous bugs. Re-used etharp_query() in etharp_output(). Added comments and JavaDoc documentation. |
11 |
* |
* |
60 |
#include "netif/etharp.h" |
#include "netif/etharp.h" |
61 |
#include "lwip/ip.h" |
#include "lwip/ip.h" |
62 |
#include "lwip/stats.h" |
#include "lwip/stats.h" |
63 |
|
#include "lwipopts.h" |
64 |
|
|
65 |
/* ARP needs to inform DHCP of any ARP replies? */ |
/* ARP needs to inform DHCP of any ARP replies? */ |
66 |
#if (LWIP_DHCP && DHPC_DOES_ARP_CHECK) |
#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) |
67 |
# include "lwip/dhcp.h" |
# include "lwip/dhcp.h" |
68 |
#endif |
#endif |
69 |
|
|
138 |
static struct etharp_entry arp_table[ARP_TABLE_SIZE]; |
static struct etharp_entry arp_table[ARP_TABLE_SIZE]; |
139 |
static u8_t ctime; |
static u8_t ctime; |
140 |
|
|
141 |
|
static struct pbuf *insert_arp_entry(struct ip_addr *ipaddr, struct eth_addr *ethaddr); |
142 |
|
|
143 |
/** |
/** |
144 |
* Initializes ARP module. |
* Initializes ARP module. |
145 |
*/ |
*/ |
151 |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
152 |
arp_table[i].state = ETHARP_STATE_EMPTY; |
arp_table[i].state = ETHARP_STATE_EMPTY; |
153 |
} |
} |
154 |
|
ctime = 0; |
155 |
} |
} |
156 |
|
|
157 |
/** |
/** |
168 |
++ctime; |
++ctime; |
169 |
/* remove expired entries from the ARP table */ |
/* remove expired entries from the ARP table */ |
170 |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
171 |
if(arp_table[i].state == ETHARP_STATE_STABLE && |
if((arp_table[i].state == ETHARP_STATE_STABLE) && |
172 |
ctime - arp_table[i].ctime >= ARP_MAXAGE) { |
(ctime - arp_table[i].ctime >= ARP_MAXAGE)) { |
173 |
DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %d.\n", i)); |
DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %u.\n", i)); |
174 |
arp_table[i].state = ETHARP_STATE_EMPTY; |
arp_table[i].state = ETHARP_STATE_EMPTY; |
175 |
} else if(arp_table[i].state == ETHARP_STATE_PENDING && |
} else if((arp_table[i].state == ETHARP_STATE_PENDING) && |
176 |
ctime - arp_table[i].ctime >= ARP_MAXPENDING) { |
(ctime - arp_table[i].ctime >= ARP_MAXPENDING)) { |
177 |
DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %d - 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)); |
178 |
arp_table[i].state = ETHARP_STATE_EMPTY; |
arp_table[i].state = ETHARP_STATE_EMPTY; |
179 |
|
/* remove any queued packet */ |
180 |
pbuf_free(arp_table[i].p); |
pbuf_free(arp_table[i].p); |
181 |
arp_table[i].p = NULL; |
arp_table[i].p = NULL; |
182 |
} |
} |
198 |
/* Try to find an unused entry in the ARP table. */ |
/* Try to find an unused entry in the ARP table. */ |
199 |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
200 |
if(arp_table[i].state == ETHARP_STATE_EMPTY) { |
if(arp_table[i].state == ETHARP_STATE_EMPTY) { |
201 |
|
DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found empty entry %u\n", i)); |
202 |
break; |
break; |
203 |
} |
} |
204 |
} |
} |
209 |
maxtime = 0; |
maxtime = 0; |
210 |
j = ARP_TABLE_SIZE; |
j = ARP_TABLE_SIZE; |
211 |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
212 |
if(arp_table[i].state == ETHARP_STATE_STABLE && |
/* remember entry with oldest stable entry in j*/ |
213 |
ctime - arp_table[i].ctime > maxtime) { |
if((arp_table[i].state == ETHARP_STATE_STABLE) && |
214 |
maxtime = ctime - arp_table[i].ctime; |
(ctime - arp_table[i].ctime > maxtime)) { |
215 |
j = i; |
maxtime = ctime - arp_table[i].ctime; |
216 |
|
j = i; |
217 |
} |
} |
218 |
} |
} |
219 |
|
DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found oldest stable entry %u\n", j)); |
220 |
i = j; |
i = j; |
221 |
} |
} |
222 |
return i; |
return i; |
223 |
} |
} |
224 |
|
|
225 |
|
/** |
226 |
|
* Insert an entry into the ARP cache, or update an existing one. |
227 |
|
* |
228 |
|
* @param ipaddr IP address of the inserted ARP entry. |
229 |
|
* @param ethaddr Ethernet address of the inserted ARP entry. |
230 |
|
* |
231 |
|
* @return pbuf If non-NULL, a packet that was queued on a pending entry. |
232 |
|
* You should sent it and must call pbuf_free(). |
233 |
|
* |
234 |
|
* @see pbuf_free() |
235 |
|
*/ |
236 |
static struct pbuf * |
static struct pbuf * |
237 |
update_arp_entry(struct ip_addr *ipaddr, struct eth_addr *ethaddr) |
insert_arp_entry(struct ip_addr *ipaddr, struct eth_addr *ethaddr) |
238 |
{ |
{ |
239 |
u8_t i, k; |
u8_t i, k; |
240 |
struct pbuf *p; |
struct pbuf *p; |
241 |
struct eth_hdr *ethhdr; |
struct eth_hdr *ethhdr; |
242 |
|
|
243 |
/* 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 |
244 |
update. If none is found, the IP -> MAC address mapping is |
update. If none is found, the IP -> MAC address mapping is |
245 |
inserted in the ARP table. */ |
inserted in the ARP table. */ |
246 |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
247 |
/* Check if the source IP address of the incoming packet matches |
/* Check if the source IP address of the incoming packet matches |
248 |
the IP address in this ARP table entry. */ |
the IP address in this ARP table entry. */ |
249 |
if(ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
if(ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
250 |
|
|
251 |
/* First, check those entries that are already in use. */ |
/* check those entries that are already in use. */ |
252 |
if(arp_table[i].state == ETHARP_STATE_STABLE) { |
if(arp_table[i].state == ETHARP_STATE_STABLE) { |
253 |
/* An old entry found, update this and return. */ |
DEBUGF(ETHARP_DEBUG, ("insert_arp_entry: updating stable entry %u\n", i)); |
254 |
for(k = 0; k < 6; ++k) { |
/* An old entry found, update this and return. */ |
255 |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
for(k = 0; k < 6; ++k) { |
256 |
} |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
257 |
arp_table[i].ctime = ctime; |
} |
258 |
return NULL; |
arp_table[i].ctime = ctime; |
259 |
|
return NULL; |
260 |
} |
} |
261 |
if(arp_table[i].state == ETHARP_STATE_PENDING) { |
else if(arp_table[i].state == ETHARP_STATE_PENDING) { |
262 |
/* A pending entry was found, so we fill this in and return |
/* A pending entry was found, so we fill this in and return |
263 |
the queued packet (if any). */ |
the queued packet (if any). */ |
264 |
for(k = 0; k < 6; ++k) { |
DEBUGF(ETHARP_DEBUG, ("insert_arp_entry: pending entry %u made stable\n", i)); |
265 |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
for(k = 0; k < 6; ++k) { |
266 |
} |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
267 |
arp_table[i].ctime = ctime; |
} |
268 |
arp_table[i].state = ETHARP_STATE_STABLE; |
arp_table[i].ctime = ctime; |
269 |
p = arp_table[i].p; |
arp_table[i].state = ETHARP_STATE_STABLE; |
270 |
if(p != NULL) { |
p = arp_table[i].p; |
271 |
p->payload = arp_table[i].payload; |
// queued packet present? */ |
272 |
p->len = arp_table[i].len; |
if(p != NULL) { |
273 |
p->tot_len = arp_table[i].tot_len; |
/* remove queued packet from ARP entry (must be freed by the caller) */ |
274 |
arp_table[i].p = NULL; |
arp_table[i].p = NULL; |
275 |
|
|
276 |
ethhdr = p->payload; |
/* fill-in Ethernet header */ |
277 |
|
ethhdr = p->payload; |
278 |
for(k = 0; k < 6; ++k) { |
|
279 |
ethhdr->dest.addr[k] = ethaddr->addr[k]; |
for(k = 0; k < 6; ++k) { |
280 |
} |
ethhdr->dest.addr[k] = ethaddr->addr[k]; |
281 |
|
} |
282 |
ethhdr->type = htons(ETHTYPE_IP); |
|
283 |
} |
ethhdr->type = htons(ETHTYPE_IP); |
284 |
return p; |
DEBUGF(ETHARP_DEBUG, ("insert_arp_entry: returning queued packet %p\n", p)); |
285 |
|
} |
286 |
|
/* return queued packet, if any */ |
287 |
|
return p; |
288 |
} |
} |
289 |
} |
} |
290 |
} |
} |
291 |
/* We get here if no ARP entry was found. If so, we create one. */ |
/* no matching ARP entry was found. find an empty or old entry. */ |
292 |
i = find_arp_entry(); |
i = find_arp_entry(); |
293 |
if(i == ARP_TABLE_SIZE) { |
if(i == ARP_TABLE_SIZE) { |
294 |
|
DEBUGF(ETHARP_DEBUG, ("insert_arp_entry: no available entry found\n")); |
295 |
return NULL; |
return NULL; |
296 |
} |
} |
297 |
|
|
298 |
|
if (arp_table[i].state == ETHARP_STATE_STABLE) { |
299 |
|
DEBUGF(ETHARP_DEBUG, ("insert_arp_entry: overwriting old stable entry %u\n", i)); |
300 |
|
} |
301 |
|
else { |
302 |
|
DEBUGF(ETHARP_DEBUG, ("insert_arp_entry: using empty entry %u\n", i)); |
303 |
|
} |
304 |
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
305 |
for(k = 0; k < 6; ++k) { |
for(k = 0; k < 6; ++k) { |
306 |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; |
308 |
arp_table[i].ctime = ctime; |
arp_table[i].ctime = ctime; |
309 |
arp_table[i].state = ETHARP_STATE_STABLE; |
arp_table[i].state = ETHARP_STATE_STABLE; |
310 |
arp_table[i].p = NULL; |
arp_table[i].p = NULL; |
311 |
|
|
312 |
return NULL; |
return NULL; |
313 |
} |
} |
314 |
|
|
315 |
/** |
/** |
316 |
* Updates the ARP table and may return any queued packet to be sent |
* Updates the ARP table and may return any queued packet to be sent. |
317 |
|
* |
318 |
|
* Should be called for all incoming packets of IP kind. It updates |
319 |
|
* the ARP table for the local network. The function does not alter |
320 |
|
* the packet in any way and does not free it. After this function has |
321 |
|
* been called, the packet p must be given to the IP layer. |
322 |
|
* |
323 |
|
* @param netif The lwIP network interface on which the IP packet pbuf arrived. |
324 |
|
* |
325 |
|
* @param pbuf The IP packet that arrived on netif. |
326 |
|
* |
327 |
|
* @return If non-NULL, a pbuf that was queued on an ARP entry. The device |
328 |
|
* driver must transmit this packet onto the network, and call pbuf_free() |
329 |
|
* for the pbuf. |
330 |
* |
* |
331 |
* Should be called for all incoming packets of IP kind. The function |
* @see pbuf_free() |
|
* does not alter the packet in any way, it just updates the ARP |
|
|
* table. After this function has been called, the normal TCP/IP stack |
|
|
* input function should be called. |
|
|
* |
|
|
* The function may return a pbuf containing a packet that had |
|
|
* previously been queued for transmission. The device driver must |
|
|
* transmit this packet onto the network, and call pbuf_free() for the |
|
|
* pbuf. |
|
332 |
*/ |
*/ |
333 |
struct pbuf * |
struct pbuf * |
334 |
etharp_ip_input(struct netif *netif, struct pbuf *p) |
etharp_ip_input(struct netif *netif, struct pbuf *p) |
339 |
|
|
340 |
/* Only insert/update an entry if the source IP address of the |
/* Only insert/update an entry if the source IP address of the |
341 |
incoming IP packet comes from a host on the local network. */ |
incoming IP packet comes from a host on the local network. */ |
342 |
|
|
343 |
|
/* source is on local network? */ |
344 |
if(!ip_addr_maskcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) { |
if(!ip_addr_maskcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) { |
345 |
|
/* do nothing */ |
346 |
return NULL; |
return NULL; |
347 |
} |
} |
348 |
DEBUGF(ETHARP_DEBUG, ("etharp_ip_input: updating ETHARP table.\n")); |
DEBUGF(ETHARP_DEBUG, ("etharp_ip_input: updating ETHARP table.\n")); |
349 |
return update_arp_entry(&(hdr->ip.src), &(hdr->eth.src)); |
/* update ARP table */ |
350 |
|
return insert_arp_entry(&(hdr->ip.src), &(hdr->eth.src)); |
351 |
} |
} |
352 |
|
|
353 |
|
|
354 |
/** |
/** |
355 |
* Updates the ARP table and may return any queued packet to be sent |
* Updates the ARP table and returns an ARP reply or a queued IP packet. |
356 |
* |
* |
357 |
* Should be called for incoming ARP packets. The pbuf in the argument |
* Should be called for incoming ARP packets. The pbuf in the argument |
358 |
* is freed by this function. If the function returns a pbuf (i.e., |
* is freed by this function. The returned pbuf is to be sent and then |
359 |
* returns non-NULL), that pbuf constitutes an ARP reply and should be |
* freed by the caller. |
360 |
* sent out on the Ethernet. |
* |
361 |
|
* @param netif The lwIP network interface on which the ARP packet pbuf arrived. |
362 |
|
* @param pbuf The ARP packet that arrived on netif. Is freed by this function. |
363 |
|
* @param ethaddr Ethernet address of netif. |
364 |
* |
* |
365 |
* @note The driver must call pbuf_free() for the returned pbuf when the |
* @return pbuf to be sent and freed by the caller. |
366 |
* packet has been sent. |
* |
367 |
|
* @see pbuf_free() |
368 |
*/ |
*/ |
369 |
struct pbuf * |
struct pbuf * |
370 |
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) |
371 |
{ |
{ |
372 |
struct etharp_hdr *hdr; |
struct etharp_hdr *hdr; |
373 |
u8_t i; |
u8_t i; |
374 |
|
|
375 |
|
/* drop short ARP packets */ |
376 |
if(p->tot_len < sizeof(struct etharp_hdr)) { |
if(p->tot_len < sizeof(struct etharp_hdr)) { |
377 |
DEBUGF(ETHARP_DEBUG, ("etharp_etharp_input: packet too short (%d/%d)\n", p->tot_len, sizeof(struct etharp_hdr))); |
DEBUGF(ETHARP_DEBUG, ("etharp_etharp_input: packet too short (%d/%d)\n", p->tot_len, sizeof(struct etharp_hdr))); |
378 |
pbuf_free(p); |
pbuf_free(p); |
380 |
} |
} |
381 |
|
|
382 |
hdr = p->payload; |
hdr = p->payload; |
383 |
|
|
384 |
switch(htons(hdr->opcode)) { |
switch(htons(hdr->opcode)) { |
385 |
|
/* ARP request? */ |
386 |
case ARP_REQUEST: |
case ARP_REQUEST: |
387 |
/* ARP request. If it asked for our address, we send out a |
/* ARP request. If it asked for our address, we send out a |
388 |
reply. */ |
reply. */ |
389 |
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP request\n")); |
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP request\n")); |
390 |
|
/* ARP request for our address? */ |
391 |
if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) { |
if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) { |
392 |
|
|
393 |
|
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP request for our address\n")); |
394 |
|
/* re-use pbuf to send ARP reply */ |
395 |
hdr->opcode = htons(ARP_REPLY); |
hdr->opcode = htons(ARP_REPLY); |
396 |
|
|
397 |
ip_addr_set(&(hdr->dipaddr), &(hdr->sipaddr)); |
ip_addr_set(&(hdr->dipaddr), &(hdr->sipaddr)); |
398 |
ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr)); |
ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr)); |
399 |
|
|
400 |
for(i = 0; i < 6; ++i) { |
for(i = 0; i < 6; ++i) { |
401 |
hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i]; |
hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i]; |
402 |
hdr->shwaddr.addr[i] = ethaddr->addr[i]; |
hdr->shwaddr.addr[i] = ethaddr->addr[i]; |
403 |
hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i]; |
hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i]; |
404 |
hdr->ethhdr.src.addr[i] = ethaddr->addr[i]; |
hdr->ethhdr.src.addr[i] = ethaddr->addr[i]; |
405 |
} |
} |
406 |
|
|
407 |
hdr->hwtype = htons(HWTYPE_ETHERNET); |
hdr->hwtype = htons(HWTYPE_ETHERNET); |
408 |
ARPH_HWLEN_SET(hdr, 6); |
ARPH_HWLEN_SET(hdr, 6); |
409 |
|
|
410 |
hdr->proto = htons(ETHTYPE_IP); |
hdr->proto = htons(ETHTYPE_IP); |
411 |
ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr)); |
ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr)); |
412 |
|
|
413 |
hdr->ethhdr.type = htons(ETHTYPE_ARP); |
hdr->ethhdr.type = htons(ETHTYPE_ARP); |
414 |
|
/* return ARP reply */ |
415 |
return p; |
return p; |
416 |
} |
} |
417 |
|
#if 0 |
418 |
|
/* ARP request, NOT for our address */ |
419 |
|
else |
420 |
|
{ |
421 |
|
} |
422 |
|
#endif |
423 |
break; |
break; |
424 |
case ARP_REPLY: |
case ARP_REPLY: |
425 |
/* ARP reply. We insert or update the ARP table. */ |
/* ARP reply. We insert or update the ARP table. */ |
426 |
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP reply\n")); |
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP reply\n")); |
|
if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) { |
|
|
struct pbuf *q; |
|
427 |
#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) |
#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) |
428 |
|
/* DHCP needs to know about ARP replies */ |
429 |
dhcp_arp_reply(&hdr->sipaddr); |
dhcp_arp_reply(&hdr->sipaddr); |
430 |
#endif |
#endif |
431 |
/* update_arp_entry() will return a pbuf that has previously been |
/* for our address? */ |
432 |
queued waiting for an ARP reply. */ |
if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) { |
433 |
q = update_arp_entry(&(hdr->sipaddr), &(hdr->shwaddr)); |
struct pbuf *q; |
434 |
|
DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP reply for us\n")); |
435 |
|
/* insert_arp_entry() can return a pbuf that has previously been |
436 |
|
queued waiting for this IP address to become ARP stable. */ |
437 |
|
q = insert_arp_entry(&(hdr->sipaddr), &(hdr->shwaddr)); |
438 |
|
/* free incoming ARP reply pbuf */ |
439 |
pbuf_free(p); |
pbuf_free(p); |
440 |
p = NULL; |
p = NULL; |
441 |
return q; |
return q; |
442 |
} |
} |
443 |
|
#if 0 |
444 |
|
/* ARP reply, NOT for our address */ |
445 |
|
else |
446 |
|
{ |
447 |
|
} |
448 |
|
#endif |
449 |
break; |
break; |
450 |
default: |
default: |
451 |
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))); |
457 |
} |
} |
458 |
|
|
459 |
/** |
/** |
460 |
* Resolve Ethernet address and append header to the outgoing packet. |
* Resolve and fill-in Ethernet address header for outgoing packet. |
461 |
* |
* |
462 |
* The etharp_output() function should be called for all outgoing |
* If ARP has the Ethernet address in cache, the given packet is |
463 |
* packets. The pbuf returned by the function should be sent out on |
* returned, ready to be sent. |
464 |
* the Ethernet. This pbuf must then be passed to etharp_output_sent(). |
* |
465 |
* |
* If ARP does not have the Ethernet address in cache the packet is |
466 |
* The function prepares the packet for transmission over the Ethernet |
* queued and a ARP request is sent (on a best-effort basis). This |
467 |
* by adding an Ethernet header. If there is no IP -> MAC address |
* ARP request is returned as a pbuf, which should be sent by the |
468 |
* mapping, the function will queue the outgoing packet and return an |
* caller. |
469 |
* ARP request packet instead. |
* |
470 |
|
* If ARP failed to allocate resources, NULL is returned. |
471 |
|
* |
472 |
|
* A returned non-NULL packet should be sent by the caller and |
473 |
|
* etharp_output_sent() must be called afterwards to free any ARP |
474 |
|
* request. |
475 |
* |
* |
476 |
* @param netif The lwIP network interface which the IP packet will be sent on. |
* @param netif The lwIP network interface which the IP packet will be sent on. |
477 |
* @param ipaddr The IP address of the packet destination. |
* @param ipaddr The IP address of the packet destination. |
478 |
* @param pbuf The pbuf(s) containing the IP packet. |
* @param pbuf The pbuf(s) containing the IP packet to be sent. |
479 |
* |
* |
480 |
* @return The packet which should be sent on the network and must be freed by |
* @return If non-NULL, a packet ready to be sent. |
|
* the caller. |
|
|
* |
|
481 |
* @see etharp_output_sent() |
* @see etharp_output_sent() |
482 |
*/ |
*/ |
483 |
struct pbuf * |
struct pbuf * |
485 |
{ |
{ |
486 |
struct eth_addr *dest, *srcaddr, mcastaddr; |
struct eth_addr *dest, *srcaddr, mcastaddr; |
487 |
struct eth_hdr *ethhdr; |
struct eth_hdr *ethhdr; |
|
struct etharp_hdr *hdr; |
|
488 |
struct pbuf *p; |
struct pbuf *p; |
489 |
u8_t i; |
u8_t i; |
490 |
|
|
|
/* obtain source Ethernet address of the given interface */ |
|
|
srcaddr = (struct eth_addr *)netif->hwaddr; |
|
|
|
|
491 |
/* Make room for Ethernet header. */ |
/* Make room for Ethernet header. */ |
492 |
if(pbuf_header(q, sizeof(struct eth_hdr)) != 0) { |
if(pbuf_header(q, sizeof(struct eth_hdr)) != 0) { |
493 |
/* The pbuf_header() call shouldn't fail, and we'll just bail |
/* The pbuf_header() call shouldn't fail, and we'll just bail |
494 |
out if it does.. */ |
out if it does.. */ |
495 |
DEBUGF(ETHARP_DEBUG, ("etharp_output: could not allocate room for header.\n")); |
DEBUGF(ETHARP_DEBUG, ("etharp_output: could not allocate room for header.\n")); |
496 |
#ifdef LINK_STATS |
#ifdef LINK_STATS |
497 |
++stats.link.lenerr; |
++stats.link.lenerr; |
499 |
return NULL; |
return NULL; |
500 |
} |
} |
501 |
|
|
502 |
|
/* obtain source Ethernet address of the given interface */ |
503 |
|
srcaddr = (struct eth_addr *)netif->hwaddr; |
504 |
|
|
505 |
/* assume unresolved Ethernet address */ |
/* assume unresolved Ethernet address */ |
506 |
dest = NULL; |
dest = NULL; |
507 |
/* Construct Ethernet header. Start with looking up deciding which |
/* Construct Ethernet header. Start with looking up deciding which |
508 |
MAC address to use as a destination address. Broadcasts and |
MAC address to use as a destination address. Broadcasts and |
509 |
multicasts are special, all other addresses are looked up in the |
multicasts are special, all other addresses are looked up in the |
510 |
ARP table. */ |
ARP table. */ |
511 |
|
|
512 |
/* destination IP address is an IP broadcast address? */ |
/* destination IP address is an IP broadcast address? */ |
513 |
if(ip_addr_isany(ipaddr) || |
if(ip_addr_isany(ipaddr) || |
514 |
ip_addr_isbroadcast(ipaddr, &(netif->netmask))) { |
ip_addr_isbroadcast(ipaddr, &(netif->netmask))) { |
515 |
/* broadcast on Ethernet also */ |
/* broadcast on Ethernet also */ |
516 |
dest = (struct eth_addr *)ðbroadcast; |
dest = (struct eth_addr *)ðbroadcast; |
517 |
} else if(ip_addr_ismulticast(ipaddr)) { |
} |
518 |
|
/* destination IP address is an IP multicast address? */ |
519 |
|
else if(ip_addr_ismulticast(ipaddr)) { |
520 |
/* Hash IP multicast address to MAC address. */ |
/* Hash IP multicast address to MAC address. */ |
521 |
mcastaddr.addr[0] = 0x01; |
mcastaddr.addr[0] = 0x01; |
522 |
mcastaddr.addr[1] = 0x0; |
mcastaddr.addr[1] = 0x0; |
526 |
mcastaddr.addr[5] = ip4_addr4(ipaddr); |
mcastaddr.addr[5] = ip4_addr4(ipaddr); |
527 |
/* destination Ethernet address is multicast */ |
/* destination Ethernet address is multicast */ |
528 |
dest = &mcastaddr; |
dest = &mcastaddr; |
529 |
/* destination IP unicast address */ |
} |
530 |
} else { |
/* destination IP address is an IP unicast address */ |
531 |
/* the destination IP network address does not match the interface's |
else { |
532 |
network address */ |
/* destination IP network address not on local network? */ |
533 |
if(!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { |
if(!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { |
534 |
/* Use the IP address of the default gateway if the destination |
/* gateway available? */ |
535 |
is not on the same subnet as we are. */ |
if (netif->gw.addr != 0) |
536 |
ipaddr = &(netif->gw); |
{ |
537 |
} |
/* use the default gateway IP address */ |
538 |
|
ipaddr = &(netif->gw); |
539 |
/* Try to find a stable IP-to-Ethernet address mapping for this IP |
} |
540 |
destination address */ |
else |
541 |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
{ |
542 |
if(arp_table[i].state == ETHARP_STATE_STABLE && |
/* IP destination address outside local network, but no gateway available */ |
543 |
ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
return NULL; |
|
dest = &arp_table[i].ethaddr; |
|
|
break; |
|
544 |
} |
} |
545 |
} |
} |
546 |
} |
|
547 |
|
/* Ethernet address for IP destination address is in ARP cache? */ |
|
/* could not find a destination Ethernet address? */ |
|
|
if(dest == NULL) { |
|
|
/* No destination address has been found, so we'll have to send |
|
|
out an ARP request for the IP address. The outgoing packet is |
|
|
queued unless the queue is full. */ |
|
|
|
|
|
/* TODO: The host requirements RFC states that ARP should save at least one |
|
|
packet, and this should be the _latest_ packet. */ |
|
|
|
|
|
/* We check if we are already querying for this address. If so, |
|
|
we'll bail out. */ |
|
548 |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
549 |
if(arp_table[i].state == ETHARP_STATE_PENDING && |
/* match found? */ |
550 |
ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
if(arp_table[i].state == ETHARP_STATE_STABLE && |
551 |
DEBUGF(ETHARP_DEBUG, ("etharp_output: already queued\n")); |
ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
552 |
return NULL; |
dest = &arp_table[i].ethaddr; |
553 |
|
break; |
554 |
} |
} |
555 |
} |
} |
556 |
|
/* could not find the destination Ethernet address in ARP cache? */ |
557 |
/* find a usable ARP entry */ |
if (dest == NULL) { |
558 |
i = find_arp_entry(); |
/* query for the IP address using ARP request */ |
559 |
|
p = etharp_query(netif, ipaddr, q); |
560 |
/* If all table entries were in pending state, we won't send out any |
/* return the ARP request */ |
561 |
more ARP requests. We'll just give up. */ |
return p; |
|
if(i == ARP_TABLE_SIZE) { |
|
|
return NULL; |
|
562 |
} |
} |
563 |
|
/* destination Ethernet address resolved from ARP cache*/ |
564 |
/* Now, i is the ARP table entry which we will fill with the new |
else |
565 |
information. */ |
{ |
566 |
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
/* fallthrough */ |
|
arp_table[i].ctime = ctime; |
|
|
arp_table[i].state = ETHARP_STATE_PENDING; |
|
|
#if 1 |
|
|
arp_table[i].p = q; |
|
|
arp_table[i].payload = q->payload; |
|
|
arp_table[i].len = q->len; |
|
|
arp_table[i].tot_len = q->tot_len; |
|
|
|
|
|
/* Because the pbuf will be queued, we'll increase the reference |
|
|
count. */ |
|
|
DEBUGF(ETHARP_DEBUG, ("etharp_output: queueing %p\n", q)); |
|
|
pbuf_ref(q); |
|
|
#else |
|
|
arp_table[i].p = NULL; |
|
|
#endif /* 0 */ |
|
|
|
|
|
|
|
|
/* We allocate a pbuf for the outgoing ARP request packet. */ |
|
|
p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM); |
|
|
if(p == NULL) { |
|
|
/* No ARP request packet could be allocated, so we forget about |
|
|
the ARP table entry. */ |
|
|
if(i != ARP_TABLE_SIZE) { |
|
|
arp_table[i].state = ETHARP_STATE_EMPTY; |
|
|
/* We decrease the reference count of the queued pbuf (which now |
|
|
is dequeued). */ |
|
|
DEBUGF(ETHARP_DEBUG, ("etharp_output: couldn't alloc pbuf for query, dequeueing %p\n", q)); |
|
|
pbuf_free(q); |
|
|
} |
|
|
return NULL; |
|
567 |
} |
} |
568 |
|
} |
569 |
hdr = p->payload; |
|
570 |
|
/* destination Ethernet address known */ |
571 |
hdr->opcode = htons(ARP_REQUEST); |
if (dest != NULL) { |
|
|
|
|
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); |
|
|
|
|
|
hdr->proto = htons(ETHTYPE_IP); |
|
|
ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr)); |
|
|
|
|
|
for(i = 0; i < 6; ++i) { |
|
|
hdr->ethhdr.dest.addr[i] = 0xff; |
|
|
hdr->ethhdr.src.addr[i] = srcaddr->addr[i]; |
|
|
} |
|
|
|
|
|
hdr->ethhdr.type = htons(ETHTYPE_ARP); |
|
|
return p; |
|
|
} else { |
|
572 |
/* A valid IP->MAC address mapping was found, so we construct the |
/* A valid IP->MAC address mapping was found, so we construct the |
573 |
Ethernet header for the outgoing packet. */ |
Ethernet header for the outgoing packet. */ |
574 |
|
|
575 |
ethhdr = q->payload; |
ethhdr = q->payload; |
576 |
|
|
577 |
for(i = 0; i < 6; i++) { |
for(i = 0; i < 6; i++) { |
578 |
ethhdr->dest.addr[i] = dest->addr[i]; |
ethhdr->dest.addr[i] = dest->addr[i]; |
579 |
ethhdr->src.addr[i] = srcaddr->addr[i]; |
ethhdr->src.addr[i] = srcaddr->addr[i]; |
580 |
} |
} |
581 |
|
|
582 |
ethhdr->type = htons(ETHTYPE_IP); |
ethhdr->type = htons(ETHTYPE_IP); |
583 |
|
/* return the outgoing packet */ |
584 |
return q; |
return q; |
585 |
} |
} |
586 |
|
// never reached; here for safety |
587 |
|
return NULL; |
588 |
} |
} |
589 |
|
|
590 |
/** |
/** |
591 |
* Clean up the ARP request that was allocated by ARP. |
* Free the ARP request pbuf. |
592 |
* |
* |
593 |
* This must be called after you have sent the packet |
* Free the ARP request pbuf that was allocated by ARP |
594 |
* returned by etharp_output(). It frees any pbuf |
* |
595 |
* allocated for an ARP request. |
* as a result of calling etharp_output(). Must be called |
596 |
|
* with the pbuf returned by etharp_output(), after you |
597 |
|
* have sent that packet. |
598 |
|
* |
599 |
|
* @param p pbuf returned earlier by etharp_output(). |
600 |
|
* |
601 |
|
* @see etharp_output(). |
602 |
*/ |
*/ |
603 |
struct pbuf * |
struct pbuf * |
604 |
etharp_output_sent(struct pbuf *p) |
etharp_output_sent(struct pbuf *p) |
606 |
struct etharp_hdr *hdr; |
struct etharp_hdr *hdr; |
607 |
hdr=p->payload; |
hdr=p->payload; |
608 |
if (hdr->opcode == htons(ARP_REQUEST)) { |
if (hdr->opcode == htons(ARP_REQUEST)) { |
609 |
pbuf_free(p); p=NULL; |
pbuf_free(p); |
610 |
}; |
p = NULL; |
611 |
|
} |
612 |
return p; |
return p; |
613 |
} |
} |
614 |
|
|
615 |
/** |
/** |
616 |
* Initiate an ARP query for the given IP address. |
* Send an ARP request for the given IP address. |
617 |
|
* |
618 |
|
* Sends an ARP request for the given IP address, unless |
619 |
|
* a request for this address is already pending. Optionally |
620 |
|
* queues an outgoing packet on the resulting ARP entry. |
621 |
* |
* |
622 |
* Used by the DHCP module to support "gratuitous" ARP, |
* @param netif The lwIP network interface where ipaddr |
623 |
* i.e. send ARP requests for one's own IP address, to |
* must be queried for. |
624 |
* see if others have the IP address in use. |
* @param ipaddr The IP address to be resolved. |
625 |
|
* @param q If non-NULL, a pbuf that must be queued on the |
626 |
|
* ARP entry for the ipaddr IP address. |
627 |
* |
* |
628 |
* Might be used in the future by manual IP configuration |
* @return pbuf containing the ARP request, NULL on failure. |
629 |
|
* |
630 |
|
* @note Might be used in the future by manual IP configuration |
631 |
* as well. |
* as well. |
632 |
* |
* |
633 |
*/ |
*/ |
634 |
|
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) |
|
635 |
{ |
{ |
636 |
struct eth_addr *srcaddr; |
struct eth_addr *srcaddr; |
637 |
struct etharp_hdr *hdr; |
struct etharp_hdr *hdr; |
638 |
struct pbuf *p; |
struct pbuf *p; |
639 |
u8_t i, j; |
u8_t i; |
|
u8_t maxtime; |
|
640 |
|
|
641 |
srcaddr = (struct eth_addr *)netif->hwaddr; |
srcaddr = (struct eth_addr *)netif->hwaddr; |
642 |
/* We check if we are already querying for this address. If so, |
/* bail out if this IP address is pending */ |
643 |
we'll bail out. */ |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
644 |
for(i = 0; i < ARP_TABLE_SIZE; ++i) |
if(arp_table[i].state == ETHARP_STATE_PENDING && |
645 |
{ |
ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
646 |
if(arp_table[i].state == ETHARP_STATE_PENDING && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) |
DEBUGF(ETHARP_DEBUG, ("etharp_query: request already pending\n")); |
647 |
{ |
/* TODO: enqueue q here if possible (BEWARE: possible other packet already |
648 |
DEBUGF(ETHARP_DEBUG, ("etharp_output: already queued\n")); |
queued. */ |
649 |
|
/* TODO: The host requirements RFC states that ARP should save at least one |
650 |
|
packet, and this should be the _latest_ packet. */ |
651 |
|
/* TODO: use the ctime field to see how long ago an ARP request was sent, |
652 |
|
possibly retry. */ |
653 |
return NULL; |
return NULL; |
654 |
} |
} |
655 |
} |
} |
656 |
/* We now try to find an unused entry in the ARP table that we |
i = find_arp_entry(); |
657 |
will setup and queue the outgoing packet. */ |
/* bail out if no ARP entries are available */ |
|
for(i = 0; i < ARP_TABLE_SIZE; ++i) |
|
|
{ |
|
|
if(arp_table[i].state == ETHARP_STATE_EMPTY) |
|
|
{ |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
/* If no unused entry is found, we try to find the oldest entry and |
|
|
throw it away. */ |
|
|
if(i == ARP_TABLE_SIZE) |
|
|
{ |
|
|
maxtime = 0; |
|
|
j = 0; |
|
|
for(i = 0; i < ARP_TABLE_SIZE; ++i) |
|
|
{ |
|
|
if(arp_table[i].state == ETHARP_STATE_STABLE && ctime - arp_table[i].ctime > maxtime) |
|
|
{ |
|
|
maxtime = ctime - arp_table[i].ctime; |
|
|
j = i; |
|
|
} |
|
|
} |
|
|
i = j; |
|
|
} |
|
|
|
|
|
/* If all table entries were in pending state, we won't send out any |
|
|
more ARP requests. We'll just give up. */ |
|
658 |
if(i == ARP_TABLE_SIZE) |
if(i == ARP_TABLE_SIZE) |
659 |
{ |
{ |
660 |
DEBUGF(ETHARP_DEBUG, ("etharp_output: no more ARP table entries available.\n")); |
DEBUGF(ETHARP_DEBUG, ("etharp_query: no more ARP table entries available.\n")); |
661 |
return NULL; |
return NULL; |
662 |
} |
} |
663 |
|
|
664 |
/* Now, i is the ARP table entry which we will fill with the new |
/* i is an available ARP table entry */ |
665 |
information. */ |
/* allocate a pbuf for the outgoing ARP request packet */ |
|
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
|
|
/* for(k = 0; k < 6; ++k) { |
|
|
arp_table[i].ethaddr.addr[k] = dest->addr[k]; |
|
|
}*/ |
|
|
arp_table[i].ctime = ctime; |
|
|
arp_table[i].state = ETHARP_STATE_PENDING; |
|
|
arp_table[i].p = NULL; |
|
|
|
|
|
/* We allocate a pbuf for the outgoing ARP request packet. */ |
|
666 |
p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM); |
p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM); |
667 |
if(p == NULL) |
/* could allocate pbuf? */ |
668 |
{ |
if (p != NULL) { |
669 |
/* No ARP request packet could be allocated, so we forget about |
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
670 |
the ARP table entry. */ |
arp_table[i].ctime = ctime; |
671 |
if(i != ARP_TABLE_SIZE) |
arp_table[i].state = ETHARP_STATE_PENDING; |
672 |
{ |
/* remember pbuf to queue, if any */ |
673 |
arp_table[i].state = ETHARP_STATE_EMPTY; |
arp_table[i].p = q; |
674 |
} |
/* any pbuf to queue? */ |
675 |
|
if (q != NULL) { |
676 |
|
/* pbufs are queued, increase the reference count */ |
677 |
|
pbuf_ref_chain(q); |
678 |
|
} |
679 |
|
} |
680 |
|
/* could not allocate pbuf for ARP request */ |
681 |
|
else { |
682 |
return NULL; |
return NULL; |
683 |
} |
} |
684 |
|
/* p is the allocated pbuf */ |
685 |
|
|
686 |
hdr = p->payload; |
hdr = p->payload; |
|
|
|
687 |
hdr->opcode = htons(ARP_REQUEST); |
hdr->opcode = htons(ARP_REQUEST); |
688 |
|
|
689 |
for(i = 0; i < 6; ++i) |
for(i = 0; i < 6; ++i) |