arp_cache.c
Go to the documentation of this file.
1 /**
2  * @file arp_cache.c
3  * @brief ARP cache management
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * Address Resolution Protocol is used to determine the hardware address of
30  * a specific host when only its IPv4 address is known. Refer to RFC 826
31  *
32  * @author Oryx Embedded SARL (www.oryx-embedded.com)
33  * @version 2.4.4
34  **/
35 
36 //Switch to the appropriate trace level
37 #define TRACE_LEVEL ARP_TRACE_LEVEL
38 
39 //Dependencies
40 #include "core/net.h"
41 #include "ipv4/arp_cache.h"
42 #include "ipv4/ipv4_misc.h"
43 #include "debug.h"
44 
45 //Check TCP/IP stack configuration
46 #if (IPV4_SUPPORT == ENABLED && ETH_SUPPORT == ENABLED)
47 
48 
49 /**
50  * @brief Update ARP cache entry state
51  * @param[in] entry Pointer to a ARP cache entry
52  * @param[in] newState New state to switch to
53  **/
54 
55 void arpChangeState(ArpCacheEntry *entry, ArpState newState)
56 {
57 #if defined(ARP_CHANGE_STATE_HOOK)
58  ARP_CHANGE_STATE_HOOK(entry, newState);
59 #endif
60 
61  //Save current time
62  entry->timestamp = osGetSystemTime();
63  //Switch to the new state
64  entry->state = newState;
65 }
66 
67 
68 /**
69  * @brief Create a new entry in the ARP cache
70  * @param[in] interface Underlying network interface
71  * @return Pointer to the newly created entry
72  **/
73 
75 {
76  uint_t i;
78  ArpCacheEntry *entry;
79  ArpCacheEntry *oldestEntry;
80 
81  //Get current time
83 
84  //Keep track of the oldest entry
85  oldestEntry = NULL;
86 
87  //Loop through ARP cache entries
88  for(i = 0; i < ARP_CACHE_SIZE; i++)
89  {
90  //Point to the current entry
91  entry = &interface->arpCache[i];
92 
93  //Check the state of the ARP entry
94  if(entry->state == ARP_STATE_NONE)
95  {
96  //Initialize ARP entry
97  osMemset(entry, 0, sizeof(ArpCacheEntry));
98 
99  //Return a pointer to the ARP entry
100  return entry;
101  }
102  else if(entry->state == ARP_STATE_PERMANENT)
103  {
104  //Static ARP entries are never updated
105  }
106  else
107  {
108  //Keep track of the oldest entry in the table
109  if(oldestEntry == NULL)
110  {
111  oldestEntry = entry;
112  }
113  else if(entry->state == ARP_STATE_STALE &&
114  oldestEntry->state != ARP_STATE_STALE)
115  {
116  oldestEntry = entry;
117  }
118  else if(entry->state != ARP_STATE_STALE &&
119  oldestEntry->state == ARP_STATE_STALE)
120  {
121  }
122  else if((time - entry->timestamp) > (time - oldestEntry->timestamp))
123  {
124  oldestEntry = entry;
125  }
126  else
127  {
128  }
129  }
130  }
131 
132  //Any entry available in the ARP cache?
133  if(oldestEntry != NULL)
134  {
135  //Drop any pending packets
136  arpFlushQueuedPackets(interface, oldestEntry);
137  //The oldest entry is removed whenever the table runs out of space
138  arpChangeState(oldestEntry, ARP_STATE_NONE);
139  //Initialize ARP entry
140  osMemset(oldestEntry, 0, sizeof(ArpCacheEntry));
141  }
142 
143  //Return a pointer to the ARP entry
144  return oldestEntry;
145 }
146 
147 
148 /**
149  * @brief Search the ARP cache for a given IPv4 address
150  * @param[in] interface Underlying network interface
151  * @param[in] ipAddr IPv4 address
152  * @return A pointer to the matching ARP entry is returned. NULL is returned
153  * if the specified IPv4 address could not be found in ARP cache
154  **/
155 
157 {
158  uint_t i;
159  ArpCacheEntry *entry;
160 
161  //Loop through ARP cache entries
162  for(i = 0; i < ARP_CACHE_SIZE; i++)
163  {
164  //Point to the current entry
165  entry = &interface->arpCache[i];
166 
167  //Check whether the entry is currently in use
168  if(entry->state != ARP_STATE_NONE)
169  {
170  //Current entry matches the specified address?
171  if(entry->ipAddr == ipAddr)
172  {
173  return entry;
174  }
175  }
176  }
177 
178  //No matching entry in ARP cache
179  return NULL;
180 }
181 
182 
183 /**
184  * @brief Flush ARP cache
185  * @param[in] interface Underlying network interface
186  **/
187 
188 void arpFlushCache(NetInterface *interface)
189 {
190  uint_t i;
191  ArpCacheEntry *entry;
192 
193  //Loop through ARP cache entries
194  for(i = 0; i < ARP_CACHE_SIZE; i++)
195  {
196  //Point to the current entry
197  entry = &interface->arpCache[i];
198 
199  //Check the state of the ARP entry
200  if(entry->state == ARP_STATE_PERMANENT)
201  {
202  //Static ARP entries are never updated
203  }
204  else
205  {
206  //Drop packets that are waiting for address resolution
207  arpFlushQueuedPackets(interface, entry);
208 
209  //Delete ARP entry
211  }
212  }
213 }
214 
215 
216 /**
217  * @brief Send packets that are waiting for address resolution
218  * @param[in] interface Underlying network interface
219  * @param[in] entry Pointer to a ARP cache entry
220  **/
221 
223 {
224  uint_t i;
225  size_t length;
226  ArpQueueItem *item;
227 
228  //Check the state of the ARP entry
229  if(entry->state == ARP_STATE_INCOMPLETE)
230  {
231  //Loop through the queued packets
232  for(i = 0; i < entry->queueSize; i++)
233  {
234  //Point to the current queue item
235  item = &entry->queue[i];
236 
237  //Retrieve the length of the IPv4 packet
238  length = netBufferGetLength(item->buffer) - item->offset;
239  //Update IP statistics
240  ipv4UpdateOutStats(interface, entry->ipAddr, length);
241 
242  //Send the IPv4 packet
243  ethSendFrame(interface, &entry->macAddr, ETH_TYPE_IPV4, item->buffer,
244  item->offset, &item->ancillary);
245 
246  //Release memory buffer
247  netBufferFree(item->buffer);
248  }
249  }
250 
251  //The queue is now empty
252  entry->queueSize = 0;
253 }
254 
255 
256 /**
257  * @brief Flush packet queue
258  * @param[in] interface Underlying network interface
259  * @param[in] entry Pointer to a ARP cache entry
260  **/
261 
263 {
264  uint_t i;
265 
266  //Check the state of the ARP entry
267  if(entry->state == ARP_STATE_INCOMPLETE)
268  {
269  //Drop packets that are waiting for address resolution
270  for(i = 0; i < entry->queueSize; i++)
271  {
272  //Release memory buffer
273  netBufferFree(entry->queue[i].buffer);
274  }
275  }
276 
277  //The queue is now empty
278  entry->queueSize = 0;
279 }
280 
281 #endif
@ ARP_STATE_STALE
Definition: arp.h:131
void arpFlushCache(NetInterface *interface)
Flush ARP cache.
Definition: arp_cache.c:188
@ ARP_STATE_NONE
Definition: arp.h:128
error_t ethSendFrame(NetInterface *interface, const MacAddr *destAddr, uint16_t type, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send an Ethernet frame.
Definition: ethernet.c:399
size_t offset
Offset to the first byte of the packet.
Definition: arp.h:179
@ ETH_TYPE_IPV4
Definition: ethernet.h:164
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:297
NetBuffer * buffer
Packet waiting for address resolution.
Definition: arp.h:178
uint_t queueSize
Number of queued packets.
Definition: arp.h:197
Helper functions for IPv4.
#define ARP_CACHE_SIZE
Definition: arp.h:46
void arpFlushQueuedPackets(NetInterface *interface, ArpCacheEntry *entry)
Flush packet queue.
Definition: arp_cache.c:262
void arpChangeState(ArpCacheEntry *entry, ArpState newState)
Update ARP cache entry state.
Definition: arp_cache.c:55
MacAddr macAddr
Link layer address associated with the IPv4 address.
Definition: arp.h:192
@ ARP_STATE_INCOMPLETE
Definition: arp.h:129
#define NetInterface
Definition: net.h:36
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
ArpState
ARP cache entry states.
Definition: arp.h:127
void ipv4UpdateOutStats(NetInterface *interface, Ipv4Addr destIpAddr, size_t length)
Update IPv4 output statistics.
Definition: ipv4_misc.c:875
uint8_t length
Definition: tcp.h:368
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
ArpState state
Reachability state.
Definition: arp.h:190
uint32_t systime_t
System time.
void arpSendQueuedPackets(NetInterface *interface, ArpCacheEntry *entry)
Send packets that are waiting for address resolution.
Definition: arp_cache.c:222
uint32_t time
ArpCacheEntry * arpFindEntry(NetInterface *interface, Ipv4Addr ipAddr)
Search the ARP cache for a given IPv4 address.
Definition: arp_cache.c:156
ArpCacheEntry * arpCreateEntry(NetInterface *interface)
Create a new entry in the ARP cache.
Definition: arp_cache.c:74
@ ARP_STATE_PERMANENT
Definition: arp.h:134
systime_t timestamp
Time stamp to manage entry lifetime.
Definition: arp.h:193
ARP cache entry.
Definition: arp.h:189
ArpQueueItem queue[ARP_MAX_PENDING_PACKETS]
Packets waiting for address resolution to complete.
Definition: arp.h:196
NetTxAncillary ancillary
Additional options.
Definition: arp.h:180
Ipv4Addr ipAddr
Definition: ipcp.h:105
ARP cache management.
ARP queue item.
Definition: arp.h:177
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:135
TCP/IP stack core.
Ipv4Addr ipAddr
Unicast IPv4 address.
Definition: arp.h:191
Debugging facilities.
systime_t osGetSystemTime(void)
Retrieve system time.