arp.c
Go to the documentation of this file.
1 /**
2  * @file arp.c
3  * @brief ARP (Address Resolution Protocol)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 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 for
31  * more details
32  *
33  * @author Oryx Embedded SARL (www.oryx-embedded.com)
34  * @version 2.6.0
35  **/
36 
37 //Switch to the appropriate trace level
38 #define TRACE_LEVEL ARP_TRACE_LEVEL
39 
40 //Dependencies
41 #include "core/net.h"
42 #include "core/ethernet.h"
43 #include "ipv4/arp.h"
44 #include "ipv4/arp_cache.h"
45 #include "ipv4/ipv4_misc.h"
46 #include "debug.h"
47 
48 //Check TCP/IP stack configuration
49 #if (IPV4_SUPPORT == ENABLED && ETH_SUPPORT == ENABLED)
50 
51 
52 /**
53  * @brief ARP cache initialization
54  * @param[in] interface Underlying network interface
55  * @return Error code
56  **/
57 
59 {
60  //Enable ARP protocol
61  interface->enableArp = TRUE;
62  //Set ARP reachable time
63  interface->arpReachableTime = ARP_REACHABLE_TIME;
64  //Set ARP probe timeout
65  interface->arpProbeTimeout = ARP_PROBE_TIMEOUT;
66 
67  //Initialize the ARP cache
68  osMemset(interface->arpCache, 0, sizeof(interface->arpCache));
69 
70  //Successful initialization
71  return NO_ERROR;
72 }
73 
74 
75 /**
76  * @brief Enable address resolution using ARP
77  * @param[in] interface Underlying network interface
78  * @param[in] enable This flag specifies whether the host is allowed to send
79  * ARP requests and respond to incoming ARP requests. When the flag is set
80  * to FALSE, the host relies exclusively on static ARP entries to map IPv4
81  * addresses into MAC addresses and silently drop incoming ARP requests
82  * @return Error code
83  **/
84 
85 error_t arpEnable(NetInterface *interface, bool_t enable)
86 {
87  //Check parameters
88  if(interface == NULL)
90 
91  //Get exclusive access
92  netLock(interface->netContext);
93 
94  //Enable or disable ARP protocol
95  interface->enableArp = enable;
96 
97  //If ARP is disabled then flush dynamic entries from the ARP cache
98  if(!enable)
99  {
100  arpFlushCache(interface);
101  }
102 
103  //Release exclusive access
104  netUnlock(interface->netContext);
105 
106  //Successful processing
107  return NO_ERROR;
108 }
109 
110 
111 /**
112  * @brief Configure the ARP reachable time
113  * @param[in] interface Underlying network interface
114  * @param[in] reachableTime The time, in milliseconds, a node assumes a
115  * neighbor is reachable
116  * @return Error code
117  **/
118 
120 {
121  uint_t i;
122  ArpCacheEntry *entry;
123 
124  //Check parameters
125  if(interface == NULL || reachableTime == 0)
127 
128  //Get exclusive access
129  netLock(interface->netContext);
130 
131  //Save ARP reachable time
132  interface->arpReachableTime = reachableTime;
133 
134  //Go through ARP cache
135  for(i = 0; i < ARP_CACHE_SIZE; i++)
136  {
137  //Point to the current entry
138  entry = &interface->arpCache[i];
139 
140  //Check the state of the ARP entry
141  if(entry->state == ARP_STATE_REACHABLE)
142  {
143  //Adjust the reachable time, if necessary
144  if(entry->timeout > reachableTime)
145  {
146  entry->timeout = reachableTime;
147  }
148  }
149  }
150 
151  //Release exclusive access
152  netUnlock(interface->netContext);
153 
154  //Successful processing
155  return NO_ERROR;
156 }
157 
158 
159 /**
160  * @brief Configure the time interval between subsequent ARP probes
161  * @param[in] interface Underlying network interface
162  * @param[in] probeTimeout The time, in milliseconds, between subsequent
163  * retransmissions of probes
164  * @return Error code
165  **/
166 
168 {
169  uint_t i;
170  ArpCacheEntry *entry;
171 
172  //Check parameters
173  if(interface == NULL || probeTimeout == 0)
175 
176  //Get exclusive access
177  netLock(interface->netContext);
178 
179  //Save ARP probe timeout
180  interface->arpProbeTimeout = probeTimeout;
181 
182  //Go through ARP cache
183  for(i = 0; i < ARP_CACHE_SIZE; i++)
184  {
185  //Point to the current entry
186  entry = &interface->arpCache[i];
187 
188  //Check the state of the ARP entry
189  if(entry->state == ARP_STATE_PROBE)
190  {
191  //Adjust the probe timeout, if necessary
192  if(entry->timeout > probeTimeout)
193  {
194  entry->timeout = probeTimeout;
195  }
196  }
197  }
198 
199  //Release exclusive access
200  netUnlock(interface->netContext);
201 
202  //Successful processing
203  return NO_ERROR;
204 }
205 
206 
207 /**
208  * @brief Add a static entry in the ARP cache
209  * @param[in] interface Underlying network interface
210  * @param[in] ipAddr IPv4 address
211  * @param[in] macAddr MAC address
212  * @return Error code
213  **/
214 
216  const MacAddr *macAddr)
217 {
218  error_t error;
219  ArpCacheEntry *entry;
220 
221  //Check parameters
222  if(interface == NULL || macAddr == NULL)
224 
225  //Get exclusive access
226  netLock(interface->netContext);
227 
228  //Search the ARP cache for the specified IPv4 address
229  entry = arpFindEntry(interface, ipAddr);
230 
231  //Check whether a matching entry exists
232  if(entry != NULL)
233  {
234  //Check the state of the ARP entry
235  if(entry->state == ARP_STATE_INCOMPLETE)
236  {
237  //Record the corresponding MAC address
238  entry->macAddr = *macAddr;
239  //Send all the packets that are pending for transmission
240  arpSendQueuedPackets(interface, entry);
241  }
242  }
243  else
244  {
245  //Create a new entry in the ARP cache
246  entry = arpCreateEntry(interface);
247  }
248 
249  //ARP cache entry successfully created?
250  if(entry != NULL)
251  {
252  //Record the IPv4 address and the corresponding MAC address
253  entry->ipAddr = ipAddr;
254  entry->macAddr = *macAddr;
255 
256  //Unused parameters
257  entry->timeout = 0;
258  entry->retransmitCount = 0;
259  entry->queueSize = 0;
260 
261  //Update entry state
263 
264  //Successful processing
265  error = NO_ERROR;
266  }
267  else
268  {
269  //Failed to create ARP cache entry
270  error = ERROR_OUT_OF_RESOURCES;
271  }
272 
273  //Release exclusive access
274  netUnlock(interface->netContext);
275 
276  //Return status code
277  return error;
278 }
279 
280 
281 /**
282  * @brief Remove a static entry from the ARP cache
283  * @param[in] interface Underlying network interface
284  * @param[in] ipAddr IPv4 address
285  * @return Error code
286  **/
287 
289 {
290  error_t error;
291  ArpCacheEntry *entry;
292 
293  //Check parameters
294  if(interface == NULL)
296 
297  //Get exclusive access
298  netLock(interface->netContext);
299 
300  //Search the ARP cache for the specified IPv4 address
301  entry = arpFindEntry(interface, ipAddr);
302 
303  //Check whether a matching entry has been found
304  if(entry != NULL && entry->state == ARP_STATE_PERMANENT)
305  {
306  //Delete ARP entry
308  //Successful processing
309  error = NO_ERROR;
310  }
311  else
312  {
313  //No matching entry in ARP cache
314  error = ERROR_NOT_FOUND;
315  }
316 
317  //Release exclusive access
318  netUnlock(interface->netContext);
319 
320  //Return status code
321  return error;
322 }
323 
324 
325 /**
326  * @brief Address resolution using ARP protocol
327  * @param[in] interface Underlying network interface
328  * @param[in] ipAddr IPv4 address
329  * @param[in] macAddr Physical address matching the specified IPv4 address
330  * @return Error code
331  **/
332 
334 {
335  error_t error;
336  ArpCacheEntry *entry;
337 
338  //Search the ARP cache for the specified IPv4 address
339  entry = arpFindEntry(interface, ipAddr);
340 
341  //Check whether a matching entry has been found
342  if(entry != NULL)
343  {
344  //Check the state of the ARP entry
345  if(entry->state == ARP_STATE_INCOMPLETE)
346  {
347  //The address resolution is already in progress
348  error = ERROR_IN_PROGRESS;
349  }
350  else if(entry->state == ARP_STATE_STALE)
351  {
352  //Copy the MAC address associated with the specified IPv4 address
353  *macAddr = entry->macAddr;
354 
355  //Delay before sending the first probe
357  //Switch to the DELAY state
359 
360  //Successful address resolution
361  error = NO_ERROR;
362  }
363  else
364  {
365  //Copy the MAC address associated with the specified IPv4 address
366  *macAddr = entry->macAddr;
367 
368  //Successful address resolution
369  error = NO_ERROR;
370  }
371  }
372  else
373  {
374  //Check whether ARP is enabled
375  if(interface->enableArp)
376  {
377  //If no entry exists, then create a new one
378  entry = arpCreateEntry(interface);
379 
380  //ARP cache entry successfully created?
381  if(entry != NULL)
382  {
383  //Record the IPv4 address whose MAC address is unknown
384  entry->ipAddr = ipAddr;
385 
386  //Reset retransmission counter
387  entry->retransmitCount = 0;
388  //No packet are pending in the transmit queue
389  entry->queueSize = 0;
390 
391  //Send an ARP request
392  arpSendRequest(interface, entry->ipAddr, &MAC_BROADCAST_ADDR);
393 
394  //Set timeout value
395  entry->timeout = ARP_REQUEST_TIMEOUT;
396  //Enter INCOMPLETE state
398 
399  //The address resolution is in progress
400  error = ERROR_IN_PROGRESS;
401  }
402  else
403  {
404  //Failed to create ARP cache entry
405  error = ERROR_OUT_OF_RESOURCES;
406  }
407  }
408  else
409  {
410  //ARP is disabled
411  error = ERROR_INVALID_ADDRESS;
412  }
413  }
414 
415  //Return status code
416  return error;
417 }
418 
419 
420 /**
421  * @brief Enqueue an IPv4 packet waiting for address resolution
422  * @param[in] interface Underlying network interface
423  * @param[in] ipAddr IPv4 address of the destination host
424  * @param[in] buffer Multi-part buffer containing the packet to be enqueued
425  * @param[in] offset Offset to the first byte of the packet
426  * @param[in] ancillary Additional options passed to the stack along with
427  * the packet
428  * @return Error code
429  **/
430 
432  NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
433 {
434  error_t error;
435  uint_t i;
436  size_t length;
437  ArpCacheEntry *entry;
438 
439  //Retrieve the length of the multi-part buffer
440  length = netBufferGetLength(buffer);
441 
442  //Search the ARP cache for the specified IPv4 address
443  entry = arpFindEntry(interface, ipAddr);
444 
445  //Check whether a matching entry exists
446  if(entry != NULL)
447  {
448  //Check the state of the ARP entry
449  if(entry->state == ARP_STATE_INCOMPLETE)
450  {
451  //Check whether the packet queue is full
452  if(entry->queueSize >= ARP_MAX_PENDING_PACKETS)
453  {
454  //When the queue overflows, the new arrival should replace the oldest entry
455  netBufferFree(entry->queue[0].buffer);
456 
457  //Make room for the new packet
458  for(i = 1; i < ARP_MAX_PENDING_PACKETS; i++)
459  {
460  entry->queue[i - 1] = entry->queue[i];
461  }
462 
463  //Adjust the number of pending packets
464  entry->queueSize--;
465  }
466 
467  //Index of the entry to be filled in
468  i = entry->queueSize;
469  //Allocate a memory buffer to store the packet
470  entry->queue[i].buffer = netBufferAlloc(length);
471 
472  //Successful memory allocation?
473  if(entry->queue[i].buffer != NULL)
474  {
475  //Copy the contents of the IPv4 packet
476  netBufferCopy(entry->queue[i].buffer, 0, buffer, 0, length);
477  //Offset to the first byte of the IPv4 header
478  entry->queue[i].offset = offset;
479  //Additional options passed to the stack along with the packet
480  entry->queue[i].ancillary = *ancillary;
481 
482  //Increment the number of queued packets
483  entry->queueSize++;
484  //The packet was successfully enqueued
485  error = NO_ERROR;
486  }
487  else
488  {
489  //Failed to allocate memory
490  error = ERROR_OUT_OF_MEMORY;
491  }
492  }
493  else
494  {
495  //The address is already resolved
496  error = ERROR_UNEXPECTED_STATE;
497  }
498  }
499  else
500  {
501  //No matching entry in ARP cache
502  error = ERROR_NOT_FOUND;
503  }
504 
505  //Return status code
506  return error;
507 }
508 
509 
510 /**
511  * @brief ARP timer handler
512  *
513  * This routine must be periodically called by the TCP/IP stack to
514  * manage ARP cache
515  *
516  * @param[in] interface Underlying network interface
517  **/
518 
519 void arpTick(NetInterface *interface)
520 {
521  uint_t i;
522  systime_t time;
523  ArpCacheEntry *entry;
524 
525  //Get current time
526  time = osGetSystemTime();
527 
528  //Go through ARP cache
529  for(i = 0; i < ARP_CACHE_SIZE; i++)
530  {
531  //Point to the current entry
532  entry = &interface->arpCache[i];
533 
534  //Check the state of the ARP entry
535  if(entry->state == ARP_STATE_PERMANENT)
536  {
537  //Static ARP entries are never updated
538  }
539  else if(entry->state == ARP_STATE_INCOMPLETE)
540  {
541  //The request timed out?
542  if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
543  {
544  //Increment retransmission counter
545  entry->retransmitCount++;
546 
547  //Check whether the maximum number of retransmissions has been exceeded
548  if(entry->retransmitCount < ARP_MAX_REQUESTS)
549  {
550  //Retransmit ARP request
551  arpSendRequest(interface, entry->ipAddr, &MAC_BROADCAST_ADDR);
552 
553  //Save the time at which the packet was sent
554  entry->timestamp = time;
555  //Set timeout value
556  entry->timeout = ARP_REQUEST_TIMEOUT;
557  }
558  else
559  {
560  //Drop packets that are waiting for address resolution
561  arpFlushQueuedPackets(interface, entry);
562 
563  //The entry should be deleted since address resolution has failed
565  }
566  }
567  }
568  else if(entry->state == ARP_STATE_REACHABLE)
569  {
570  //Periodically time out ARP cache entries
571  if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
572  {
573  //Enter STALE state
575  }
576  }
577  else if(entry->state == ARP_STATE_STALE)
578  {
579  //The neighbor is no longer known to be reachable but until traffic
580  //is sent to the neighbor, no attempt should be made to verify its
581  //reachability
582  }
583  else if(entry->state == ARP_STATE_DELAY)
584  {
585  //Wait for the specified delay before sending the first probe
586  if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
587  {
588  //Reset retransmission counter
589  entry->retransmitCount = 0;
590 
591  //Send a point-to-point ARP request to the host
592  arpSendRequest(interface, entry->ipAddr, &entry->macAddr);
593 
594  //Set timeout value
595  entry->timeout = interface->arpProbeTimeout;
596  //Switch to the PROBE state
598  }
599  }
600  else if(entry->state == ARP_STATE_PROBE)
601  {
602  //The request timed out?
603  if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
604  {
605  //Increment retransmission counter
606  entry->retransmitCount++;
607 
608  //Check whether the maximum number of retransmissions has been
609  //exceeded
610  if(entry->retransmitCount < ARP_MAX_PROBES)
611  {
612  //Send a point-to-point ARP request to the host
613  arpSendRequest(interface, entry->ipAddr, &entry->macAddr);
614 
615  //Save the time at which the packet was sent
616  entry->timestamp = time;
617  //Set timeout value
618  entry->timeout = interface->arpProbeTimeout;
619  }
620  else
621  {
622  //The entry should be deleted since the host is not reachable
623  //anymore
625  }
626  }
627  }
628  else
629  {
630  //Just for sanity
632  }
633  }
634 }
635 
636 
637 /**
638  * @brief Incoming ARP packet processing
639  * @param[in] interface Underlying network interface
640  * @param[in] arpPacket Incoming ARP packet
641  * @param[in] length Packet length
642  **/
643 
644 void arpProcessPacket(NetInterface *interface, ArpPacket *arpPacket,
645  size_t length)
646 {
647  uint_t i;
648  bool_t validTarget;
649  Ipv4AddrEntry *addrEntry;
650  NetInterface *logicalInterface;
651 
652  //Discard invalid ARP packets
653  if(length < sizeof(ArpPacket))
654  return;
655 
656  //Debug message
657  TRACE_INFO("ARP packet received (%" PRIuSIZE " bytes)...\r\n", length);
658  //Dump ARP packet contents for debugging purpose
659  arpDumpPacket(arpPacket);
660 
661  //Make sure the hardware type is valid
662  if(arpPacket->hrd != HTONS(ARP_HARDWARE_TYPE_ETH))
663  return;
664 
665  //Make sure the protocol type is valid
666  if(arpPacket->pro != HTONS(ARP_PROTOCOL_TYPE_IPV4))
667  return;
668 
669  //Check the length of the hardware address
670  if(arpPacket->hln != sizeof(MacAddr))
671  return;
672 
673  //Check the length of the protocol address
674  if(arpPacket->pln != sizeof(Ipv4Addr))
675  return;
676 
677  //The target protocol address must a valid address assigned to the interface
678  //or a tentative address whose uniqueness on a link is being verified
679  validTarget = FALSE;
680 
681  //Loop through the list of IPv4 addresses assigned to the interface
682  for(i = 0; i < IPV4_ADDR_LIST_SIZE; i++)
683  {
684  //Point to the current entry
685  addrEntry = &interface->ipv4Context.addrList[i];
686 
687  //Valid entry?
688  if(addrEntry->state != IPV4_ADDR_STATE_INVALID)
689  {
690  //Check whether the sender protocol address matches the IP address
691  //assigned to the interface
692  if(addrEntry->addr == arpPacket->spa)
693  {
694  //Tentative address?
695  if(addrEntry->state == IPV4_ADDR_STATE_TENTATIVE)
696  {
697  //If the host receives any ARP packet where the sender IP
698  //address is the address being probed for, then this is a
699  //conflicting ARP packet
700  addrEntry->conflict = TRUE;
701  //Exit immediately
702  return;
703  }
704  else
705  {
706  //Point to the logical interface
707  logicalInterface = nicGetLogicalInterface(interface);
708 
709  //If the sender hardware address does not match the hardware
710  //address of that interface, then this is a conflicting ARP
711  //packet
712  if(!macCompAddr(&arpPacket->sha, &logicalInterface->macAddr))
713  {
714  //An address conflict has been detected...
715  addrEntry->conflict = TRUE;
716  //Exit immediately
717  return;
718  }
719  }
720  }
721 
722  //Check whether the target protocol address matches an IP address
723  //assigned to the interface
724  if(addrEntry->addr == arpPacket->tpa)
725  {
726  validTarget = TRUE;
727  }
728  }
729  }
730 
731  //Valid target protocol address?
732  if(validTarget)
733  {
734  //Check operation code
735  switch(ntohs(arpPacket->op))
736  {
737  //ARP request?
739  //Process incoming ARP request
740  arpProcessRequest(interface, arpPacket);
741  break;
742 
743  //ARP reply?
745  //Process incoming ARP reply
746  arpProcessReply(interface, arpPacket);
747  break;
748 
749  //Unknown operation code?
750  default:
751  //Debug message
752  TRACE_INFO("Unknown operation code!\r\n");
753  //Discard incoming packet
754  break;
755  }
756  }
757 }
758 
759 
760 /**
761  * @brief Incoming ARP request processing
762  * @param[in] interface Underlying network interface
763  * @param[in] arpRequest Incoming ARP request
764  **/
765 
766 void arpProcessRequest(NetInterface *interface, ArpPacket *arpRequest)
767 {
768  uint_t i;
769  bool_t validTarget;
770  Ipv4AddrEntry *addrEntry;
771  NetInterface *logicalInterface;
772 
773  //Debug message
774  TRACE_INFO("ARP Request received...\r\n");
775 
776  //Check sender protocol address
777  if(ipv4IsBroadcastAddr(interface, arpRequest->spa) ||
778  ipv4IsMulticastAddr(arpRequest->spa))
779  {
780  return;
781  }
782 
783  //Initialize flag
784  validTarget = TRUE;
785 
786  //Loop through the list of IPv4 addresses assigned to the interface
787  for(i = 0; i < IPV4_ADDR_LIST_SIZE; i++)
788  {
789  //Point to the current entry
790  addrEntry = &interface->ipv4Context.addrList[i];
791 
792  //Tentative address?
793  if(addrEntry->state == IPV4_ADDR_STATE_TENTATIVE)
794  {
795  //Check whether the target IP address is an address being probed for
796  if(addrEntry->addr == arpRequest->tpa)
797  {
798  //The target protocol address is a tentative address
799  validTarget = FALSE;
800 
801  //ARP probe received?
802  if(arpRequest->spa == IPV4_UNSPECIFIED_ADDR)
803  {
804  //Point to the logical interface
805  logicalInterface = nicGetLogicalInterface(interface);
806 
807  //If the sender hardware address does not match the hardware
808  //address of that interface, then this is a conflicting ARP
809  //packet
810  if(!macCompAddr(&arpRequest->sha, &logicalInterface->macAddr))
811  {
812  //An address conflict has been detected...
813  addrEntry->conflict = TRUE;
814  }
815  }
816  }
817  }
818  }
819 
820  //In all cases, the host must not respond to an ARP request for an address
821  //being probed for
822  if(validTarget && interface->enableArp)
823  {
824  //Send ARP reply
825  arpSendReply(interface, arpRequest->tpa, arpRequest->spa,
826  &arpRequest->sha);
827  }
828 }
829 
830 
831 /**
832  * @brief Incoming ARP reply processing
833  * @param[in] interface Underlying network interface
834  * @param[in] arpReply Incoming ARP reply
835  **/
836 
837 void arpProcessReply(NetInterface *interface, ArpPacket *arpReply)
838 {
839  ArpCacheEntry *entry;
840 
841  //Debug message
842  TRACE_INFO("ARP Reply received...\r\n");
843 
844  //Check sender protocol address
845  if(arpReply->spa == IPV4_UNSPECIFIED_ADDR ||
846  ipv4IsBroadcastAddr(interface, arpReply->spa) ||
847  ipv4IsMulticastAddr(arpReply->spa))
848  {
849  return;
850  }
851 
852  //Check sender hardware address
853  if(macCompAddr(&arpReply->sha, &MAC_UNSPECIFIED_ADDR) ||
854  macCompAddr(&arpReply->sha, &MAC_BROADCAST_ADDR) ||
855  macIsMulticastAddr(&arpReply->sha))
856  {
857  return;
858  }
859 
860  //Check whether the target IP address is an address being probed for
861  if(ipv4IsTentativeAddr(interface, arpReply->tpa))
862  return;
863 
864  //Search the ARP cache for the specified IPv4 address
865  entry = arpFindEntry(interface, arpReply->spa);
866 
867  //Check whether a matching entry has been found
868  if(entry != NULL)
869  {
870  //Check the state of the ARP entry
871  if(entry->state == ARP_STATE_INCOMPLETE)
872  {
873  //Record the corresponding MAC address
874  entry->macAddr = arpReply->sha;
875 
876  //Send all the packets that are pending for transmission
877  arpSendQueuedPackets(interface, entry);
878 
879  //The validity of the ARP entry is limited in time
880  entry->timeout = interface->arpReachableTime;
881  //Switch to the REACHABLE state
883  }
884  else if(entry->state == ARP_STATE_REACHABLE)
885  {
886  //Different link-layer address than cached?
887  if(!macCompAddr(&arpReply->sha, &entry->macAddr))
888  {
889  //Enter STALE state
891  }
892  }
893  else if(entry->state == ARP_STATE_PROBE)
894  {
895  //Record IPv4/MAC address pair
896  entry->ipAddr = arpReply->spa;
897  entry->macAddr = arpReply->sha;
898 
899  //The validity of the ARP entry is limited in time
900  entry->timeout = interface->arpReachableTime;
901  //Switch to the REACHABLE state
903  }
904  else
905  {
906  //Static ARP entries are never updated
907  }
908  }
909 }
910 
911 
912 /**
913  * @brief Send ARP probe
914  * @param[in] interface Underlying network interface
915  * @param[in] targetIpAddr Target IPv4 address
916  * @return Error code
917  **/
918 
919 error_t arpSendProbe(NetInterface *interface, Ipv4Addr targetIpAddr)
920 {
921  error_t error;
922  size_t offset;
923  NetBuffer *buffer;
924  ArpPacket *arpRequest;
925  NetInterface *logicalInterface;
926  NetTxAncillary ancillary;
927 
928  //Point to the logical interface
929  logicalInterface = nicGetLogicalInterface(interface);
930 
931  //Allocate a memory buffer to hold an ARP packet
932  buffer = ethAllocBuffer(sizeof(ArpPacket), &offset);
933  //Failed to allocate buffer?
934  if(buffer == NULL)
935  return ERROR_OUT_OF_MEMORY;
936 
937  //Point to the beginning of the ARP packet
938  arpRequest = netBufferAt(buffer, offset, 0);
939 
940  //Format ARP request
941  arpRequest->hrd = htons(ARP_HARDWARE_TYPE_ETH);
942  arpRequest->pro = htons(ARP_PROTOCOL_TYPE_IPV4);
943  arpRequest->hln = sizeof(MacAddr);
944  arpRequest->pln = sizeof(Ipv4Addr);
945  arpRequest->op = htons(ARP_OPCODE_ARP_REQUEST);
946  arpRequest->sha = logicalInterface->macAddr;
947  arpRequest->spa = IPV4_UNSPECIFIED_ADDR;
948  arpRequest->tha = MAC_UNSPECIFIED_ADDR;
949  arpRequest->tpa = targetIpAddr;
950 
951  //Debug message
952  TRACE_INFO("Sending ARP Probe (%" PRIuSIZE " bytes)...\r\n", sizeof(ArpPacket));
953  //Dump ARP packet contents for debugging purpose
954  arpDumpPacket(arpRequest);
955 
956  //Additional options can be passed to the stack along with the packet
957  ancillary = NET_DEFAULT_TX_ANCILLARY;
958 
959  //Send ARP request
960  error = ethSendFrame(interface, &MAC_BROADCAST_ADDR, ETH_TYPE_ARP, buffer,
961  offset, &ancillary);
962 
963  //Free previously allocated memory
964  netBufferFree(buffer);
965 
966  //Return status code
967  return error;
968 }
969 
970 
971 /**
972  * @brief Send ARP request
973  * @param[in] interface Underlying network interface
974  * @param[in] targetIpAddr Target IPv4 address
975  * @param[in] destMacAddr Destination MAC address
976  * @return Error code
977  **/
978 
979 error_t arpSendRequest(NetInterface *interface, Ipv4Addr targetIpAddr,
980  const MacAddr *destMacAddr)
981 {
982  error_t error;
983  size_t offset;
984  NetBuffer *buffer;
985  ArpPacket *arpRequest;
986  Ipv4Addr senderIpAddr;
987  NetInterface *logicalInterface;
988  NetTxAncillary ancillary;
989 
990  //Point to the logical interface
991  logicalInterface = nicGetLogicalInterface(interface);
992 
993  //Select the most appropriate sender IP address to be used
994  error = ipv4SelectSourceAddr(interface->netContext, &interface, targetIpAddr,
995  &senderIpAddr);
996  //No address assigned to the interface?
997  if(error)
998  return error;
999 
1000  //Allocate a memory buffer to hold an ARP packet
1001  buffer = ethAllocBuffer(sizeof(ArpPacket), &offset);
1002  //Failed to allocate buffer?
1003  if(buffer == NULL)
1004  return ERROR_OUT_OF_MEMORY;
1005 
1006  //Point to the beginning of the ARP packet
1007  arpRequest = netBufferAt(buffer, offset, 0);
1008 
1009  //Format ARP request
1010  arpRequest->hrd = htons(ARP_HARDWARE_TYPE_ETH);
1011  arpRequest->pro = htons(ARP_PROTOCOL_TYPE_IPV4);
1012  arpRequest->hln = sizeof(MacAddr);
1013  arpRequest->pln = sizeof(Ipv4Addr);
1014  arpRequest->op = htons(ARP_OPCODE_ARP_REQUEST);
1015  arpRequest->sha = logicalInterface->macAddr;
1016  arpRequest->spa = senderIpAddr;
1017  arpRequest->tha = MAC_UNSPECIFIED_ADDR;
1018  arpRequest->tpa = targetIpAddr;
1019 
1020  //Debug message
1021  TRACE_INFO("Sending ARP Request (%" PRIuSIZE " bytes)...\r\n", sizeof(ArpPacket));
1022  //Dump ARP packet contents for debugging purpose
1023  arpDumpPacket(arpRequest);
1024 
1025  //Additional options can be passed to the stack along with the packet
1026  ancillary = NET_DEFAULT_TX_ANCILLARY;
1027 
1028  //Send ARP request
1029  error = ethSendFrame(interface, destMacAddr, ETH_TYPE_ARP, buffer, offset,
1030  &ancillary);
1031 
1032  //Free previously allocated memory
1033  netBufferFree(buffer);
1034 
1035  //Return status code
1036  return error;
1037 }
1038 
1039 
1040 /**
1041  * @brief Send ARP reply
1042  * @param[in] interface Underlying network interface
1043  * @param[in] senderIpAddr Sender Ipv4 address
1044  * @param[in] targetIpAddr Target IPv4 address
1045  * @param[in] targetMacAddr Target MAC address
1046  * @return Error code
1047  **/
1048 
1049 error_t arpSendReply(NetInterface *interface, Ipv4Addr senderIpAddr,
1050  Ipv4Addr targetIpAddr, const MacAddr *targetMacAddr)
1051 {
1052  error_t error;
1053  size_t offset;
1054  NetBuffer *buffer;
1055  ArpPacket *arpReply;
1056  NetInterface *logicalInterface;
1057  NetTxAncillary ancillary;
1058 
1059  //Point to the logical interface
1060  logicalInterface = nicGetLogicalInterface(interface);
1061 
1062  //Allocate a memory buffer to hold an ARP packet
1063  buffer = ethAllocBuffer(sizeof(ArpPacket), &offset);
1064  //Failed to allocate buffer?
1065  if(buffer == NULL)
1066  return ERROR_OUT_OF_MEMORY;
1067 
1068  //Point to the beginning of the ARP packet
1069  arpReply = netBufferAt(buffer, offset, 0);
1070 
1071  //Format ARP reply
1072  arpReply->hrd = htons(ARP_HARDWARE_TYPE_ETH);
1073  arpReply->pro = htons(ETH_TYPE_IPV4);
1074  arpReply->hln = sizeof(MacAddr);
1075  arpReply->pln = sizeof(Ipv4Addr);
1076  arpReply->op = htons(ARP_OPCODE_ARP_REPLY);
1077  arpReply->sha = logicalInterface->macAddr;
1078  arpReply->spa = senderIpAddr;
1079  arpReply->tha = *targetMacAddr;
1080  arpReply->tpa = targetIpAddr;
1081 
1082  //Debug message
1083  TRACE_INFO("Sending ARP Reply (%" PRIuSIZE " bytes)...\r\n", sizeof(ArpPacket));
1084  //Dump ARP packet contents for debugging purpose
1085  arpDumpPacket(arpReply);
1086 
1087  //Additional options can be passed to the stack along with the packet
1088  ancillary = NET_DEFAULT_TX_ANCILLARY;
1089 
1090  //Send ARP reply
1091  error = ethSendFrame(interface, targetMacAddr, ETH_TYPE_ARP, buffer, offset,
1092  &ancillary);
1093 
1094  //Free previously allocated memory
1095  netBufferFree(buffer);
1096 
1097  //Return status code
1098  return error;
1099 }
1100 
1101 
1102 /**
1103  * @brief Dump ARP packet for debugging purpose
1104  * @param[in] arpPacket ARP header
1105  **/
1106 
1107 void arpDumpPacket(const ArpPacket *arpPacket)
1108 {
1109  //Dump ARP packet contents
1110  TRACE_DEBUG(" Hardware Type (hrd) = 0x%04" PRIX16 "\r\n", ntohs(arpPacket->hrd));
1111  TRACE_DEBUG(" Protocol Type (pro) = 0x%04" PRIX16 "\r\n", ntohs(arpPacket->pro));
1112  TRACE_DEBUG(" Hardware Address Length (hln) = %" PRIu8 "\r\n", arpPacket->hln);
1113  TRACE_DEBUG(" Protocol Address Length (pln) = %" PRIu8 "\r\n", arpPacket->pln);
1114  TRACE_DEBUG(" Opcode (op) = %" PRIu16 "\r\n", ntohs(arpPacket->op));
1115  TRACE_DEBUG(" Sender Hardware Address (sha) = %s\r\n", macAddrToString(&arpPacket->sha, NULL));
1116  TRACE_DEBUG(" Sender Protocol Address (spa) = %s\r\n", ipv4AddrToString(arpPacket->spa, NULL));
1117  TRACE_DEBUG(" Target Hardware Address (tha)= %s\r\n", macAddrToString(&arpPacket->tha, NULL));
1118  TRACE_DEBUG(" Target Protocol Address (tpa) = %s\r\n", ipv4AddrToString(arpPacket->tpa, NULL));
1119 }
1120 
1121 #endif
#define ipv4IsMulticastAddr(ipAddr)
Definition: ipv4.h:186
#define htons(value)
Definition: cpu_endian.h:413
@ ARP_STATE_STALE
Definition: arp.h:131
void netUnlock(NetContext *context)
Release exclusive access to the core of the TCP/IP stack.
Definition: net.c:319
int bool_t
Definition: compiler_port.h:63
@ ERROR_NOT_FOUND
Definition: error.h:148
Ipv4Addr addr
IPv4 address.
Definition: ipv4.h:411
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:70
#define ARP_MAX_PENDING_PACKETS
Definition: arp.h:53
void arpFlushCache(NetInterface *interface)
Flush ARP cache.
Definition: arp_cache.c:188
error_t arpAddStaticEntry(NetInterface *interface, Ipv4Addr ipAddr, const MacAddr *macAddr)
Add a static entry in the ARP cache.
Definition: arp.c:215
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
bool_t ipv4IsBroadcastAddr(NetInterface *interface, Ipv4Addr ipAddr)
Check whether an IPv4 address is a broadcast address.
Definition: ipv4_misc.c:475
#define TRUE
Definition: os_port.h:50
@ ARP_STATE_REACHABLE
Definition: arp.h:130
@ ARP_STATE_NONE
Definition: arp.h:128
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
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:406
size_t offset
Offset to the first byte of the packet.
Definition: arp.h:179
error_t arpEnqueuePacket(NetInterface *interface, Ipv4Addr ipAddr, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Enqueue an IPv4 packet waiting for address resolution.
Definition: arp.c:431
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
Ipv4AddrState state
IPv4 address state.
Definition: ipv4.h:412
@ ARP_STATE_DELAY
Definition: arp.h:132
error_t arpInit(NetInterface *interface)
ARP cache initialization.
Definition: arp.c:58
@ ETH_TYPE_IPV4
Definition: ethernet.h:164
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define timeCompare(t1, t2)
Definition: os_port.h:40
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:322
void arpTick(NetInterface *interface)
ARP timer handler.
Definition: arp.c:519
NetBuffer * buffer
Packet waiting for address resolution.
Definition: arp.h:178
Ethernet.
#define ARP_MAX_REQUESTS
Definition: arp.h:60
#define ARP_HARDWARE_TYPE_ETH
Definition: arp.h:101
void arpProcessRequest(NetInterface *interface, ArpPacket *arpRequest)
Incoming ARP request processing.
Definition: arp.c:766
@ ERROR_IN_PROGRESS
Definition: error.h:214
uint_t queueSize
Number of queued packets.
Definition: arp.h:197
Helper functions for IPv4.
ArpPacket
Definition: arp.h:161
#define FALSE
Definition: os_port.h:46
#define ARP_CACHE_SIZE
Definition: arp.h:46
error_t arpSendReply(NetInterface *interface, Ipv4Addr senderIpAddr, Ipv4Addr targetIpAddr, const MacAddr *targetMacAddr)
Send ARP reply.
Definition: arp.c:1049
@ ARP_OPCODE_ARP_REQUEST
Definition: arp.h:117
void arpFlushQueuedPackets(NetInterface *interface, ArpCacheEntry *entry)
Flush packet queue.
Definition: arp_cache.c:262
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
void arpChangeState(ArpCacheEntry *entry, ArpState newState)
Update ARP cache entry state.
Definition: arp_cache.c:55
error_t
Error codes.
Definition: error.h:43
@ IPV4_ADDR_STATE_TENTATIVE
An address whose uniqueness on a link is being verified.
Definition: ipv4.h:227
MacAddr macAddr
Link layer address associated with the IPv4 address.
Definition: arp.h:192
void arpProcessReply(NetInterface *interface, ArpPacket *arpReply)
Incoming ARP reply processing.
Definition: arp.c:837
#define ARP_PROBE_TIMEOUT
Definition: arp.h:81
error_t arpRemoveStaticEntry(NetInterface *interface, Ipv4Addr ipAddr)
Remove a static entry from the ARP cache.
Definition: arp.c:288
@ ERROR_INVALID_ADDRESS
Definition: error.h:103
char_t * macAddrToString(const MacAddr *macAddr, char_t *str)
Convert a MAC address to a dash delimited string.
Definition: ethernet.c:926
error_t ipv4SelectSourceAddr(NetContext *context, NetInterface **interface, Ipv4Addr destAddr, Ipv4Addr *srcAddr)
IPv4 source address selection.
Definition: ipv4_misc.c:173
@ ARP_STATE_INCOMPLETE
Definition: arp.h:129
#define NetInterface
Definition: net.h:40
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
uint_t retransmitCount
Retransmission counter.
Definition: arp.h:195
bool_t ipv4IsTentativeAddr(NetInterface *interface, Ipv4Addr ipAddr)
Check whether an IPv4 address is a tentative address.
Definition: ipv4_misc.c:529
@ ETH_TYPE_ARP
Definition: ethernet.h:165
#define NetTxAncillary
Definition: net_misc.h:36
error_t netBufferCopy(NetBuffer *dest, size_t destOffset, const NetBuffer *src, size_t srcOffset, size_t length)
Copy data between multi-part buffers.
Definition: net_mem.c:522
#define TRACE_INFO(...)
Definition: debug.h:105
#define IPV4_ADDR_LIST_SIZE
Definition: ipv4.h:80
uint8_t length
Definition: tcp.h:375
void arpProcessPacket(NetInterface *interface, ArpPacket *arpPacket, size_t length)
Incoming ARP packet processing.
Definition: arp.c:644
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
IPv4 address entry.
Definition: ipv4.h:410
MacAddr
Definition: ethernet.h:197
error_t arpSendRequest(NetInterface *interface, Ipv4Addr targetIpAddr, const MacAddr *destMacAddr)
Send ARP request.
Definition: arp.c:979
NetBuffer * netBufferAlloc(size_t length)
Allocate a multi-part buffer.
Definition: net_mem.c:243
uint32_t systime_t
System time.
#define ntohs(value)
Definition: cpu_endian.h:421
void arpSendQueuedPackets(NetInterface *interface, ArpCacheEntry *entry)
Send packets that are waiting for address resolution.
Definition: arp_cache.c:222
#define TRACE_DEBUG(...)
Definition: debug.h:119
uint32_t time
void arpDumpPacket(const ArpPacket *arpPacket)
Dump ARP packet for debugging purpose.
Definition: arp.c:1107
ArpCacheEntry * arpFindEntry(NetInterface *interface, Ipv4Addr ipAddr)
Search the ARP cache for a given IPv4 address.
Definition: arp_cache.c:156
#define HTONS(value)
Definition: cpu_endian.h:410
@ ERROR_UNEXPECTED_STATE
Definition: error.h:99
ArpCacheEntry * arpCreateEntry(NetInterface *interface)
Create a new entry in the ARP cache.
Definition: arp_cache.c:74
error_t arpSetProbeTimout(NetInterface *interface, systime_t probeTimeout)
Configure the time interval between subsequent ARP probes.
Definition: arp.c:167
@ ARP_STATE_PERMANENT
Definition: arp.h:134
@ IPV4_ADDR_STATE_INVALID
An address that is not assigned to any interface.
Definition: ipv4.h:226
error_t arpSetReachableTime(NetInterface *interface, systime_t reachableTime)
Configure the ARP reachable time.
Definition: arp.c:119
#define ARP_REACHABLE_TIME
Definition: arp.h:88
systime_t timestamp
Timestamp to manage entry lifetime.
Definition: arp.h:193
uint32_t reachableTime
Definition: ndp.h:307
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
ARP cache entry.
Definition: arp.h:189
systime_t timeout
Timeout value.
Definition: arp.h:194
@ ARP_STATE_PROBE
Definition: arp.h:133
error_t arpEnable(NetInterface *interface, bool_t enable)
Enable address resolution using ARP.
Definition: arp.c:85
ArpQueueItem queue[ARP_MAX_PENDING_PACKETS]
Packets waiting for address resolution to complete.
Definition: arp.h:196
void netLock(NetContext *context)
Get exclusive access to the core of the TCP/IP stack.
Definition: net.c:307
NetTxAncillary ancillary
Additional options.
Definition: arp.h:180
void * netBufferAt(const NetBuffer *buffer, size_t offset, size_t length)
Returns a pointer to a data segment.
Definition: net_mem.c:418
Ipv4Addr ipAddr
Definition: ipcp.h:105
ARP cache management.
error_t arpResolve(NetInterface *interface, Ipv4Addr ipAddr, MacAddr *macAddr)
Address resolution using ARP protocol.
Definition: arp.c:333
bool_t conflict
Address conflict detected.
Definition: ipv4.h:413
@ ARP_OPCODE_ARP_REPLY
Definition: arp.h:118
#define ARP_PROTOCOL_TYPE_IPV4
Definition: arp.h:103
#define ARP_MAX_PROBES
Definition: arp.h:74
NetBuffer * ethAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an Ethernet frame.
Definition: ethernet.c:784
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
TCP/IP stack core.
NetInterface * nicGetLogicalInterface(NetInterface *interface)
Retrieve logical interface.
Definition: nic.c:51
char_t * ipv4AddrToString(Ipv4Addr ipAddr, char_t *str)
Convert a binary IPv4 address to dot-decimal notation.
Definition: ipv4.c:1468
#define ARP_REQUEST_TIMEOUT
Definition: arp.h:67
ARP (Address Resolution Protocol)
Ipv4Addr ipAddr
Unicast IPv4 address.
Definition: arp.h:191
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:51
#define ARP_DELAY_FIRST_PROBE_TIME
Definition: arp.h:95
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
error_t arpSendProbe(NetInterface *interface, Ipv4Addr targetIpAddr)
Send ARP probe.
Definition: arp.c:919
const MacAddr MAC_BROADCAST_ADDR
Definition: ethernet.c:53
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:128
systime_t osGetSystemTime(void)
Retrieve system time.