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