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-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * Address Resolution Protocol is used to determine the hardware address of
30  * a specific host when only its IPv4 address is known. Refer to RFC 826
31  *
32  * @author Oryx Embedded SARL (www.oryx-embedded.com)
33  * @version 2.4.4
34  **/
35 
36 //Switch to the appropriate trace level
37 #define TRACE_LEVEL ARP_TRACE_LEVEL
38 
39 //Dependencies
40 #include "core/net.h"
41 #include "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 
65  //Initialize the ARP cache
66  osMemset(interface->arpCache, 0, sizeof(interface->arpCache));
67 
68  //Successful initialization
69  return NO_ERROR;
70 }
71 
72 
73 /**
74  * @brief Enable address resolution using ARP
75  * @param[in] interface Underlying network interface
76  * @param[in] enable This flag specifies whether the host is allowed to send
77  * ARP requests and respond to incoming ARP requests. When the flag is set
78  * to FALSE, the host relies exclusively on static ARP entries to map IPv4
79  * addresses into MAC addresses and silently drop incoming ARP requests
80  * @return Error code
81  **/
82 
83 error_t arpEnable(NetInterface *interface, bool_t enable)
84 {
85  //Check parameters
86  if(interface == NULL)
88 
89  //Get exclusive access
91 
92  //Enable or disable ARP protocol
93  interface->enableArp = enable;
94 
95  //If ARP is disabled then flush dynamic entries from the ARP cache
96  if(!enable)
97  {
98  arpFlushCache(interface);
99  }
100 
101  //Release exclusive access
103 
104  //Successful processing
105  return NO_ERROR;
106 }
107 
108 
109 /**
110  * @brief Add a static entry in the ARP cache
111  * @param[in] interface Underlying network interface
112  * @param[in] ipAddr IPv4 address
113  * @param[in] macAddr MAC address
114  * @return Error code
115  **/
116 
118  const MacAddr *macAddr)
119 {
120  error_t error;
121  ArpCacheEntry *entry;
122 
123  //Check parameters
124  if(interface == NULL || macAddr == NULL)
126 
127  //Get exclusive access
129 
130  //Search the ARP cache for the specified IPv4 address
131  entry = arpFindEntry(interface, ipAddr);
132 
133  //Check whether a matching entry exists
134  if(entry != NULL)
135  {
136  //Check the state of the ARP entry
137  if(entry->state == ARP_STATE_INCOMPLETE)
138  {
139  //Record the corresponding MAC address
140  entry->macAddr = *macAddr;
141  //Send all the packets that are pending for transmission
142  arpSendQueuedPackets(interface, entry);
143  }
144  }
145  else
146  {
147  //Create a new entry in the ARP cache
148  entry = arpCreateEntry(interface);
149  }
150 
151  //ARP cache entry successfully created?
152  if(entry != NULL)
153  {
154  //Record the IPv4 address and the corresponding MAC address
155  entry->ipAddr = ipAddr;
156  entry->macAddr = *macAddr;
157 
158  //Unused parameters
159  entry->timeout = 0;
160  entry->retransmitCount = 0;
161  entry->queueSize = 0;
162 
163  //Update entry state
165 
166  //Successful processing
167  error = NO_ERROR;
168  }
169  else
170  {
171  //Failed to create ARP cache entry
172  error = ERROR_OUT_OF_RESOURCES;
173  }
174 
175  //Release exclusive access
177 
178  //Return status code
179  return error;
180 }
181 
182 
183 /**
184  * @brief Remove a static entry from the ARP cache
185  * @param[in] interface Underlying network interface
186  * @param[in] ipAddr IPv4 address
187  * @return Error code
188  **/
189 
191 {
192  error_t error;
193  ArpCacheEntry *entry;
194 
195  //Check parameters
196  if(interface == NULL)
198 
199  //Get exclusive access
201 
202  //Search the ARP cache for the specified IPv4 address
203  entry = arpFindEntry(interface, ipAddr);
204 
205  //Check whether a matching entry has been found
206  if(entry != NULL && entry->state == ARP_STATE_PERMANENT)
207  {
208  //Delete ARP entry
210  //Successful processing
211  error = NO_ERROR;
212  }
213  else
214  {
215  //No matching entry in ARP cache
216  error = ERROR_NOT_FOUND;
217  }
218 
219  //Release exclusive access
221 
222  //Return status code
223  return error;
224 }
225 
226 
227 /**
228  * @brief Address resolution using ARP protocol
229  * @param[in] interface Underlying network interface
230  * @param[in] ipAddr IPv4 address
231  * @param[in] macAddr Physical address matching the specified IPv4 address
232  * @return Error code
233  **/
234 
236 {
237  error_t error;
238  ArpCacheEntry *entry;
239 
240  //Search the ARP cache for the specified IPv4 address
241  entry = arpFindEntry(interface, ipAddr);
242 
243  //Check whether a matching entry has been found
244  if(entry != NULL)
245  {
246  //Check the state of the ARP entry
247  if(entry->state == ARP_STATE_INCOMPLETE)
248  {
249  //The address resolution is already in progress
250  error = ERROR_IN_PROGRESS;
251  }
252  else if(entry->state == ARP_STATE_STALE)
253  {
254  //Copy the MAC address associated with the specified IPv4 address
255  *macAddr = entry->macAddr;
256 
257  //Delay before sending the first probe
259  //Switch to the DELAY state
261 
262  //Successful address resolution
263  error = NO_ERROR;
264  }
265  else
266  {
267  //Copy the MAC address associated with the specified IPv4 address
268  *macAddr = entry->macAddr;
269 
270  //Successful address resolution
271  error = NO_ERROR;
272  }
273  }
274  else
275  {
276  //Check whether ARP is enabled
277  if(interface->enableArp)
278  {
279  //If no entry exists, then create a new one
280  entry = arpCreateEntry(interface);
281 
282  //ARP cache entry successfully created?
283  if(entry != NULL)
284  {
285  //Record the IPv4 address whose MAC address is unknown
286  entry->ipAddr = ipAddr;
287 
288  //Reset retransmission counter
289  entry->retransmitCount = 0;
290  //No packet are pending in the transmit queue
291  entry->queueSize = 0;
292 
293  //Send an ARP request
294  arpSendRequest(interface, entry->ipAddr, &MAC_BROADCAST_ADDR);
295 
296  //Set timeout value
297  entry->timeout = ARP_REQUEST_TIMEOUT;
298  //Enter INCOMPLETE state
300 
301  //The address resolution is in progress
302  error = ERROR_IN_PROGRESS;
303  }
304  else
305  {
306  //Failed to create ARP cache entry
307  error = ERROR_OUT_OF_RESOURCES;
308  }
309  }
310  else
311  {
312  //ARP is disabled
313  error = ERROR_INVALID_ADDRESS;
314  }
315  }
316 
317  //Return status code
318  return error;
319 }
320 
321 
322 /**
323  * @brief Enqueue an IPv4 packet waiting for address resolution
324  * @param[in] interface Underlying network interface
325  * @param[in] ipAddr IPv4 address of the destination host
326  * @param[in] buffer Multi-part buffer containing the packet to be enqueued
327  * @param[in] offset Offset to the first byte of the packet
328  * @param[in] ancillary Additional options passed to the stack along with
329  * the packet
330  * @return Error code
331  **/
332 
334  NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
335 {
336  error_t error;
337  uint_t i;
338  size_t length;
339  ArpCacheEntry *entry;
340 
341  //Retrieve the length of the multi-part buffer
342  length = netBufferGetLength(buffer);
343 
344  //Search the ARP cache for the specified IPv4 address
345  entry = arpFindEntry(interface, ipAddr);
346 
347  //Check whether a matching entry exists
348  if(entry != NULL)
349  {
350  //Check the state of the ARP entry
351  if(entry->state == ARP_STATE_INCOMPLETE)
352  {
353  //Check whether the packet queue is full
354  if(entry->queueSize >= ARP_MAX_PENDING_PACKETS)
355  {
356  //When the queue overflows, the new arrival should replace the oldest entry
357  netBufferFree(entry->queue[0].buffer);
358 
359  //Make room for the new packet
360  for(i = 1; i < ARP_MAX_PENDING_PACKETS; i++)
361  {
362  entry->queue[i - 1] = entry->queue[i];
363  }
364 
365  //Adjust the number of pending packets
366  entry->queueSize--;
367  }
368 
369  //Index of the entry to be filled in
370  i = entry->queueSize;
371  //Allocate a memory buffer to store the packet
372  entry->queue[i].buffer = netBufferAlloc(length);
373 
374  //Successful memory allocation?
375  if(entry->queue[i].buffer != NULL)
376  {
377  //Copy the contents of the IPv4 packet
378  netBufferCopy(entry->queue[i].buffer, 0, buffer, 0, length);
379  //Offset to the first byte of the IPv4 header
380  entry->queue[i].offset = offset;
381  //Additional options passed to the stack along with the packet
382  entry->queue[i].ancillary = *ancillary;
383 
384  //Increment the number of queued packets
385  entry->queueSize++;
386  //The packet was successfully enqueued
387  error = NO_ERROR;
388  }
389  else
390  {
391  //Failed to allocate memory
392  error = ERROR_OUT_OF_MEMORY;
393  }
394  }
395  else
396  {
397  //The address is already resolved
398  error = ERROR_UNEXPECTED_STATE;
399  }
400  }
401  else
402  {
403  //No matching entry in ARP cache
404  error = ERROR_NOT_FOUND;
405  }
406 
407  //Return status code
408  return error;
409 }
410 
411 
412 /**
413  * @brief ARP timer handler
414  *
415  * This routine must be periodically called by the TCP/IP stack to
416  * manage ARP cache
417  *
418  * @param[in] interface Underlying network interface
419  **/
420 
421 void arpTick(NetInterface *interface)
422 {
423  uint_t i;
424  systime_t time;
425  ArpCacheEntry *entry;
426 
427  //Get current time
428  time = osGetSystemTime();
429 
430  //Go through ARP cache
431  for(i = 0; i < ARP_CACHE_SIZE; i++)
432  {
433  //Point to the current entry
434  entry = &interface->arpCache[i];
435 
436  //Check the state of the ARP entry
437  if(entry->state == ARP_STATE_PERMANENT)
438  {
439  //Static ARP entries are never updated
440  }
441  else if(entry->state == ARP_STATE_INCOMPLETE)
442  {
443  //The request timed out?
444  if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
445  {
446  //Increment retransmission counter
447  entry->retransmitCount++;
448 
449  //Check whether the maximum number of retransmissions has been exceeded
450  if(entry->retransmitCount < ARP_MAX_REQUESTS)
451  {
452  //Retransmit ARP request
453  arpSendRequest(interface, entry->ipAddr, &MAC_BROADCAST_ADDR);
454 
455  //Save the time at which the packet was sent
456  entry->timestamp = time;
457  //Set timeout value
458  entry->timeout = ARP_REQUEST_TIMEOUT;
459  }
460  else
461  {
462  //Drop packets that are waiting for address resolution
463  arpFlushQueuedPackets(interface, entry);
464 
465  //The entry should be deleted since address resolution has failed
467  }
468  }
469  }
470  else if(entry->state == ARP_STATE_REACHABLE)
471  {
472  //Periodically time out ARP cache entries
473  if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
474  {
475  //Enter STALE state
477  }
478  }
479  else if(entry->state == ARP_STATE_STALE)
480  {
481  //The neighbor is no longer known to be reachable but until traffic
482  //is sent to the neighbor, no attempt should be made to verify its
483  //reachability
484  }
485  else if(entry->state == ARP_STATE_DELAY)
486  {
487  //Wait for the specified delay before sending the first probe
488  if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
489  {
490  //Reset retransmission counter
491  entry->retransmitCount = 0;
492 
493  //Send a point-to-point ARP request to the host
494  arpSendRequest(interface, entry->ipAddr, &entry->macAddr);
495 
496  //Set timeout value
497  entry->timeout = ARP_PROBE_TIMEOUT;
498  //Switch to the PROBE state
500  }
501  }
502  else if(entry->state == ARP_STATE_PROBE)
503  {
504  //The request timed out?
505  if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
506  {
507  //Increment retransmission counter
508  entry->retransmitCount++;
509 
510  //Check whether the maximum number of retransmissions has been
511  //exceeded
512  if(entry->retransmitCount < ARP_MAX_PROBES)
513  {
514  //Send a point-to-point ARP request to the host
515  arpSendRequest(interface, entry->ipAddr, &entry->macAddr);
516 
517  //Save the time at which the packet was sent
518  entry->timestamp = time;
519  //Set timeout value
520  entry->timeout = ARP_PROBE_TIMEOUT;
521  }
522  else
523  {
524  //The entry should be deleted since the host is not reachable
525  //anymore
527  }
528  }
529  }
530  else
531  {
532  //Just for sanity
534  }
535  }
536 }
537 
538 
539 /**
540  * @brief Incoming ARP packet processing
541  * @param[in] interface Underlying network interface
542  * @param[in] arpPacket Incoming ARP packet
543  * @param[in] length Packet length
544  **/
545 
546 void arpProcessPacket(NetInterface *interface, ArpPacket *arpPacket,
547  size_t length)
548 {
549  uint_t i;
550  bool_t validTarget;
551  Ipv4AddrEntry *addrEntry;
552  NetInterface *logicalInterface;
553 
554  //Discard invalid ARP packets
555  if(length < sizeof(ArpPacket))
556  return;
557 
558  //Debug message
559  TRACE_INFO("ARP packet received (%" PRIuSIZE " bytes)...\r\n", length);
560  //Dump ARP packet contents for debugging purpose
561  arpDumpPacket(arpPacket);
562 
563  //Make sure the hardware type is valid
564  if(arpPacket->hrd != HTONS(ARP_HARDWARE_TYPE_ETH))
565  return;
566  //Make sure the protocol type is valid
567  if(arpPacket->pro != HTONS(ARP_PROTOCOL_TYPE_IPV4))
568  return;
569  //Check the length of the hardware address
570  if(arpPacket->hln != sizeof(MacAddr))
571  return;
572  //Check the length of the protocol address
573  if(arpPacket->pln != sizeof(Ipv4Addr))
574  return;
575 
576  //The target protocol address must a valid address assigned to the interface
577  //or a tentative address whose uniqueness on a link is being verified
578  validTarget = FALSE;
579 
580  //Loop through the list of IPv4 addresses assigned to the interface
581  for(i = 0; i < IPV4_ADDR_LIST_SIZE; i++)
582  {
583  //Point to the current entry
584  addrEntry = &interface->ipv4Context.addrList[i];
585 
586  //Valid entry?
587  if(addrEntry->state != IPV4_ADDR_STATE_INVALID)
588  {
589  //Check whether the sender protocol address matches the IP address
590  //assigned to the interface
591  if(addrEntry->addr == arpPacket->spa)
592  {
593  //Tentative address?
594  if(addrEntry->state == IPV4_ADDR_STATE_TENTATIVE)
595  {
596  //If the host receives any ARP packet where the sender IP
597  //address is the address being probed for, then this is a
598  //conflicting ARP packet
599  addrEntry->conflict = TRUE;
600  //Exit immediately
601  return;
602  }
603  else
604  {
605  //Point to the logical interface
606  logicalInterface = nicGetLogicalInterface(interface);
607 
608  //If the sender hardware address does not match the hardware
609  //address of that interface, then this is a conflicting ARP
610  //packet
611  if(!macCompAddr(&arpPacket->sha, &logicalInterface->macAddr))
612  {
613  //An address conflict has been detected...
614  addrEntry->conflict = TRUE;
615  //Exit immediately
616  return;
617  }
618  }
619  }
620 
621  //Check whether the target protocol address matches an IP address
622  //assigned to the interface
623  if(addrEntry->addr == arpPacket->tpa)
624  {
625  validTarget = TRUE;
626  }
627  }
628  }
629 
630  //Valid target protocol address?
631  if(validTarget)
632  {
633  //Check operation code
634  switch(ntohs(arpPacket->op))
635  {
636  //ARP request?
638  //Process incoming ARP request
639  arpProcessRequest(interface, arpPacket);
640  break;
641 
642  //ARP reply?
644  //Process incoming ARP reply
645  arpProcessReply(interface, arpPacket);
646  break;
647 
648  //Unknown operation code?
649  default:
650  //Debug message
651  TRACE_INFO("Unknown operation code!\r\n");
652  //Discard incoming packet
653  break;
654  }
655  }
656 }
657 
658 
659 /**
660  * @brief Incoming ARP request processing
661  * @param[in] interface Underlying network interface
662  * @param[in] arpRequest Incoming ARP request
663  **/
664 
665 void arpProcessRequest(NetInterface *interface, ArpPacket *arpRequest)
666 {
667  uint_t i;
668  bool_t validTarget;
669  Ipv4AddrEntry *addrEntry;
670  NetInterface *logicalInterface;
671 
672  //Debug message
673  TRACE_INFO("ARP Request received...\r\n");
674 
675  //Check sender protocol address
676  if(ipv4IsBroadcastAddr(interface, arpRequest->spa))
677  return;
678  if(ipv4IsMulticastAddr(arpRequest->spa))
679  return;
680 
681  //Initialize flag
682  validTarget = TRUE;
683 
684  //Loop through the list of IPv4 addresses assigned to the interface
685  for(i = 0; i < IPV4_ADDR_LIST_SIZE; i++)
686  {
687  //Point to the current entry
688  addrEntry = &interface->ipv4Context.addrList[i];
689 
690  //Tentative address?
691  if(addrEntry->state == IPV4_ADDR_STATE_TENTATIVE)
692  {
693  //Check whether the target IP address is an address being probed for
694  if(addrEntry->addr == arpRequest->tpa)
695  {
696  //The target protocol address is a tentative address
697  validTarget = FALSE;
698 
699  //ARP probe received?
700  if(arpRequest->spa == IPV4_UNSPECIFIED_ADDR)
701  {
702  //Point to the logical interface
703  logicalInterface = nicGetLogicalInterface(interface);
704 
705  //If the sender hardware address does not match the hardware
706  //address of that interface, then this is a conflicting ARP
707  //packet
708  if(!macCompAddr(&arpRequest->sha, &logicalInterface->macAddr))
709  {
710  //An address conflict has been detected...
711  addrEntry->conflict = TRUE;
712  }
713  }
714  }
715  }
716  }
717 
718  //In all cases, the host must not respond to an ARP request for an address
719  //being probed for
720  if(validTarget && interface->enableArp)
721  {
722  //Send ARP reply
723  arpSendReply(interface, arpRequest->tpa, arpRequest->spa,
724  &arpRequest->sha);
725  }
726 }
727 
728 
729 /**
730  * @brief Incoming ARP reply processing
731  * @param[in] interface Underlying network interface
732  * @param[in] arpReply Incoming ARP reply
733  **/
734 
735 void arpProcessReply(NetInterface *interface, ArpPacket *arpReply)
736 {
737  ArpCacheEntry *entry;
738 
739  //Debug message
740  TRACE_INFO("ARP Reply received...\r\n");
741 
742  //Check sender protocol address
743  if(arpReply->spa == IPV4_UNSPECIFIED_ADDR)
744  return;
745  if(ipv4IsBroadcastAddr(interface, arpReply->spa))
746  return;
747  if(ipv4IsMulticastAddr(arpReply->spa))
748  return;
749 
750  //Check sender hardware address
751  if(macCompAddr(&arpReply->sha, &MAC_UNSPECIFIED_ADDR))
752  return;
753  if(macCompAddr(&arpReply->sha, &MAC_BROADCAST_ADDR))
754  return;
755  if(macIsMulticastAddr(&arpReply->sha))
756  return;
757 
758  //Check whether the target IP address is an address being probed for
759  if(ipv4IsTentativeAddr(interface, arpReply->tpa))
760  return;
761 
762  //Search the ARP cache for the specified IPv4 address
763  entry = arpFindEntry(interface, arpReply->spa);
764 
765  //Check whether a matching entry has been found
766  if(entry != NULL)
767  {
768  //Check the state of the ARP entry
769  if(entry->state == ARP_STATE_INCOMPLETE)
770  {
771  //Record the corresponding MAC address
772  entry->macAddr = arpReply->sha;
773 
774  //Send all the packets that are pending for transmission
775  arpSendQueuedPackets(interface, entry);
776 
777  //The validity of the ARP entry is limited in time
778  entry->timeout = ARP_REACHABLE_TIME;
779  //Switch to the REACHABLE state
781  }
782  else if(entry->state == ARP_STATE_REACHABLE)
783  {
784  //Different link-layer address than cached?
785  if(!macCompAddr(&arpReply->sha, &entry->macAddr))
786  {
787  //Enter STALE state
789  }
790  }
791  else if(entry->state == ARP_STATE_PROBE)
792  {
793  //Record IPv4/MAC address pair
794  entry->ipAddr = arpReply->spa;
795  entry->macAddr = arpReply->sha;
796 
797  //The validity of the ARP entry is limited in time
798  entry->timeout = ARP_REACHABLE_TIME;
799  //Switch to the REACHABLE state
801  }
802  else
803  {
804  //Static ARP entries are never updated
805  }
806  }
807 }
808 
809 
810 /**
811  * @brief Send ARP probe
812  * @param[in] interface Underlying network interface
813  * @param[in] targetIpAddr Target IPv4 address
814  * @return Error code
815  **/
816 
817 error_t arpSendProbe(NetInterface *interface, Ipv4Addr targetIpAddr)
818 {
819  error_t error;
820  size_t offset;
821  NetBuffer *buffer;
822  ArpPacket *arpRequest;
823  NetInterface *logicalInterface;
824  NetTxAncillary ancillary;
825 
826  //Point to the logical interface
827  logicalInterface = nicGetLogicalInterface(interface);
828 
829  //Allocate a memory buffer to hold an ARP packet
830  buffer = ethAllocBuffer(sizeof(ArpPacket), &offset);
831  //Failed to allocate buffer?
832  if(buffer == NULL)
833  return ERROR_OUT_OF_MEMORY;
834 
835  //Point to the beginning of the ARP packet
836  arpRequest = netBufferAt(buffer, offset, 0);
837 
838  //Format ARP request
839  arpRequest->hrd = htons(ARP_HARDWARE_TYPE_ETH);
840  arpRequest->pro = htons(ARP_PROTOCOL_TYPE_IPV4);
841  arpRequest->hln = sizeof(MacAddr);
842  arpRequest->pln = sizeof(Ipv4Addr);
843  arpRequest->op = htons(ARP_OPCODE_ARP_REQUEST);
844  arpRequest->sha = logicalInterface->macAddr;
845  arpRequest->spa = IPV4_UNSPECIFIED_ADDR;
846  arpRequest->tha = MAC_UNSPECIFIED_ADDR;
847  arpRequest->tpa = targetIpAddr;
848 
849  //Debug message
850  TRACE_INFO("Sending ARP Probe (%" PRIuSIZE " bytes)...\r\n", sizeof(ArpPacket));
851  //Dump ARP packet contents for debugging purpose
852  arpDumpPacket(arpRequest);
853 
854  //Additional options can be passed to the stack along with the packet
855  ancillary = NET_DEFAULT_TX_ANCILLARY;
856 
857  //Send ARP request
858  error = ethSendFrame(interface, &MAC_BROADCAST_ADDR, ETH_TYPE_ARP, buffer,
859  offset, &ancillary);
860 
861  //Free previously allocated memory
862  netBufferFree(buffer);
863 
864  //Return status code
865  return error;
866 }
867 
868 
869 /**
870  * @brief Send ARP request
871  * @param[in] interface Underlying network interface
872  * @param[in] targetIpAddr Target IPv4 address
873  * @param[in] destMacAddr Destination MAC address
874  * @return Error code
875  **/
876 
877 error_t arpSendRequest(NetInterface *interface, Ipv4Addr targetIpAddr,
878  const MacAddr *destMacAddr)
879 {
880  error_t error;
881  size_t offset;
882  NetBuffer *buffer;
883  ArpPacket *arpRequest;
884  Ipv4Addr senderIpAddr;
885  NetInterface *logicalInterface;
886  NetTxAncillary ancillary;
887 
888  //Point to the logical interface
889  logicalInterface = nicGetLogicalInterface(interface);
890 
891  //Select the most appropriate sender IP address to be used
892  error = ipv4SelectSourceAddr(&interface, targetIpAddr, &senderIpAddr);
893  //No address assigned to the interface?
894  if(error)
895  return error;
896 
897  //Allocate a memory buffer to hold an ARP packet
898  buffer = ethAllocBuffer(sizeof(ArpPacket), &offset);
899  //Failed to allocate buffer?
900  if(buffer == NULL)
901  return ERROR_OUT_OF_MEMORY;
902 
903  //Point to the beginning of the ARP packet
904  arpRequest = netBufferAt(buffer, offset, 0);
905 
906  //Format ARP request
907  arpRequest->hrd = htons(ARP_HARDWARE_TYPE_ETH);
908  arpRequest->pro = htons(ARP_PROTOCOL_TYPE_IPV4);
909  arpRequest->hln = sizeof(MacAddr);
910  arpRequest->pln = sizeof(Ipv4Addr);
911  arpRequest->op = htons(ARP_OPCODE_ARP_REQUEST);
912  arpRequest->sha = logicalInterface->macAddr;
913  arpRequest->spa = senderIpAddr;
914  arpRequest->tha = MAC_UNSPECIFIED_ADDR;
915  arpRequest->tpa = targetIpAddr;
916 
917  //Debug message
918  TRACE_INFO("Sending ARP Request (%" PRIuSIZE " bytes)...\r\n", sizeof(ArpPacket));
919  //Dump ARP packet contents for debugging purpose
920  arpDumpPacket(arpRequest);
921 
922  //Additional options can be passed to the stack along with the packet
923  ancillary = NET_DEFAULT_TX_ANCILLARY;
924 
925  //Send ARP request
926  error = ethSendFrame(interface, destMacAddr, ETH_TYPE_ARP, buffer, offset,
927  &ancillary);
928 
929  //Free previously allocated memory
930  netBufferFree(buffer);
931 
932  //Return status code
933  return error;
934 }
935 
936 
937 /**
938  * @brief Send ARP reply
939  * @param[in] interface Underlying network interface
940  * @param[in] senderIpAddr Sender Ipv4 address
941  * @param[in] targetIpAddr Target IPv4 address
942  * @param[in] targetMacAddr Target MAC address
943  * @return Error code
944  **/
945 
946 error_t arpSendReply(NetInterface *interface, Ipv4Addr senderIpAddr,
947  Ipv4Addr targetIpAddr, const MacAddr *targetMacAddr)
948 {
949  error_t error;
950  size_t offset;
951  NetBuffer *buffer;
952  ArpPacket *arpReply;
953  NetInterface *logicalInterface;
954  NetTxAncillary ancillary;
955 
956  //Point to the logical interface
957  logicalInterface = nicGetLogicalInterface(interface);
958 
959  //Allocate a memory buffer to hold an ARP packet
960  buffer = ethAllocBuffer(sizeof(ArpPacket), &offset);
961  //Failed to allocate buffer?
962  if(buffer == NULL)
963  return ERROR_OUT_OF_MEMORY;
964 
965  //Point to the beginning of the ARP packet
966  arpReply = netBufferAt(buffer, offset, 0);
967 
968  //Format ARP reply
969  arpReply->hrd = htons(ARP_HARDWARE_TYPE_ETH);
970  arpReply->pro = htons(ETH_TYPE_IPV4);
971  arpReply->hln = sizeof(MacAddr);
972  arpReply->pln = sizeof(Ipv4Addr);
973  arpReply->op = htons(ARP_OPCODE_ARP_REPLY);
974  arpReply->sha = logicalInterface->macAddr;
975  arpReply->spa = senderIpAddr;
976  arpReply->tha = *targetMacAddr;
977  arpReply->tpa = targetIpAddr;
978 
979  //Debug message
980  TRACE_INFO("Sending ARP Reply (%" PRIuSIZE " bytes)...\r\n", sizeof(ArpPacket));
981  //Dump ARP packet contents for debugging purpose
982  arpDumpPacket(arpReply);
983 
984  //Additional options can be passed to the stack along with the packet
985  ancillary = NET_DEFAULT_TX_ANCILLARY;
986 
987  //Send ARP reply
988  error = ethSendFrame(interface, targetMacAddr, ETH_TYPE_ARP, buffer, offset,
989  &ancillary);
990 
991  //Free previously allocated memory
992  netBufferFree(buffer);
993 
994  //Return status code
995  return error;
996 }
997 
998 
999 /**
1000  * @brief Dump ARP packet for debugging purpose
1001  * @param[in] arpPacket ARP header
1002  **/
1003 
1004 void arpDumpPacket(const ArpPacket *arpPacket)
1005 {
1006  //Dump ARP packet contents
1007  TRACE_DEBUG(" Hardware Type (hrd) = 0x%04" PRIX16 "\r\n", ntohs(arpPacket->hrd));
1008  TRACE_DEBUG(" Protocol Type (pro) = 0x%04" PRIX16 "\r\n", ntohs(arpPacket->pro));
1009  TRACE_DEBUG(" Hardware Address Length (hln) = %" PRIu8 "\r\n", arpPacket->hln);
1010  TRACE_DEBUG(" Protocol Address Length (pln) = %" PRIu8 "\r\n", arpPacket->pln);
1011  TRACE_DEBUG(" Opcode (op) = %" PRIu16 "\r\n", ntohs(arpPacket->op));
1012  TRACE_DEBUG(" Sender Hardware Address (sha) = %s\r\n", macAddrToString(&arpPacket->sha, NULL));
1013  TRACE_DEBUG(" Sender Protocol Address (spa) = %s\r\n", ipv4AddrToString(arpPacket->spa, NULL));
1014  TRACE_DEBUG(" Target Hardware Address (tha)= %s\r\n", macAddrToString(&arpPacket->tha, NULL));
1015  TRACE_DEBUG(" Target Protocol Address (tpa) = %s\r\n", ipv4AddrToString(arpPacket->tpa, NULL));
1016 }
1017 
1018 #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:53
@ ERROR_NOT_FOUND
Definition: error.h:147
Ipv4Addr addr
IPv4 address.
Definition: ipv4.h:386
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 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:117
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:333
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
Ipv4AddrState state
IPv4 address state.
Definition: ipv4.h:387
@ 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:297
void arpTick(NetInterface *interface)
ARP timer handler.
Definition: arp.c:421
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:665
@ ERROR_IN_PROGRESS
Definition: error.h:213
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:946
@ 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:735
#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:190
@ 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:95
#define IPV4_ADDR_LIST_SIZE
Definition: ipv4.h:69
uint8_t length
Definition: tcp.h:368
void arpProcessPacket(NetInterface *interface, ArpPacket *arpPacket, size_t length)
Incoming ARP packet processing.
Definition: arp.c:546
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:385
MacAddr
Definition: ethernet.h:195
error_t arpSendRequest(NetInterface *interface, Ipv4Addr targetIpAddr, const MacAddr *destMacAddr)
Send ARP request.
Definition: arp.c:877
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:107
uint32_t time
void arpDumpPacket(const ArpPacket *arpPacket)
Dump ARP packet for debugging purpose.
Definition: arp.c:1004
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
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.
#define ARP_REACHABLE_TIME
Definition: arp.h:88
systime_t timestamp
Time stamp to manage entry lifetime.
Definition: arp.h:193
#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:83
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:235
bool_t conflict
Address conflict detected.
Definition: ipv4.h:388
@ 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:135
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:1457
#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:817
const MacAddr MAC_BROADCAST_ADDR
Definition: ethernet.c:55
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:117
systime_t osGetSystemTime(void)
Retrieve system time.