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