Rewrite from scratch a TCP/IP stack for mbed. So far the following parts are usable: Drivers: - EMAC driver (from CMSIS 2.0) Protocols: - Ethernet protocol - ARP over ethernet for IPv4 - IPv4 over Ethernet - ICMPv4 over IPv4 - UDPv4 over IPv4 APIs: - Sockets for UDPv4 The structure of this stack is designed to be very modular. Each protocol can register one or more protocol to handle its payload, and in each protocol, an API can be hooked (like Sockets for example). This is an early release.

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ARP.cpp Source File

ARP.cpp

00001 /*
00002  * $Id: ARP.c 29 2011-06-11 14:53:08Z benoit $
00003  * $Author: benoit $
00004  * $Date: 2011-06-11 16:53:08 +0200 (sam., 11 juin 2011) $
00005  * $Rev: 29 $
00006  *
00007  *
00008  *
00009  *
00010  *
00011  */
00012 
00013 #include "ARP.h"
00014 #include "Ethernet.h"
00015 #include "Debug.h"
00016 #include "IPv4.h"
00017 #include <string.h>
00018 
00019 #define    DEBUG_CURRENT_MODULE_NAME        "ARP"
00020 #define    DEBUG_CURRENT_MODULE_ID          DEBUG_MODULE_ARP
00021 
00022 enum ARP_EntryStatus
00023 {
00024     ARP_Entry_Free = 0,
00025     ARP_Entry_PendingReply,
00026     ARP_Entry_Dynamic,
00027     ARP_Entry_Expired,
00028     ARP_Entry_Static,
00029     ARP_Entry_Count,
00030 };
00031 typedef enum ARP_EntryStatus ARP_EntryStatus_t;
00032 
00033 const char *arpEntryStatusText[ARP_Entry_Count] =
00034 {
00035     "free",
00036     "pending",
00037     "dynamic",
00038     "expired",
00039     "static",
00040 };
00041 
00042 struct ARP_CacheEntry
00043 {
00044     IPv4_Addr_t            ipv4Addr;
00045     Ethernet_Addr_t        ethernetAddr;
00046     NetIF_t             *netIF;
00047     uint16_t            age;
00048     ARP_EntryStatus_t    status;
00049     RTOS_Mutex_t        mutex;
00050 };
00051 typedef struct ARP_CacheEntry ARP_CacheEntry_t;
00052 
00053 #pragma push
00054 #pragma pack(1)
00055 static struct
00056 {
00057     Ethernet_Header_t    ethernetHeader;
00058     ARP_Header_t        arpHeader;
00059     ARP_IPv4Data_t        ipv4ARPData;
00060 } arp_FullIPv4Packet;
00061 #pragma pop
00062 
00063 static void Init(void);
00064 static void Handler(NetIF_t *netIF, NetPacket_t *packet);
00065 static void PeriodicFunction(void);
00066 static ARP_CacheEntry_t *GetReusableEntry(void);
00067 static ARP_CacheEntry_t *GetEntryByIPv4Address(IPv4_Addr_t address);
00068 
00069 static ARP_CacheEntry_t        arp_CacheTable[ARP_CACHE_MAX_ENTRIES];
00070 
00071 Protocol_Handler_t arp =
00072 {
00073     PROTOCOL_INDEX_NOT_INITIALIZED,               /* Always PROTOCOL_INDEX_NOT_INITIALIZED at initialization */
00074     Protocol_ID_ARP,                              /* Protocol ID */
00075     htons(ETHERNET_PROTO_ARP),                    /* Protocol number */
00076     Init,                                         /* Protocol initialisation function */
00077     Handler,                                      /* Protocol handler */
00078     NULL,                                         /* Protocol registration function */
00079     NULL,                                         /* API registration function */
00080 };
00081 
00082 static void Init(void)
00083 {
00084     int32_t                index;
00085 
00086     DEBUG_MODULE(DEBUG_LEVEL_INFO, ("Initializing ARP layer"));
00087     memset(arp_CacheTable, 0, sizeof(arp_CacheTable));
00088     for (index = 0; index < ARP_CACHE_MAX_ENTRIES; index++)
00089     {
00090         arp_CacheTable[index].mutex = RTOS_MUTEX_CREATE();
00091     }
00092     NetIF_RegisterPeriodicFunction("ARP cache", PeriodicFunction, ARP_FUNCTION_PERIOD);
00093 }
00094 
00095 
00096 
00097 
00098 static void Handler(NetIF_t *netIF, NetPacket_t *packet)
00099 {
00100     static ARP_Type_t           type;
00101     static ARP_Protocol_t       protocol;
00102     static ARP_Operation_t      operation;
00103     static ARP_IPv4Data_t       *ipv4ARP;
00104     static ARP_Header_t         *arpHeader;
00105     static Ethernet_Addr_t      *ourHWAddress;
00106     static Ethernet_Header_t    *ethernetHeader;
00107     static ARP_CacheEntry_t     *entry;
00108 
00109     arpHeader = (ARP_Header_t *)packet->data;
00110     type = ntohs(arpHeader->type);
00111     protocol = ntohs(arpHeader->protocol);
00112     operation = ntohs(arpHeader->operation);
00113 
00114     if (type != ARP_HW_TYPE_ENET) goto Exit;      /* not an ethernet ARP, ignore  */
00115 /* Not an IPv4 ARP, ignore */
00116     if (protocol != ETHERNET_PROTO_IPV4) goto Exit;
00117 
00118     ipv4ARP = (ARP_IPv4Data_t *)(arpHeader + 1);
00119 
00120     switch(operation)
00121     {
00122         case ARP_OPERATION_REQUEST:
00123 /* Does it match our hw address? */
00124             if (ipv4ARP->ipDest.addr == netIF->ipv4Address.addr)
00125             {
00126                 DEBUG_BLOCK(DEBUG_LEVEL_VERBOSE0)
00127                 {
00128                     ARP_DumpHeader("Got ", arpHeader);
00129                 }
00130 
00131                 ourHWAddress = (Ethernet_Addr_t *)netIF->driverParameter;
00132 
00133                 arpHeader->operation = htons(ARP_OPERATION_REPLY);
00134 
00135                 ipv4ARP->hwDest = ipv4ARP->hwSource;
00136                 ipv4ARP->ipDest.addr = ipv4ARP->ipSource.addr;
00137                 ipv4ARP->hwSource = *ourHWAddress;
00138                 ipv4ARP->ipSource = netIF->ipv4Address;
00139 
00140                 NetIF_ProtoPop(packet);
00141 
00142                 ethernetHeader = (Ethernet_Header_t *)packet->data;
00143                 ethernetHeader->destination = ethernetHeader->source;
00144                 ethernetHeader->source = *ourHWAddress;
00145 
00146                 DEBUG_BLOCK(DEBUG_LEVEL_VERBOSE0)
00147                 {
00148                     ARP_DumpHeader("Replying ", arpHeader);
00149                 }
00150 
00151                 netIF->driver->Write(packet->data, packet->length);
00152             }
00153 
00154             break;
00155 
00156         case ARP_OPERATION_REPLY:
00157 /* Check if it matches an entry we requested */
00158             DEBUG_BLOCK(DEBUG_LEVEL_VERBOSE0)
00159             {
00160                 ARP_DumpHeader("Got ", arpHeader);
00161             }
00162 
00163             entry = GetEntryByIPv4Address(ipv4ARP->ipSource);
00164             if (entry == NULL) break;             /* fake arp request */
00165 
00166             entry->status = ARP_Entry_Dynamic;
00167             entry->ethernetAddr = ipv4ARP->hwSource;
00168             entry->netIF = netIF;
00169             entry->age = 0;
00170 
00171             RTOS_MUTEX_UNLOCK(entry->mutex);
00172 
00173             DEBUG_BLOCK(DEBUG_LEVEL_VERBOSE0)
00174             {
00175                 DEBUG_RAW(("Adding entry %d.%d.%d.%d at %02x:%02x:%02x:%02x:%02x:%02x",
00176                     ipv4ARP->ipSource.IP0,
00177                     ipv4ARP->ipSource.IP1,
00178                     ipv4ARP->ipSource.IP2,
00179                     ipv4ARP->ipSource.IP3,
00180                     ipv4ARP->hwSource.MA0,
00181                     ipv4ARP->hwSource.MA1,
00182                     ipv4ARP->hwSource.MA2,
00183                     ipv4ARP->hwSource.MA3,
00184                     ipv4ARP->hwSource.MA4,
00185                     ipv4ARP->hwSource.MA5
00186                     ));
00187             }
00188             break;
00189     }
00190 
00191     Exit:
00192     return;
00193 }
00194 
00195 
00196 
00197 
00198 static void PeriodicFunction(void)
00199 {
00200     int32_t        index;
00201     ARP_CacheEntry_t    *entry;
00202 
00203     for (index = 0; index < ARP_CACHE_MAX_ENTRIES; index++)
00204     {
00205         entry = arp_CacheTable + index;
00206         RTOS_MUTEX_LOCK(entry->mutex);
00207         switch(entry->status)
00208         {
00209             case ARP_Entry_Dynamic:
00210                 entry->age += ARP_FUNCTION_PERIOD;
00211                 if (entry->age > ARP_MAX_ENTRY_AGE)
00212                 {
00213                     entry->status = ARP_Entry_Expired;
00214                     entry->age = 0;
00215                 }
00216                 break;
00217 
00218             case ARP_Entry_PendingReply:
00219                 entry->age += ARP_FUNCTION_PERIOD;
00220                 if (entry->age > ARP_MAX_ENTRY_AGE)
00221                 {
00222                     entry->status = ARP_Entry_Free;
00223                     entry->age = 0;
00224                 }
00225                 break;
00226         }
00227         RTOS_MUTEX_UNLOCK(entry->mutex);
00228     }
00229 }
00230 
00231 
00232 
00233 
00234 static ARP_CacheEntry_t *GetReusableEntry(void)
00235 {
00236     int32_t                index,
00237         oldestEntryIndex, oldestEntryAge;
00238     ARP_CacheEntry_t    *entry;
00239 
00240 /* First look for a free entry */
00241     for (index = 0; index < ARP_CACHE_MAX_ENTRIES; index++)
00242     {
00243         entry = arp_CacheTable + index;
00244         RTOS_MUTEX_LOCK(entry->mutex);
00245 
00246         if (entry->status == ARP_Entry_Free)
00247         {
00248             break;
00249         }
00250 
00251         RTOS_MUTEX_UNLOCK(entry->mutex);
00252         entry = NULL;
00253     }
00254 
00255     if (entry != NULL) goto Exit;                 /* A free entry was found, return it */
00256 
00257 /* Now look for an expired entry */
00258     oldestEntryIndex = -1;
00259     oldestEntryAge = -1;
00260     for (index = 0; index < ARP_CACHE_MAX_ENTRIES; index++)
00261     {
00262         entry = arp_CacheTable + index;
00263         RTOS_MUTEX_LOCK(entry->mutex);
00264 
00265         if (entry->age > oldestEntryAge)
00266         {
00267             oldestEntryIndex = index;
00268             oldestEntryAge = entry->age;
00269         }
00270 
00271         if (entry->status == ARP_Entry_Expired)
00272         {
00273             break;
00274         }
00275 
00276         RTOS_MUTEX_UNLOCK(entry->mutex);
00277         entry = NULL;
00278     }
00279 
00280     if (entry != NULL) goto Exit;                 /* An expired entry was found, return it */
00281 
00282 /* Last possibility, return the oldest non static entry */
00283     entry = arp_CacheTable + oldestEntryIndex;
00284     RTOS_MUTEX_LOCK(entry->mutex);
00285 
00286     Exit:
00287     return entry;
00288 }
00289 
00290 
00291 
00292 
00293 static ARP_CacheEntry_t *GetEntryByIPv4Address(IPv4_Addr_t address)
00294 {
00295     int32_t                index;
00296     ARP_CacheEntry_t    *entry = NULL;
00297 
00298     for (index = 0; index < ARP_CACHE_MAX_ENTRIES; index++)
00299     {
00300         entry = arp_CacheTable + index;
00301         RTOS_MUTEX_LOCK(entry->mutex);
00302 
00303         if (entry->ipv4Addr.addr == address.addr)
00304         {
00305             break;
00306         }
00307         RTOS_MUTEX_UNLOCK(entry->mutex);
00308         entry = NULL;
00309     }
00310 
00311     return entry;
00312 }
00313 
00314 
00315 
00316 
00317 int32_t ARP_ResolveIPv4Address(NetIF_t *netIF, IPv4_Addr_t address, Ethernet_Addr_t *ethernetAddr)
00318 {
00319     int32_t                result = -1;
00320     Ethernet_Addr_t        *hwAddress;
00321     ARP_CacheEntry_t    *entry;
00322 
00323     DEBUG_MODULE(DEBUG_LEVEL_INFO, ("Resolving %d.%d.%d.%d",
00324         address.IP0,
00325         address.IP1,
00326         address.IP2,
00327         address.IP3
00328         ));
00329 
00330 /* Look if entry is already available in table */
00331     entry = GetEntryByIPv4Address(address);
00332     if (entry != NULL)                            /* Found entry, look its status */
00333     {
00334         switch(entry->status)
00335         {
00336             case ARP_Entry_Static:
00337                 DEBUG_MODULE(DEBUG_LEVEL_VERBOSE0, ("Found static entry"));
00338                 if (ethernetAddr != NULL) *ethernetAddr = entry->ethernetAddr;
00339                 RTOS_MUTEX_UNLOCK(entry->mutex);
00340                 result = 0;
00341                 break;
00342 
00343             case ARP_Entry_Dynamic:
00344                 DEBUG_MODULE(DEBUG_LEVEL_VERBOSE0, ("Found dynamic entry"));
00345                 if (ethernetAddr != NULL) *ethernetAddr = entry->ethernetAddr;
00346                 entry->age = 0;
00347                 RTOS_MUTEX_UNLOCK(entry->mutex);
00348                 result = 0;
00349                 break;
00350 
00351             case ARP_Entry_Expired:
00352                 DEBUG_MODULE(DEBUG_LEVEL_VERBOSE0, ("Found expired entry, reactivating it"));
00353                 if (ethernetAddr != NULL) *ethernetAddr = entry->ethernetAddr;
00354                 entry->status = ARP_Entry_Dynamic;
00355                 entry->age = 0;
00356                 RTOS_MUTEX_UNLOCK(entry->mutex);
00357                 result = 0;
00358                 break;
00359 
00360             case ARP_Entry_PendingReply:
00361                 DEBUG_MODULE(DEBUG_LEVEL_VERBOSE0, ("Found pending entry"));
00362                 entry->age = 0;
00363                 RTOS_MUTEX_UNLOCK(entry->mutex);
00364                 break;
00365 
00366             default:
00367                 DEBUG_MODULE(DEBUG_LEVEL_INFO, ("Default?!"));
00368                 break;
00369         }
00370     }
00371 
00372     if (result == 0) goto Exit;                   /* Resolution was successfull, exit */
00373 
00374 /* Entry not found, send a request */
00375     result = -1;
00376     DEBUG_MODULE(DEBUG_LEVEL_INFO, ("Sending ARP resolution request for %d.%d.%d.%d",
00377         address.IP0,
00378         address.IP1,
00379         address.IP2,
00380         address.IP3
00381         ));
00382 
00383 /* Update entry, setting its status to Pending reply */
00384     entry = GetReusableEntry();
00385     if (entry != NULL)
00386     {
00387         entry->status = ARP_Entry_PendingReply;
00388         entry->ipv4Addr.addr = address.addr;
00389         entry->netIF = netIF;
00390         entry->age = 0;
00391         RTOS_MUTEX_UNLOCK(entry->mutex);
00392     }
00393 /* Send ARP who-has */
00394     hwAddress = (Ethernet_Addr_t *)netIF->driverParameter;
00395 
00396     arp_FullIPv4Packet.ethernetHeader.destination = ethernet_Addr_Broadcast;
00397     arp_FullIPv4Packet.ethernetHeader.source = *hwAddress;
00398     arp_FullIPv4Packet.ethernetHeader.protocol = htons(ETHERNET_PROTO_ARP);
00399 
00400     arp_FullIPv4Packet.arpHeader.type = htons(ARP_HW_TYPE_ENET);
00401     arp_FullIPv4Packet.arpHeader.protocol = htons(ETHERNET_PROTO_IPV4);
00402     arp_FullIPv4Packet.arpHeader.operation = htons(ARP_OPERATION_REQUEST);
00403     arp_FullIPv4Packet.arpHeader.hardAddrLen = 6;
00404     arp_FullIPv4Packet.arpHeader.protoAddrLen = 4;
00405 
00406     arp_FullIPv4Packet.ipv4ARPData.hwSource = *hwAddress;
00407     arp_FullIPv4Packet.ipv4ARPData.ipSource = netIF->ipv4Address;
00408     arp_FullIPv4Packet.ipv4ARPData.hwDest = ethernet_Addr_Null;
00409     arp_FullIPv4Packet.ipv4ARPData.ipDest = address;
00410 
00411     DEBUG_BLOCK(DEBUG_LEVEL_VERBOSE0)
00412     {
00413         ARP_DumpHeader("Sending ", &arp_FullIPv4Packet.arpHeader);
00414     }
00415 
00416     netIF->driver->Write((uint8_t *)&arp_FullIPv4Packet, sizeof(arp_FullIPv4Packet));
00417 
00418     Exit:
00419     return result;
00420 }
00421 
00422 
00423 
00424 
00425 int32_t ARP_AddStaticEntry(NetIF_t *netIF, IPv4_Addr_t address, const Ethernet_Addr_t *ethernetAddr)
00426 {
00427     int32_t                result = 0;
00428     ARP_CacheEntry_t    *entry;
00429 
00430     entry = GetReusableEntry();
00431     if (entry == NULL)
00432     {
00433         result = -1;
00434         goto Exit;
00435     }
00436     entry->netIF = netIF;
00437     entry->status = ARP_Entry_Static;
00438     entry->ipv4Addr.addr = address.addr;
00439     entry->ethernetAddr = *ethernetAddr;
00440     entry->age = 0;
00441     RTOS_MUTEX_UNLOCK(entry->mutex);
00442 
00443     Exit:
00444     return result;
00445 }
00446 
00447 
00448 
00449 
00450 int32_t ARP_RemoveEntry(const NetIF_t *netIF, IPv4_Addr_t address)
00451 {
00452     int32_t        result = 0;
00453 
00454     return result;
00455 }
00456 
00457 
00458 
00459 
00460 void ARP_FlushCache(Bool_t flushStaticEntries)
00461 {
00462     int32_t                index;
00463     ARP_CacheEntry_t    *entry;
00464 
00465     for (index = 0; index < ARP_CACHE_MAX_ENTRIES; index++)
00466     {
00467         entry = arp_CacheTable + index;
00468         RTOS_MUTEX_LOCK(entry->mutex);
00469         if ((entry->status == ARP_Entry_Static) && (!flushStaticEntries))
00470         {
00471             RTOS_MUTEX_UNLOCK(entry->mutex);
00472             continue;
00473         }
00474         entry->status = ARP_Entry_Free;
00475         entry->ipv4Addr = ipv4_Addr_Any;
00476         entry->ethernetAddr = ethernet_Addr_Null;
00477         entry->age = 0;
00478         RTOS_MUTEX_UNLOCK(entry->mutex);
00479     }
00480 }
00481 
00482 
00483 
00484 
00485 void ARP_DisplayCache(void)
00486 {
00487     int32_t                index;
00488     ARP_CacheEntry_t    *entry = NULL;
00489 
00490     DEBUG_RAW(("ARP cache"));
00491     DEBUG_RAW(("index dev   MAC address            type  age  IPv4 address"));
00492     DEBUG_RAW(("----------------------------------------------------------"));
00493 /*      en0   00:11:22:33:44:55  dyn    10 163.157.128.131 */
00494     for (index = 0; index < ARP_CACHE_MAX_ENTRIES; index++)
00495     {
00496         entry = arp_CacheTable + index;
00497 
00498         DEBUG_RAW(("%2d    %s%c   %02x:%02x:%02x:%02x:%02x:%02x  %8s  %4d  %d.%d.%d.%d",
00499             index,
00500             entry->status != ARP_Entry_Free ? entry->netIF->name : "--",
00501             entry->status != ARP_Entry_Free ? entry->netIF->index + '0' : '-',
00502             entry->ethernetAddr.MA0,
00503             entry->ethernetAddr.MA1,
00504             entry->ethernetAddr.MA2,
00505             entry->ethernetAddr.MA3,
00506             entry->ethernetAddr.MA4,
00507             entry->ethernetAddr.MA5,
00508 
00509             arpEntryStatusText[entry->status],
00510             entry->age,
00511 
00512             entry->ipv4Addr.IP0,
00513             entry->ipv4Addr.IP1,
00514             entry->ipv4Addr.IP2,
00515             entry->ipv4Addr.IP3
00516             ));
00517     }
00518 }
00519 
00520 
00521 
00522 
00523 void ARP_DumpHeader(const char *prefix, ARP_Header_t *arpHeader)
00524 {
00525     ARP_IPv4Data_t    *ipv4ARP = NULL;
00526 
00527     if (arpHeader->protocol == htons(ETHERNET_PROTO_IPV4))
00528     {
00529         ipv4ARP = (ARP_IPv4Data_t *)(arpHeader + 1);
00530 
00531         switch(ntohs(arpHeader->operation))
00532         {
00533             case ARP_OPERATION_REQUEST:
00534                 DEBUG_RAW(("%sARP who-has %d.%d.%d.%d tell %02x:%02x:%02x:%02x:%02x:%02x",
00535                     prefix != NULL ? prefix : "",
00536 
00537                     ipv4ARP->ipDest.IP0,
00538                     ipv4ARP->ipDest.IP1,
00539                     ipv4ARP->ipDest.IP2,
00540                     ipv4ARP->ipDest.IP3,
00541 
00542                     ipv4ARP->hwSource.MA0,
00543                     ipv4ARP->hwSource.MA1,
00544                     ipv4ARP->hwSource.MA2,
00545                     ipv4ARP->hwSource.MA3,
00546                     ipv4ARP->hwSource.MA4,
00547                     ipv4ARP->hwSource.MA5
00548                     ));
00549                 break;
00550 
00551             case ARP_OPERATION_REPLY:
00552                 DEBUG_RAW(("%sARP %d.%d.%d.%d is-at %02x:%02x:%02x:%02x:%02x:%02x",
00553                     prefix != NULL ? prefix : "",
00554 
00555                     ipv4ARP->ipSource.IP0,
00556                     ipv4ARP->ipSource.IP1,
00557                     ipv4ARP->ipSource.IP2,
00558                     ipv4ARP->ipSource.IP3,
00559 
00560                     ipv4ARP->hwSource.MA0,
00561                     ipv4ARP->hwSource.MA1,
00562                     ipv4ARP->hwSource.MA2,
00563                     ipv4ARP->hwSource.MA3,
00564                     ipv4ARP->hwSource.MA4,
00565                     ipv4ARP->hwSource.MA5
00566                     ));
00567                 break;
00568 
00569             default:
00570                 break;
00571         }
00572     }
00573     else
00574     {
00575         DEBUG_RAW(("%sARP: unsupported protocol %d",
00576             prefix != NULL ? prefix : "",
00577             arpHeader->protocol
00578             ));
00579     }
00580 }