Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arp.c Source File

arp.c

Go to the documentation of this file.
00001 /**
00002  * @file arp.c
00003  * @brief ARP (Address Resolution Protocol)
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @section Description
00026  *
00027  * Address Resolution Protocol is used to determine the hardware address of
00028  * a specific host when only its IPv4 address is known. Refer to RFC 826
00029  *
00030  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00031  * @version 1.7.6
00032  **/
00033 
00034 //Switch to the appropriate trace level
00035 #define TRACE_LEVEL ARP_TRACE_LEVEL
00036 
00037 //Dependencies
00038 #include <string.h>
00039 #include "core/net.h"
00040 #include "core/ethernet.h"
00041 #include "ipv4/arp.h"
00042 #include "debug.h"
00043 
00044 //Check TCP/IP stack configuration
00045 #if (IPV4_SUPPORT == ENABLED && ETH_SUPPORT == ENABLED)
00046 
00047 //Tick counter to handle periodic operations
00048 systime_t arpTickCounter;
00049 
00050 
00051 /**
00052  * @brief ARP cache initialization
00053  * @param[in] interface Underlying network interface
00054  * @return Error code
00055  **/
00056 
00057 error_t arpInit(NetInterface *interface)
00058 {
00059    //Initialize the ARP cache
00060    memset(interface->arpCache, 0, sizeof(interface->arpCache));
00061 
00062    //Successful initialization
00063    return NO_ERROR;
00064 }
00065 
00066 
00067 /**
00068  * @brief Flush ARP cache
00069  * @param[in] interface Underlying network interface
00070  **/
00071 
00072 void arpFlushCache(NetInterface *interface)
00073 {
00074    uint_t i;
00075    ArpCacheEntry *entry;
00076 
00077    //Loop through ARP cache entries
00078    for(i = 0; i < ARP_CACHE_SIZE; i++)
00079    {
00080       //Point to the current entry
00081       entry = &interface->arpCache[i];
00082 
00083       //Drop packets that are waiting for address resolution
00084       arpFlushQueuedPackets(interface, entry);
00085       //Release ARP entry
00086       entry->state = ARP_STATE_NONE;
00087    }
00088 }
00089 
00090 
00091 /**
00092  * @brief Create a new entry in the ARP cache
00093  * @param[in] interface Underlying network interface
00094  * @return Pointer to the newly created entry
00095  **/
00096 
00097 ArpCacheEntry *arpCreateEntry(NetInterface *interface)
00098 {
00099    uint_t i;
00100    ArpCacheEntry *entry;
00101    ArpCacheEntry *oldestEntry;
00102 
00103    //Keep track of the oldest entry
00104    oldestEntry = &interface->arpCache[0];
00105 
00106    //Loop through ARP cache entries
00107    for(i = 0; i < ARP_CACHE_SIZE; i++)
00108    {
00109       //Point to the current entry
00110       entry = &interface->arpCache[i];
00111 
00112       //Check whether the entry is currently in used or not
00113       if(entry->state == ARP_STATE_NONE)
00114       {
00115          //Erase contents
00116          memset(entry, 0, sizeof(ArpCacheEntry));
00117          //Return a pointer to the ARP entry
00118          return entry;
00119       }
00120 
00121       //Keep track of the oldest entry in the table
00122       if(timeCompare(entry->timestamp, oldestEntry->timestamp) < 0)
00123          oldestEntry = entry;
00124    }
00125 
00126    //Drop any pending packets
00127    arpFlushQueuedPackets(interface, oldestEntry);
00128    //The oldest entry is removed whenever the table runs out of space
00129    memset(oldestEntry, 0, sizeof(ArpCacheEntry));
00130    //Return a pointer to the ARP entry
00131    return oldestEntry;
00132 }
00133 
00134 
00135 /**
00136  * @brief Search the ARP cache for a given IPv4 address
00137  * @param[in] interface Underlying network interface
00138  * @param[in] ipAddr IPv4 address
00139  * @return A pointer to the matching ARP entry is returned. NULL is returned
00140  *   if the specified IPv4 address could not be found in ARP cache
00141  **/
00142 
00143 ArpCacheEntry *arpFindEntry(NetInterface *interface, Ipv4Addr ipAddr)
00144 {
00145    uint_t i;
00146    ArpCacheEntry *entry;
00147 
00148    //Loop through ARP cache entries
00149    for(i = 0; i < ARP_CACHE_SIZE; i++)
00150    {
00151       //Point to the current entry
00152       entry = &interface->arpCache[i];
00153 
00154       //Check whether the entry is currently in used
00155       if(entry->state != ARP_STATE_NONE)
00156       {
00157          //Current entry matches the specified address?
00158          if(entry->ipAddr == ipAddr)
00159             return entry;
00160       }
00161    }
00162 
00163    //No matching entry in ARP cache...
00164    return NULL;
00165 }
00166 
00167 
00168 /**
00169  * @brief Send packets that are waiting for address resolution
00170  * @param[in] interface Underlying network interface
00171  * @param[in] entry Pointer to a ARP cache entry
00172  **/
00173 
00174 void arpSendQueuedPackets(NetInterface *interface, ArpCacheEntry *entry)
00175 {
00176    uint_t i;
00177    ArpQueueItem *item;
00178 
00179    //Check current state
00180    if(entry->state == ARP_STATE_INCOMPLETE)
00181    {
00182       //Loop through the queued packets
00183       for(i = 0; i < entry->queueSize; i++)
00184       {
00185          //Point to the current queue item
00186          item = &entry->queue[i];
00187 
00188          //Send the IPv4 packet
00189          ethSendFrame(interface, &entry->macAddr,
00190             item->buffer, item->offset, ETH_TYPE_IPV4);
00191 
00192          //Release memory buffer
00193          netBufferFree(item->buffer);
00194       }
00195    }
00196 
00197    //The queue is now empty
00198    entry->queueSize = 0;
00199 }
00200 
00201 
00202 /**
00203  * @brief Flush packet queue
00204  * @param[in] interface Underlying network interface
00205  * @param[in] entry Pointer to a ARP cache entry
00206  **/
00207 
00208 void arpFlushQueuedPackets(NetInterface *interface, ArpCacheEntry *entry)
00209 {
00210    uint_t i;
00211 
00212    //Check current state
00213    if(entry->state == ARP_STATE_INCOMPLETE)
00214    {
00215       //Drop packets that are waiting for address resolution
00216       for(i = 0; i < entry->queueSize; i++)
00217       {
00218          //Release memory buffer
00219          netBufferFree(entry->queue[i].buffer);
00220       }
00221    }
00222 
00223    //The queue is now empty
00224    entry->queueSize = 0;
00225 }
00226 
00227 
00228 /**
00229  * @brief Address resolution using ARP protocol
00230  * @param[in] interface Underlying network interface
00231  * @param[in] ipAddr IPv4 address
00232  * @param[in] macAddr Physical address matching the specified IPv4 address
00233  * @return Error code
00234  **/
00235 
00236 error_t arpResolve(NetInterface *interface, Ipv4Addr ipAddr, MacAddr *macAddr)
00237 {
00238    error_t error;
00239    ArpCacheEntry *entry;
00240 
00241    //Search the ARP cache for the specified IPv4 address
00242    entry = arpFindEntry(interface, ipAddr);
00243 
00244    //Check whether a matching entry has been found
00245    if(entry != NULL)
00246    {
00247       //Check the state of the ARP entry
00248       if(entry->state == ARP_STATE_INCOMPLETE)
00249       {
00250          //The address resolution is already in progress
00251          error = ERROR_IN_PROGRESS;
00252       }
00253       else if(entry->state == ARP_STATE_STALE)
00254       {
00255          //Copy the MAC address associated with the specified IPv4 address
00256          *macAddr = entry->macAddr;
00257 
00258          //Start delay timer
00259          entry->timestamp = osGetSystemTime();
00260          //Delay before sending the first probe
00261          entry->timeout = ARP_DELAY_FIRST_PROBE_TIME;
00262          //Switch to the DELAY state
00263          entry->state = ARP_STATE_DELAY;
00264 
00265          //Successful address resolution
00266          error = NO_ERROR;
00267       }
00268       else
00269       {
00270          //Copy the MAC address associated with the specified IPv4 address
00271          *macAddr = entry->macAddr;
00272 
00273          //Successful address resolution
00274          error = NO_ERROR;
00275       }
00276    }
00277    else
00278    {
00279       //If no entry exists, then create a new one
00280       entry = arpCreateEntry(interface);
00281 
00282       //ARP cache entry successfully created?
00283       if(entry != NULL)
00284       {
00285          //Record the IPv4 address whose MAC address is unknown
00286          entry->ipAddr = ipAddr;
00287 
00288          //Reset retransmission counter
00289          entry->retransmitCount = 0;
00290          //No packet are pending in the transmit queue
00291          entry->queueSize = 0;
00292 
00293          //Send an ARP request
00294          arpSendRequest(interface, entry->ipAddr, &MAC_BROADCAST_ADDR);
00295 
00296          //Save the time at which the packet was sent
00297          entry->timestamp = osGetSystemTime();
00298          //Set timeout value
00299          entry->timeout = ARP_REQUEST_TIMEOUT;
00300          //Enter INCOMPLETE state
00301          entry->state = ARP_STATE_INCOMPLETE;
00302 
00303          //The address resolution is in progress
00304          error = ERROR_IN_PROGRESS;
00305       }
00306       else
00307       {
00308          //Failed to create ARP cache entry...
00309          error = ERROR_OUT_OF_RESOURCES;
00310       }
00311    }
00312 
00313    //Return status code
00314    return error;
00315 }
00316 
00317 
00318 /**
00319  * @brief Enqueue an IPv4 packet waiting for address resolution
00320  * @param[in] interface Underlying network interface
00321  * @param[in] ipAddr IPv4 address of the destination host
00322  * @param[in] buffer Multi-part buffer containing the packet to be enqueued
00323  * @param[in] offset Offset to the first byte of the packet
00324  * @return Error code
00325  **/
00326 
00327 error_t arpEnqueuePacket(NetInterface *interface,
00328    Ipv4Addr ipAddr, NetBuffer *buffer, size_t offset)
00329 {
00330    error_t error;
00331    uint_t i;
00332    size_t length;
00333    ArpCacheEntry *entry;
00334 
00335    //Retrieve the length of the multi-part buffer
00336    length = netBufferGetLength(buffer);
00337 
00338    //Search the ARP cache for the specified IPv4 address
00339    entry = arpFindEntry(interface, ipAddr);
00340 
00341    //Check whether a matching entry exists
00342    if(entry != NULL)
00343    {
00344       //Check current state
00345       if(entry->state == ARP_STATE_INCOMPLETE)
00346       {
00347          //Check whether the packet queue is full
00348          if(entry->queueSize >= ARP_MAX_PENDING_PACKETS)
00349          {
00350             //When the queue overflows, the new arrival should replace the oldest entry
00351             netBufferFree(entry->queue[0].buffer);
00352 
00353             //Make room for the new packet
00354             for(i = 1; i < ARP_MAX_PENDING_PACKETS; i++)
00355                entry->queue[i - 1] = entry->queue[i];
00356 
00357             //Adjust the number of pending packets
00358             entry->queueSize--;
00359          }
00360 
00361          //Index of the entry to be filled in
00362          i = entry->queueSize;
00363          //Allocate a memory buffer to store the packet
00364          entry->queue[i].buffer = netBufferAlloc(length);
00365 
00366          //Successful memory allocation?
00367          if(entry->queue[i].buffer != NULL)
00368          {
00369             //Copy the contents of the IPv4 packet
00370             netBufferCopy(entry->queue[i].buffer, 0, buffer, 0, length);
00371             //Offset to the first byte of the IPv4 header
00372             entry->queue[i].offset = offset;
00373 
00374             //Increment the number of queued packets
00375             entry->queueSize++;
00376             //The packet was successfully enqueued
00377             error = NO_ERROR;
00378          }
00379          else
00380          {
00381             //Failed to allocate memory
00382             error = ERROR_OUT_OF_MEMORY;
00383          }
00384       }
00385       else
00386       {
00387          //The address is already resolved
00388          error = ERROR_UNEXPECTED_STATE;
00389       }
00390    }
00391    else
00392    {
00393       //No matching entry in ARP cache
00394       error = ERROR_NOT_FOUND;
00395    }
00396 
00397    //Return status code
00398    return error;
00399 }
00400 
00401 
00402 /**
00403  * @brief ARP timer handler
00404  *
00405  * This routine must be periodically called by the TCP/IP stack to
00406  * manage ARP cache
00407  *
00408  * @param[in] interface Underlying network interface
00409  **/
00410 
00411 void arpTick(NetInterface *interface)
00412 {
00413    uint_t i;
00414    systime_t time;
00415    ArpCacheEntry *entry;
00416 
00417    //Get current time
00418    time = osGetSystemTime();
00419 
00420    //Go through ARP cache
00421    for(i = 0; i < ARP_CACHE_SIZE; i++)
00422    {
00423       //Point to the current entry
00424       entry = &interface->arpCache[i];
00425 
00426       //INCOMPLETE state?
00427       if(entry->state == ARP_STATE_INCOMPLETE)
00428       {
00429          //The request timed out?
00430          if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
00431          {
00432             //Increment retransmission counter
00433             entry->retransmitCount++;
00434 
00435             //Check whether the maximum number of retransmissions has been exceeded
00436             if(entry->retransmitCount < ARP_MAX_REQUESTS)
00437             {
00438                //Retransmit ARP request
00439                arpSendRequest(interface, entry->ipAddr, &MAC_BROADCAST_ADDR);
00440 
00441                //Save the time at which the packet was sent
00442                entry->timestamp = time;
00443                //Set timeout value
00444                entry->timeout = ARP_REQUEST_TIMEOUT;
00445             }
00446             else
00447             {
00448                //Drop packets that are waiting for address resolution
00449                arpFlushQueuedPackets(interface, entry);
00450                //The entry should be deleted since address resolution has failed
00451                entry->state = ARP_STATE_NONE;
00452             }
00453          }
00454       }
00455       //REACHABLE state?
00456       else if(entry->state == ARP_STATE_REACHABLE)
00457       {
00458          //Periodically time out ARP cache entries
00459          if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
00460          {
00461             //Save current time
00462             entry->timestamp = osGetSystemTime();
00463             //Enter STALE state
00464             entry->state = ARP_STATE_STALE;
00465          }
00466       }
00467       //DELAY state?
00468       else if(entry->state == ARP_STATE_DELAY)
00469       {
00470          //Wait for the specified delay before sending the first probe
00471          if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
00472          {
00473             //Send a point-to-point ARP request to the host
00474             arpSendRequest(interface, entry->ipAddr, &entry->macAddr);
00475 
00476             //Save the time at which the packet was sent
00477             entry->timestamp = time;
00478             //Set timeout value
00479             entry->timeout = ARP_PROBE_TIMEOUT;
00480             //Switch to the PROBE state
00481             entry->state = ARP_STATE_PROBE;
00482          }
00483       }
00484       //PROBE state?
00485       else if(entry->state == ARP_STATE_PROBE)
00486       {
00487          //The request timed out?
00488          if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
00489          {
00490             //Increment retransmission counter
00491             entry->retransmitCount++;
00492 
00493             //Check whether the maximum number of retransmissions has been exceeded
00494             if(entry->retransmitCount < ARP_MAX_PROBES)
00495             {
00496                //Send a point-to-point ARP request to the host
00497                arpSendRequest(interface, entry->ipAddr, &entry->macAddr);
00498 
00499                //Save the time at which the packet was sent
00500                entry->timestamp = time;
00501                //Set timeout value
00502                entry->timeout = ARP_PROBE_TIMEOUT;
00503             }
00504             else
00505             {
00506                //The entry should be deleted since the host is not reachable anymore
00507                entry->state = ARP_STATE_NONE;
00508             }
00509          }
00510       }
00511    }
00512 }
00513 
00514 
00515 /**
00516  * @brief Incoming ARP packet processing
00517  * @param[in] interface Underlying network interface
00518  * @param[in] arpPacket Incoming ARP packet
00519  * @param[in] length Packet length
00520  **/
00521 
00522 void arpProcessPacket(NetInterface *interface, ArpPacket *arpPacket, size_t length)
00523 {
00524    //Discard invalid ARP packets
00525    if(length < sizeof(ArpPacket))
00526       return;
00527 
00528    //Debug message
00529    TRACE_INFO("ARP packet received (%" PRIuSIZE " bytes)...\r\n", length);
00530    //Dump ARP packet contents for debugging purpose
00531    arpDumpPacket(arpPacket);
00532 
00533    //Make sure the hardware type is valid
00534    if(arpPacket->hrd != HTONS(ARP_HARDWARE_TYPE_ETH))
00535       return;
00536    //Make sure the protocol type is valid
00537    if(arpPacket->pro != HTONS(ARP_PROTOCOL_TYPE_IPV4))
00538       return;
00539    //Check the length of the hardware address
00540    if(arpPacket->hln != sizeof(MacAddr))
00541       return;
00542    //Check the length of the protocol address
00543    if(arpPacket->pln != sizeof(Ipv4Addr))
00544       return;
00545 
00546    //Check the state of the host address
00547    if(interface->ipv4Context.addrState == IPV4_ADDR_STATE_TENTATIVE)
00548    {
00549       //If the host receives any ARP packet where the sender IP address is
00550       //the address being probed for, then this is a conflicting ARP packet
00551       if(arpPacket->spa == interface->ipv4Context.addr)
00552       {
00553          //An address conflict has been detected...
00554          interface->ipv4Context.addrConflict = TRUE;
00555          //Exit immediately
00556          return;
00557       }
00558    }
00559    else if(interface->ipv4Context.addrState == IPV4_ADDR_STATE_VALID)
00560    {
00561       //Check whether the sender protocol address matches the IP
00562       //address assigned to the interface
00563       if(arpPacket->spa == interface->ipv4Context.addr)
00564       {
00565          //If the sender hardware address does not match the hardware
00566          //address of that interface, then this is a conflicting ARP packet
00567          if(!macCompAddr(&arpPacket->sha, &interface->macAddr))
00568          {
00569             //An address conflict has been detected...
00570             interface->ipv4Context.addrConflict = TRUE;
00571             //Exit immediately
00572             return;
00573          }
00574       }
00575    }
00576 
00577    //Check whether the target protocol address matches the IP
00578    //address assigned to the interface
00579    if(arpPacket->tpa != interface->ipv4Context.addr)
00580       return;
00581 
00582    //Check operation code
00583    switch(ntohs(arpPacket->op))
00584    {
00585    //ARP request?
00586    case ARP_OPCODE_ARP_REQUEST:
00587       //Process incoming ARP request
00588       arpProcessRequest(interface, arpPacket);
00589       break;
00590    //ARP reply?
00591    case ARP_OPCODE_ARP_REPLY:
00592       //Process incoming ARP reply
00593       arpProcessReply(interface, arpPacket);
00594       break;
00595    //Unknown operation code?
00596    default:
00597       //Debug message
00598       TRACE_INFO("Unknown operation code!\r\n");
00599       //Discard incoming packet
00600       break;
00601    }
00602 }
00603 
00604 
00605 /**
00606  * @brief Incoming ARP request processing
00607  * @param[in] interface Underlying network interface
00608  * @param[in] arpRequest Incoming ARP request
00609  **/
00610 
00611 void arpProcessRequest(NetInterface *interface, ArpPacket *arpRequest)
00612 {
00613    //Debug message
00614    TRACE_INFO("ARP Request received...\r\n");
00615 
00616    //Check sender protocol address
00617    if(ipv4IsBroadcastAddr(interface, arpRequest->spa))
00618       return;
00619    if(ipv4IsMulticastAddr(arpRequest->spa))
00620       return;
00621 
00622    //Check whether the target IP address is an address being probed for
00623    if(ipv4IsTentativeAddr(interface, arpRequest->tpa))
00624    {
00625       //ARP probe received?
00626       if(arpRequest->spa == IPV4_UNSPECIFIED_ADDR)
00627       {
00628          //If the sender hardware address does not match the hardware
00629          //address of that interface, then this is a conflicting ARP packet
00630          if(!macCompAddr(&arpRequest->sha, &interface->macAddr))
00631          {
00632             //An address conflict has been detected...
00633             interface->ipv4Context.addrConflict = TRUE;
00634          }
00635       }
00636 
00637       //In all cases, the host must not respond to an ARP request for an
00638       //address being probed for
00639       return;
00640    }
00641 
00642    //Send ARP reply
00643    arpSendReply(interface, arpRequest->spa, &arpRequest->sha, &arpRequest->sha);
00644 }
00645 
00646 
00647 /**
00648  * @brief Incoming ARP reply processing
00649  * @param[in] interface Underlying network interface
00650  * @param[in] arpReply Incoming ARP reply
00651  **/
00652 
00653 void arpProcessReply(NetInterface *interface, ArpPacket *arpReply)
00654 {
00655    ArpCacheEntry *entry;
00656 
00657    //Debug message
00658    TRACE_INFO("ARP Reply received...\r\n");
00659 
00660    //Check sender protocol address
00661    if(arpReply->spa == IPV4_UNSPECIFIED_ADDR)
00662       return;
00663    if(ipv4IsBroadcastAddr(interface, arpReply->spa))
00664       return;
00665    if(ipv4IsMulticastAddr(arpReply->spa))
00666       return;
00667 
00668    //Check sender hardware address
00669    if(macCompAddr(&arpReply->sha, &MAC_UNSPECIFIED_ADDR))
00670       return;
00671    if(macCompAddr(&arpReply->sha, &MAC_BROADCAST_ADDR))
00672       return;
00673    if(macIsMulticastAddr(&arpReply->sha))
00674       return;
00675 
00676    //Check whether the target IP address is an address being probed for
00677    if(ipv4IsTentativeAddr(interface, arpReply->tpa))
00678       return;
00679 
00680    //Search the ARP cache for the specified IPv4 address
00681    entry = arpFindEntry(interface, arpReply->spa);
00682 
00683    //Check whether a matching entry has been found
00684    if(entry != NULL)
00685    {
00686       //Check current state
00687       if(entry->state == ARP_STATE_INCOMPLETE)
00688       {
00689          //Record the corresponding MAC address
00690          entry->macAddr = arpReply->sha;
00691 
00692          //Send all the packets that are pending for transmission
00693          arpSendQueuedPackets(interface, entry);
00694 
00695          //Save current time
00696          entry->timestamp = osGetSystemTime();
00697          //The validity of the ARP entry is limited in time
00698          entry->timeout = ARP_REACHABLE_TIME;
00699          //Switch to the REACHABLE state
00700          entry->state = ARP_STATE_REACHABLE;
00701       }
00702       else if(entry->state == ARP_STATE_REACHABLE)
00703       {
00704          //Different link-layer address than cached?
00705          if(!macCompAddr(&arpReply->sha, &entry->macAddr))
00706          {
00707             //Enter STALE state
00708             entry->state = ARP_STATE_STALE;
00709          }
00710       }
00711       else if(entry->state == ARP_STATE_PROBE)
00712       {
00713          //Record IPv4/MAC address pair
00714          entry->ipAddr = arpReply->spa;
00715          entry->macAddr = arpReply->sha;
00716 
00717          //Save current time
00718          entry->timestamp = osGetSystemTime();
00719          //The validity of the ARP entry is limited in time
00720          entry->timeout = ARP_REACHABLE_TIME;
00721          //Switch to the REACHABLE state
00722          entry->state = ARP_STATE_REACHABLE;
00723       }
00724    }
00725 }
00726 
00727 
00728 /**
00729  * @brief Send ARP probe
00730  * @param[in] interface Underlying network interface
00731  * @param[in] targetIpAddr Target IPv4 address
00732  * @return Error code
00733  **/
00734 
00735 error_t arpSendProbe(NetInterface *interface, Ipv4Addr targetIpAddr)
00736 {
00737    error_t error;
00738    size_t offset;
00739    NetBuffer *buffer;
00740    ArpPacket *arpRequest;
00741 
00742    //Allocate a memory buffer to hold an ARP packet
00743    buffer = ethAllocBuffer(sizeof(ArpPacket), &offset);
00744    //Failed to allocate buffer?
00745    if(buffer == NULL)
00746       return ERROR_OUT_OF_MEMORY;
00747 
00748    //Point to the beginning of the ARP packet
00749    arpRequest = netBufferAt(buffer, offset);
00750 
00751    //Format ARP request
00752    arpRequest->hrd = htons(ARP_HARDWARE_TYPE_ETH);
00753    arpRequest->pro = htons(ARP_PROTOCOL_TYPE_IPV4);
00754    arpRequest->hln = sizeof(MacAddr);
00755    arpRequest->pln = sizeof(Ipv4Addr);
00756    arpRequest->op = htons(ARP_OPCODE_ARP_REQUEST);
00757    arpRequest->sha = interface->macAddr;
00758    arpRequest->spa = IPV4_UNSPECIFIED_ADDR;
00759    arpRequest->tha = MAC_UNSPECIFIED_ADDR;
00760    arpRequest->tpa = targetIpAddr;
00761 
00762    //Debug message
00763    TRACE_INFO("Sending ARP Probe (%" PRIuSIZE " bytes)...\r\n", sizeof(ArpPacket));
00764    //Dump ARP packet contents for debugging purpose
00765    arpDumpPacket(arpRequest);
00766 
00767    //Send ARP request
00768    error = ethSendFrame(interface, &MAC_BROADCAST_ADDR,
00769       buffer, offset, ETH_TYPE_ARP);
00770 
00771    //Free previously allocated memory
00772    netBufferFree(buffer);
00773    //Return status code
00774    return error;
00775 }
00776 
00777 
00778 /**
00779  * @brief Send ARP request
00780  * @param[in] interface Underlying network interface
00781  * @param[in] targetIpAddr Target IPv4 address
00782  * @param[in] destMacAddr Destination MAC address
00783  * @return Error code
00784  **/
00785 
00786 error_t arpSendRequest(NetInterface *interface,
00787    Ipv4Addr targetIpAddr, const MacAddr *destMacAddr)
00788 {
00789    error_t error;
00790    size_t offset;
00791    NetBuffer *buffer;
00792    ArpPacket *arpRequest;
00793    Ipv4Addr senderIpAddr;
00794 
00795    //Select the most appropriate sender IP address to be used
00796    error = ipv4SelectSourceAddr(&interface, targetIpAddr, &senderIpAddr);
00797    //No address assigned to the interface?
00798    if(error)
00799       return error;
00800 
00801    //Allocate a memory buffer to hold an ARP packet
00802    buffer = ethAllocBuffer(sizeof(ArpPacket), &offset);
00803    //Failed to allocate buffer?
00804    if(buffer == NULL)
00805       return ERROR_OUT_OF_MEMORY;
00806 
00807    //Point to the beginning of the ARP packet
00808    arpRequest = netBufferAt(buffer, offset);
00809 
00810    //Format ARP request
00811    arpRequest->hrd = htons(ARP_HARDWARE_TYPE_ETH);
00812    arpRequest->pro = htons(ARP_PROTOCOL_TYPE_IPV4);
00813    arpRequest->hln = sizeof(MacAddr);
00814    arpRequest->pln = sizeof(Ipv4Addr);
00815    arpRequest->op = htons(ARP_OPCODE_ARP_REQUEST);
00816    arpRequest->sha = interface->macAddr;
00817    arpRequest->spa = senderIpAddr;
00818    arpRequest->tha = MAC_UNSPECIFIED_ADDR;
00819    arpRequest->tpa = targetIpAddr;
00820 
00821    //Debug message
00822    TRACE_INFO("Sending ARP Request (%" PRIuSIZE " bytes)...\r\n", sizeof(ArpPacket));
00823    //Dump ARP packet contents for debugging purpose
00824    arpDumpPacket(arpRequest);
00825 
00826    //Send ARP request
00827    error = ethSendFrame(interface, destMacAddr, buffer, offset, ETH_TYPE_ARP);
00828 
00829    //Free previously allocated memory
00830    netBufferFree(buffer);
00831    //Return status code
00832    return error;
00833 }
00834 
00835 
00836 /**
00837  * @brief Send ARP reply
00838  * @param[in] interface Underlying network interface
00839  * @param[in] targetIpAddr Target IPv4 address
00840  * @param[in] targetMacAddr Target MAC address
00841  * @param[in] destMacAddr Destination MAC address
00842  * @return Error code
00843  **/
00844 
00845 error_t arpSendReply(NetInterface *interface, Ipv4Addr targetIpAddr,
00846    const MacAddr *targetMacAddr, const MacAddr *destMacAddr)
00847 {
00848    error_t error;
00849    size_t offset;
00850    NetBuffer *buffer;
00851    ArpPacket *arpReply;
00852 
00853    //Allocate a memory buffer to hold an ARP packet
00854    buffer = ethAllocBuffer(sizeof(ArpPacket), &offset);
00855    //Failed to allocate buffer?
00856    if(buffer == NULL)
00857       return ERROR_OUT_OF_MEMORY;
00858 
00859    //Point to the beginning of the ARP packet
00860    arpReply = netBufferAt(buffer, offset);
00861 
00862    //Format ARP reply
00863    arpReply->hrd = htons(ARP_HARDWARE_TYPE_ETH);
00864    arpReply->pro = htons(ETH_TYPE_IPV4);
00865    arpReply->hln = sizeof(MacAddr);
00866    arpReply->pln = sizeof(Ipv4Addr);
00867    arpReply->op = htons(ARP_OPCODE_ARP_REPLY);
00868    arpReply->sha = interface->macAddr;
00869    arpReply->spa = interface->ipv4Context.addr;
00870    arpReply->tha = *targetMacAddr;
00871    arpReply->tpa = targetIpAddr;
00872 
00873    //Debug message
00874    TRACE_INFO("Sending ARP Reply (%" PRIuSIZE " bytes)...\r\n", sizeof(ArpPacket));
00875    //Dump ARP packet contents for debugging purpose
00876    arpDumpPacket(arpReply);
00877 
00878    //Send ARP reply
00879    error = ethSendFrame(interface, destMacAddr, buffer, offset, ETH_TYPE_ARP);
00880 
00881    //Free previously allocated memory
00882    netBufferFree(buffer);
00883    //Return status code
00884    return error;
00885 }
00886 
00887 
00888 /**
00889  * @brief Dump ARP packet for debugging purpose
00890  * @param[in] arpPacket ARP header
00891  **/
00892 
00893 void arpDumpPacket(const ArpPacket *arpPacket)
00894 {
00895    //Dump ARP packet contents
00896    TRACE_DEBUG("  Hardware Type (hrd) = 0x%04" PRIX16 "\r\n", ntohs(arpPacket->hrd));
00897    TRACE_DEBUG("  Protocol Type (pro) = 0x%04" PRIX16 "\r\n", ntohs(arpPacket->pro));
00898    TRACE_DEBUG("  Hardware Address Length (hln) = %" PRIu8 "\r\n", arpPacket->hln);
00899    TRACE_DEBUG("  Protocol Address Length (pln) = %" PRIu8 "\r\n", arpPacket->pln);
00900    TRACE_DEBUG("  Opcode (op) = %" PRIu16 "\r\n", ntohs(arpPacket->op));
00901    TRACE_DEBUG("  Sender Hardware Address (sha)= %s\r\n", macAddrToString(&arpPacket->sha, NULL));
00902    TRACE_DEBUG("  Sender Protocol Address (spa) = %s\r\n", ipv4AddrToString(arpPacket->spa, NULL));
00903    TRACE_DEBUG("  Target Hardware Address (tha)= %s\r\n", macAddrToString(&arpPacket->tha, NULL));
00904    TRACE_DEBUG("  Target Protocol Address (tpa) = %s\r\n", ipv4AddrToString(arpPacket->tpa, NULL));
00905 }
00906 
00907 #endif
00908