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