124 |
static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; |
static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; |
125 |
static struct etharp_entry arp_table[ARP_TABLE_SIZE]; |
static struct etharp_entry arp_table[ARP_TABLE_SIZE]; |
126 |
|
|
127 |
static struct pbuf *update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags); |
static s8_t find_arp_entry(void); |
128 |
#define ARP_INSERT_FLAG 1 |
#define ARP_INSERT_FLAG 1 |
129 |
|
static struct pbuf *update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags); |
130 |
|
#if ARP_QUEUEING |
131 |
|
static struct pbuf *etharp_enqueue(s8_t i, struct pbuf *q); |
132 |
|
static struct pbuf *etharp_dequeue(s8_t i); |
133 |
|
#endif |
134 |
/** |
/** |
135 |
* Initializes ARP module. |
* Initializes ARP module. |
136 |
*/ |
*/ |
137 |
void |
void |
138 |
etharp_init(void) |
etharp_init(void) |
139 |
{ |
{ |
140 |
u8_t i; |
s8_t i; |
141 |
/* clear ARP entries */ |
/* clear ARP entries */ |
142 |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
143 |
arp_table[i].state = ETHARP_STATE_EMPTY; |
arp_table[i].state = ETHARP_STATE_EMPTY; |
144 |
#if ARP_QUEUEING |
#if ARP_QUEUEING |
145 |
arp_table[i].p = NULL; |
arp_table[i].p = NULL; |
146 |
#endif |
#endif |
147 |
|
arp_table[i].ctime = 0; |
148 |
} |
} |
149 |
} |
} |
150 |
|
|
157 |
void |
void |
158 |
etharp_tmr(void) |
etharp_tmr(void) |
159 |
{ |
{ |
160 |
u8_t i; |
s8_t i; |
161 |
|
|
162 |
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); |
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); |
163 |
/* remove expired entries from the ARP table */ |
/* remove expired entries from the ARP table */ |
191 |
} |
} |
192 |
|
|
193 |
/** |
/** |
194 |
* Return an empty ARP entry or, if the table is full, ARP_TABLE_SIZE if all |
* Return an empty ARP entry (possibly recycling the oldest stable entry). |
|
* entries are pending, otherwise the oldest entry. |
|
195 |
* |
* |
196 |
* @return The ARP entry index that is available, ARP_TABLE_SIZE if no usable |
* @return The ARP entry index that is available, ERR_MEM if no usable |
197 |
* entry is found. |
* entry is found. |
198 |
*/ |
*/ |
199 |
static u8_t |
static s8_t |
200 |
find_arp_entry(void) |
find_arp_entry(void) |
201 |
{ |
{ |
202 |
u8_t i, j, maxtime; |
s8_t i, j; |
203 |
|
u8_t maxtime = 0; |
204 |
|
|
205 |
/* Try to find an unused entry in the ARP table. */ |
j = ARP_TABLE_SIZE; |
206 |
|
/* search ARP table for an unused or old entry */ |
207 |
for (i = 0; i < ARP_TABLE_SIZE; ++i) { |
for (i = 0; i < ARP_TABLE_SIZE; ++i) { |
208 |
|
/* empty entry? */ |
209 |
if (arp_table[i].state == ETHARP_STATE_EMPTY) { |
if (arp_table[i].state == ETHARP_STATE_EMPTY) { |
210 |
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found empty entry %u\n", i)); |
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning empty entry %u\n", i)); |
211 |
break; |
return i; |
212 |
|
/* stable entry? */ |
213 |
|
} else if (arp_table[i].state == ETHARP_STATE_STABLE) { |
214 |
|
/* remember entry with oldest stable entry in j */ |
215 |
|
if (arp_table[i].ctime >= maxtime) maxtime = arp_table[j = i].ctime; |
216 |
} |
} |
217 |
} |
} |
218 |
|
/* no empty entry found? */ |
|
/* If no unused entry is found, we try to find the oldest entry and |
|
|
throw it away. If all entries are new and ctime drop one */ |
|
219 |
if (i == ARP_TABLE_SIZE) { |
if (i == ARP_TABLE_SIZE) { |
220 |
maxtime = 0; |
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found oldest stable entry %u\n", j)); |
221 |
j = ARP_TABLE_SIZE; |
/* fall-back to oldest stable */ |
222 |
for (i = 0; i < ARP_TABLE_SIZE; ++i) { |
i = j; |
223 |
/* remember entry with oldest stable entry in j */ |
} |
224 |
if ((arp_table[i].state == ETHARP_STATE_STABLE) && |
/* no available entry found? */ |
225 |
#if ARP_QUEUEING /* do not want to re-use an entry with queued packets */ |
if (i == ARP_TABLE_SIZE) { |
226 |
(arp_table[i].p == NULL) && |
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: no replacable entry could be found\n")); |
227 |
#endif |
/* return failure */ |
228 |
(arp_table[i].ctime >= maxtime)) { |
return ERR_MEM; |
|
maxtime = arp_table[i].ctime; |
|
|
j = i; |
|
|
/* { j = oldest stable entry } */ |
|
|
} |
|
|
} |
|
|
if (j != ARP_TABLE_SIZE) { |
|
|
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found oldest stable entry %u\n", j)); |
|
|
} else { |
|
|
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: no replacable entry could be found\n")); |
|
|
} |
|
|
i = j; |
|
229 |
} |
} |
230 |
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning %u, state %u\n", i, arp_table[i].state)); |
|
231 |
|
/* clean up the recycled stable entry */ |
232 |
|
if (arp_table[i].state == ETHARP_STATE_STABLE) { |
233 |
|
#if ARP_QUEUEING |
234 |
|
struct pbuf *q; |
235 |
|
/* free packets on queue */ |
236 |
|
q = etharp_dequeue(i); |
237 |
|
if (q != NULL) pbuf_free(q); |
238 |
|
#endif |
239 |
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_arp_entry: recycling oldest stable entry %u\n", i)); |
240 |
|
arp_table[i].state = ETHARP_STATE_EMPTY; |
241 |
|
arp_table[i].ctime = 0; |
242 |
|
} |
243 |
|
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning %u\n", i)); |
244 |
return i; |
return i; |
245 |
} |
} |
246 |
|
|
247 |
|
#if ARP_QUEUEING |
248 |
|
static struct pbuf * |
249 |
|
etharp_enqueue(s8_t i, struct pbuf *q) |
250 |
|
{ |
251 |
|
/* any pbuf to queue? */ |
252 |
|
if (q != NULL) { |
253 |
|
/* remove old packet on queue? */ |
254 |
|
#if ARP_QUEUE_FIRST == 0 |
255 |
|
struct pbuf *p; |
256 |
|
p = etharp_dequeue(i); |
257 |
|
if (p != NULL) pbuf_free(p); |
258 |
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("etharp_query: dropped packet %p on ARP queue. Should not occur.\n", (void *)arp_table[i].p)); |
259 |
|
#endif |
260 |
|
/* packet can be queued? */ |
261 |
|
if (arp_table[i].p == NULL) { |
262 |
|
/* copy PBUF_REF referenced payloads into PBUF_RAM */ |
263 |
|
q = pbuf_take(q); |
264 |
|
/* remember pbuf to queue, if any */ |
265 |
|
arp_table[i].p = q; |
266 |
|
/* pbufs are queued, increase the reference count */ |
267 |
|
pbuf_ref(q); |
268 |
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: queued packet %p on ARP entry %u.\n", (void *)q, i)); |
269 |
|
} |
270 |
|
} |
271 |
|
return arp_table[i].p; |
272 |
|
} |
273 |
|
|
274 |
|
static struct pbuf * |
275 |
|
etharp_dequeue(s8_t i) |
276 |
|
{ |
277 |
|
/* queued packets on a stable entry (work in progress) */ |
278 |
|
if (arp_table[i].p != NULL) { |
279 |
|
/* send the queued IP packets */ |
280 |
|
netif->linkoutput(netif, arp_table[i].p); |
281 |
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, |
282 |
|
("find_arp_entry: sent queued packet %p.\n", (void *)arp_table[i].p)); |
283 |
|
arp_table[i].p = NULL; |
284 |
|
} |
285 |
|
return arp_table[i].p; |
286 |
|
} |
287 |
|
#endif |
288 |
|
|
289 |
/** |
/** |
290 |
* Update (or insert) a IP/MAC address pair in the ARP cache. |
* Update (or insert) a IP/MAC address pair in the ARP cache. |
291 |
* |
* |
303 |
static struct pbuf * |
static struct pbuf * |
304 |
update_arp_entry(struct netif *netif, 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) |
305 |
{ |
{ |
306 |
u8_t i, k; |
s8_t i, k; |
307 |
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("update_arp_entry()\n")); |
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("update_arp_entry()\n")); |
308 |
LWIP_ASSERT("netif->hwaddr_len != 0", netif->hwaddr_len != 0); |
LWIP_ASSERT("netif->hwaddr_len != 0", netif->hwaddr_len != 0); |
309 |
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: %u.%u.%u.%u - %02x:%02x:%02x:%02x:%02x:%02x\n", ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr), |
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: %u.%u.%u.%u - %02x:%02x:%02x:%02x:%02x:%02x\n", ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr), |
375 |
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: adding entry to table\n")); |
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: adding entry to table\n")); |
376 |
/* find an empty or old entry. */ |
/* find an empty or old entry. */ |
377 |
i = find_arp_entry(); |
i = find_arp_entry(); |
378 |
if (i == ARP_TABLE_SIZE) { |
if (i == ERR_MEM) { |
379 |
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no available entry found\n")); |
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no available entry found\n")); |
380 |
return NULL; |
return NULL; |
381 |
} |
} |
|
/* see if find_arp_entry() gave us an old stable, or empty entry to re-use */ |
|
|
if (arp_table[i].state == ETHARP_STATE_STABLE) { |
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: overwriting old stable entry %u\n", i)); |
|
|
/* stable entries should have no queued packets (TODO: allow later) */ |
|
|
#if ARP_QUEUEING |
|
|
LWIP_ASSERT("update_arp_entry: arp_table[i].p == NULL", arp_table[i].p == NULL); |
|
|
#endif |
|
|
} else { |
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("update_arp_entry: filling empty entry %u with state %u\n", i, arp_table[i].state)); |
|
|
LWIP_ASSERT("update_arp_entry: arp_table[i].state == ETHARP_STATE_EMPTY", arp_table[i].state == ETHARP_STATE_EMPTY); |
|
|
} |
|
382 |
/* set IP address */ |
/* set IP address */ |
383 |
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
384 |
/* set Ethernet hardware address */ |
/* set Ethernet hardware address */ |
580 |
{ |
{ |
581 |
struct eth_addr *dest, *srcaddr, mcastaddr; |
struct eth_addr *dest, *srcaddr, mcastaddr; |
582 |
struct eth_hdr *ethhdr; |
struct eth_hdr *ethhdr; |
583 |
u8_t i; |
s8_t i; |
584 |
|
|
585 |
/* make room for Ethernet header */ |
/* make room for Ethernet header */ |
586 |
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { |
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { |
709 |
struct eth_addr *srcaddr; |
struct eth_addr *srcaddr; |
710 |
struct etharp_hdr *hdr; |
struct etharp_hdr *hdr; |
711 |
err_t result = ERR_OK; |
err_t result = ERR_OK; |
712 |
u8_t i; |
s8_t i; |
713 |
u8_t perform_arp_request = 1; |
u8_t perform_arp_request = 1; |
714 |
/* prevent 'unused argument' warning if ARP_QUEUEING == 0 */ |
/* prevent 'unused argument' warning if ARP_QUEUEING == 0 */ |
715 |
(void)q; |
(void)q; |
719 |
if (ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
if (ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
720 |
if (arp_table[i].state == ETHARP_STATE_PENDING) { |
if (arp_table[i].state == ETHARP_STATE_PENDING) { |
721 |
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already pending as entry %u\n", i)); |
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already pending as entry %u\n", i)); |
722 |
/* break out of for-loop, user may wish to queue a packet on a stable entry */ |
/* break out of for-loop, user may wish to queue a packet on a pending entry */ |
723 |
/* TODO: we will issue a new ARP request, which should not occur too often */ |
/* TODO: we will issue a new ARP request, which should not occur too often */ |
724 |
/* we might want to run a faster timer on ARP to limit this */ |
/* we might want to run a faster timer on ARP to limit this */ |
725 |
break; |
break; |
739 |
/* find an available (unused or old) entry */ |
/* find an available (unused or old) entry */ |
740 |
i = find_arp_entry(); |
i = find_arp_entry(); |
741 |
/* bail out if no ARP entries are available */ |
/* bail out if no ARP entries are available */ |
742 |
if (i == ARP_TABLE_SIZE) { |
if (i == ERR_MEM) { |
743 |
LWIP_DEBUGF(ETHARP_DEBUG | 2, ("etharp_query: no more ARP entries available. Should seldom occur.\n")); |
LWIP_DEBUGF(ETHARP_DEBUG | 2, ("etharp_query: no more ARP entries available. Should seldom occur.\n")); |
744 |
return ERR_MEM; |
return ERR_MEM; |
745 |
} |
} |
|
/* we will now recycle entry i */ |
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: created ARP table entry %u.\n", i)); |
|
746 |
/* i is available, create ARP entry */ |
/* i is available, create ARP entry */ |
|
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
|
|
arp_table[i].ctime = 0; |
|
747 |
arp_table[i].state = ETHARP_STATE_PENDING; |
arp_table[i].state = ETHARP_STATE_PENDING; |
748 |
#if ARP_QUEUEING /* deal with queue of recycled entry */ |
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
749 |
/* free queued packet, as entry is now invalidated and recycled */ |
/* queried address was already in ARP table */ |
750 |
if (arp_table[i].p != NULL) { |
} else { |
|
pbuf_free(arp_table[i].p); |
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, |
|
|
("etharp_query: dropped packet %p from recycled ARP entry queue. Should not occur.\n", (void *)arp_table[i].p)); |
|
|
arp_table[i].p = NULL; |
|
|
} |
|
|
#endif |
|
|
} |
|
751 |
#if ARP_QUEUEING |
#if ARP_QUEUEING |
752 |
/* any pbuf to queue and queue is empty? */ |
etharp_enqueue(i, q); |
|
if (q != NULL) { |
|
|
/* yield later packets over older packets? */ |
|
|
#if ARP_QUEUE_FIRST == 0 |
|
|
/* earlier queued packet on this entry? */ |
|
|
if (arp_table[i].p != NULL) { |
|
|
pbuf_free(arp_table[i].p); |
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("etharp_query: dropped packet %p on ARP queue. Should not occur.\n", (void *)arp_table[i].p)); |
|
|
arp_table[i].p = NULL; |
|
|
/* fall-through into next if */ |
|
|
} |
|
753 |
#endif |
#endif |
|
/* packet can be queued? */ |
|
|
if (arp_table[i].p == NULL) { |
|
|
/* copy PBUF_REF referenced payloads into PBUF_RAM */ |
|
|
q = pbuf_take(q); |
|
|
/* remember pbuf to queue, if any */ |
|
|
arp_table[i].p = q; |
|
|
/* pbufs are queued, increase the reference count */ |
|
|
pbuf_ref(q); |
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: queued packet %p on ARP entry %u.\n", (void *)q, i)); |
|
|
} |
|
754 |
} |
} |
|
#endif |
|
755 |
/* ARP request? */ |
/* ARP request? */ |
756 |
if (perform_arp_request) |
if (perform_arp_request) |
757 |
{ |
{ |