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