Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ethernet.c Source File

ethernet.c

Go to the documentation of this file.
00001 /**
00002  * @file ethernet.c
00003  * @brief Ethernet
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  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL ETH_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <ctype.h>
00036 #include "core/net.h"
00037 #include "core/nic.h"
00038 #include "core/ethernet.h"
00039 #include "core/socket.h"
00040 #include "core/raw_socket.h"
00041 #include "core/tcp_timer.h"
00042 #include "ipv4/arp.h"
00043 #include "ipv4/ipv4.h"
00044 #include "ipv6/ipv6.h"
00045 #include "mibs/mib2_module.h"
00046 #include "debug.h"
00047 
00048 //Check TCP/IP stack configuration
00049 #if (ETH_SUPPORT == ENABLED)
00050 
00051 //Unspecified MAC address
00052 const MacAddr MAC_UNSPECIFIED_ADDR = {{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}};
00053 //Broadcast MAC address
00054 const MacAddr MAC_BROADCAST_ADDR = {{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}};
00055 //Unspecified EUI-64 address
00056 const Eui64 EUI64_UNSPECIFIED_ADDR = {{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}};
00057 
00058 //Padding bytes
00059 const uint8_t ethPadding[64] =
00060 {
00061    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00062    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00063    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00064    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00065    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00066    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00067    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00068    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
00069 };
00070 
00071 //A lookup table can be used to speed up CRC calculation
00072 #if (ETH_FAST_CRC_SUPPORT == ENABLED)
00073 
00074 static const uint32_t crc32Table[256] =
00075 {
00076    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
00077    0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
00078    0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
00079    0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
00080    0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
00081    0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
00082    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
00083    0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
00084    0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
00085    0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
00086    0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
00087    0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
00088    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
00089    0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
00090    0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
00091    0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
00092    0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
00093    0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
00094    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
00095    0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
00096    0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
00097    0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
00098    0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
00099    0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
00100    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
00101    0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
00102    0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
00103    0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
00104    0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
00105    0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
00106    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
00107    0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
00108    0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
00109    0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
00110    0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
00111    0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
00112    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
00113    0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
00114    0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
00115    0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
00116    0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
00117    0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
00118    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
00119    0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
00120    0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
00121    0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
00122    0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
00123    0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
00124    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
00125    0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
00126    0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
00127    0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
00128    0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
00129    0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
00130    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
00131    0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
00132    0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
00133    0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
00134    0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
00135    0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
00136    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
00137    0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
00138    0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
00139    0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
00140 };
00141 
00142 #endif
00143 
00144 
00145 /**
00146  * @brief Ethernet related initialization
00147  * @param[in] interface Underlying network interface
00148  * @return Error code
00149  **/
00150 
00151 error_t ethInit(NetInterface *interface)
00152 {
00153    //Clear the MAC filter table contents
00154    memset(interface->macMulticastFilter, 0,
00155       sizeof(interface->macMulticastFilter));
00156 
00157    //Successful initialization
00158    return NO_ERROR;
00159 }
00160 
00161 
00162 /**
00163  * @brief Process an incoming Ethernet frame
00164  * @param[in] interface Underlying network interface
00165  * @param[in] ethFrame Incoming Ethernet frame to process
00166  * @param[in] length Total frame length
00167  **/
00168 
00169 void ethProcessFrame(NetInterface *interface, EthHeader *ethFrame, size_t length)
00170 {
00171 #if (IPV6_SUPPORT == ENABLED)
00172    NetBuffer1 buffer;
00173 #endif
00174    uint32_t crc;
00175 
00176    //Total number of octets received on the interface
00177    MIB2_INC_COUNTER32(interface->mibIfEntry->ifInOctets, length);
00178 
00179    //Ensure the length of the incoming frame is valid
00180    if(length < sizeof(EthHeader))
00181    {
00182       //Number of inbound packets that contained errors
00183       MIB2_INC_COUNTER32(interface->mibIfEntry->ifInErrors, 1);
00184       //Discard the received frame
00185       return;
00186    }
00187 
00188    //Debug message
00189    TRACE_DEBUG("Ethernet frame received (%" PRIuSIZE " bytes)...\r\n", length);
00190    //Dump Ethernet header contents for debugging purpose
00191    ethDumpHeader(ethFrame);
00192 
00193    //Check whether the CRC is included in the received frame
00194    if(!interface->nicDriver->autoCrcStrip)
00195    {
00196       //Ensure the length of the incoming frame is valid
00197       if(length < (sizeof(EthHeader) + ETH_CRC_SIZE))
00198       {
00199          //Number of inbound packets that contained errors
00200          MIB2_INC_COUNTER32(interface->mibIfEntry->ifInErrors, 1);
00201          //Discard the received frame
00202          return;
00203       }
00204 
00205       //CRC verification not supported by hardware?
00206       if(!interface->nicDriver->autoCrcVerif)
00207       {
00208          //The value of the residue is 0x2144DF1C when no CRC errors are detected
00209          if(ethCalcCrc(ethFrame, length) != 0x2144DF1C)
00210          {
00211             //Debug message
00212             TRACE_WARNING("Wrong CRC detected!\r\n");
00213             //Number of inbound packets that contained errors
00214             MIB2_INC_COUNTER32(interface->mibIfEntry->ifInErrors, 1);
00215             //Discard the received frame
00216             return;
00217          }
00218       }
00219 
00220       //Retrieve CRC value
00221       memcpy(&crc, (uint8_t *) ethFrame + length - ETH_CRC_SIZE, ETH_CRC_SIZE);
00222       //Reseed the pseudo-random number generator
00223       netInitRand(crc);
00224    }
00225 
00226    //Frame filtering based on destination MAC address
00227    if(ethCheckDestAddr(interface, &ethFrame->destAddr))
00228    {
00229       //Number of inbound packets which were chosen to be discarded
00230       //even though no errors had been detected
00231       MIB2_INC_COUNTER32(interface->mibIfEntry->ifInDiscards, 1);
00232       //Discard the received frame
00233       return;
00234    }
00235 
00236    //Check whether the destination address is a group address
00237    if(macIsMulticastAddr(&ethFrame->destAddr))
00238    {
00239       //Number of non-unicast packets delivered to a higher-layer protocol
00240       MIB2_INC_COUNTER32(interface->mibIfEntry->ifInNUcastPkts, 1);
00241    }
00242    else
00243    {
00244       //Number of unicast packets delivered to a higher-layer protocol
00245       MIB2_INC_COUNTER32(interface->mibIfEntry->ifInUcastPkts, 1);
00246    }
00247 
00248 #if (RAW_SOCKET_SUPPORT == ENABLED)
00249    //Allow raw sockets to process Ethernet packets
00250    rawSocketProcessEthPacket(interface, ethFrame, length - ETH_CRC_SIZE);
00251 #endif
00252 
00253    //Calculate the length of the data payload
00254    length -= sizeof(EthHeader);
00255 
00256    //Check whether the CRC is included in the received frame
00257    if(!interface->nicDriver->autoCrcStrip)
00258       length -= ETH_CRC_SIZE;
00259 
00260    //Check Ethernet type field
00261    switch(ntohs(ethFrame->type))
00262    {
00263 #if (IPV4_SUPPORT == ENABLED)
00264    //ARP packet received?
00265    case ETH_TYPE_ARP:
00266       //Process incoming ARP packet
00267       arpProcessPacket(interface, (ArpPacket *) ethFrame->data, length);
00268       break;
00269    //IPv4 packet received?
00270    case ETH_TYPE_IPV4:
00271       //Process incoming IPv4 packet
00272       ipv4ProcessPacket(interface, (Ipv4Header *) ethFrame->data, length);
00273       break;
00274 #endif
00275 
00276 #if (IPV6_SUPPORT == ENABLED)
00277    //IPv6 packet received?
00278    case ETH_TYPE_IPV6:
00279       //The incoming Ethernet frame fits in a single chunk
00280       buffer.chunkCount = 1;
00281       buffer.maxChunkCount = 1;
00282       buffer.chunk[0].address = ethFrame->data;
00283       buffer.chunk[0].length = length;
00284       buffer.chunk[0].size = 0;
00285 
00286       //Process incoming IPv6 packet
00287       ipv6ProcessPacket(interface, (NetBuffer *) &buffer, 0);
00288       break;
00289 #endif
00290 
00291    //Unknown packet received?
00292    default:
00293       //Debug message
00294       TRACE_WARNING("Unknown Ethernet type!\r\n");
00295 
00296       //Number of packets received via the interface which were
00297       //discarded because of an unknown or unsupported protocol
00298       MIB2_INC_COUNTER32(interface->mibIfEntry->ifInUnknownProtos , 1);
00299       break;
00300    }
00301 }
00302 
00303 
00304 /**
00305  * @brief Send an Ethernet frame
00306  * @param[in] interface Underlying network interface
00307  * @param[in] destAddr MAC address of the destination host
00308  * @param[in] buffer Multi-part buffer containing the payload
00309  * @param[in] offset Offset to the first payload byte
00310  * @param[in] type Ethernet type
00311  * @return Error code
00312  **/
00313 
00314 error_t ethSendFrame(NetInterface *interface, const MacAddr *destAddr,
00315    NetBuffer *buffer, size_t offset, uint16_t type)
00316 {
00317    error_t error;
00318    size_t length;
00319    EthHeader *header;
00320 
00321    //Is there enough space for the Ethernet header?
00322    if(offset < sizeof(EthHeader))
00323       return ERROR_INVALID_PARAMETER;
00324 
00325    //Make room for the Ethernet header
00326    offset -= sizeof(EthHeader);
00327    //Retrieve the length of the frame
00328    length = netBufferGetLength(buffer) - offset;
00329 
00330    //Position to the beginning of the frame
00331    header = netBufferAt(buffer, offset);
00332 
00333    //Format Ethernet header
00334    header->destAddr = *destAddr;
00335    header->srcAddr = interface->macAddr;
00336    header->type = htons(type);
00337 
00338    //Automatic padding not supported by hardware?
00339    if(!interface->nicDriver->autoPadding)
00340    {
00341       //The host controller should manually add padding
00342       //to the packet before transmitting it
00343       if(length < (ETH_MIN_FRAME_SIZE - ETH_CRC_SIZE))
00344       {
00345          size_t n;
00346 
00347          //Add padding as necessary
00348          n = (ETH_MIN_FRAME_SIZE - ETH_CRC_SIZE) - length;
00349 
00350          //Append padding bytes
00351          error = netBufferAppend(buffer, ethPadding, n);
00352          //Any error to report?
00353          if(error)
00354             return error;
00355 
00356          //Adjust frame length
00357          length += n;
00358       }
00359    }
00360 
00361    //CRC calculation not supported by hardware?
00362    if(!interface->nicDriver->autoCrcCalc)
00363    {
00364       uint32_t crc;
00365 
00366       //Compute CRC over the header and payload
00367       crc = ethCalcCrcEx(buffer, offset, length);
00368       //Convert from host byte order to little-endian byte order
00369       crc = htole32(crc);
00370 
00371       //Append the calculated CRC value
00372       error = netBufferAppend(buffer, &crc, sizeof(crc));
00373       //Any error to report?
00374       if(error)
00375          return error;
00376 
00377       //Adjust frame length
00378       length += sizeof(crc);
00379    }
00380 
00381    //Total number of octets transmitted out of the interface
00382    MIB2_INC_COUNTER32(interface->mibIfEntry->ifOutOctets, length);
00383 
00384    //Check whether the destination address is a group address
00385    if(macIsMulticastAddr(&header->destAddr))
00386    {
00387       //Total number of non-unicast packets that higher-level protocols
00388       //requested be transmitted
00389       MIB2_INC_COUNTER32(interface->mibIfEntry->ifOutNUcastPkts, 1);
00390    }
00391    else
00392    {
00393       //Total number of unicast packets that higher-level protocols
00394       //requested be transmitted
00395       MIB2_INC_COUNTER32(interface->mibIfEntry->ifOutUcastPkts, 1);
00396    }
00397 
00398    //Debug message
00399    TRACE_DEBUG("Sending Ethernet frame (%" PRIuSIZE " bytes)...\r\n", length);
00400    //Dump Ethernet header contents for debugging purpose
00401    ethDumpHeader(header);
00402 
00403    //Send the resulting packet over the specified link
00404    error = nicSendPacket(interface, buffer, offset);
00405    //Return status code
00406    return error;
00407 }
00408 
00409 
00410 /**
00411  * @brief Destination MAC address filtering
00412  * @param[in] interface Underlying network interface
00413  * @param[in] macAddr Destination MAC address to be checked
00414  * @return Error code
00415  **/
00416 
00417 error_t ethCheckDestAddr(NetInterface *interface, const MacAddr *macAddr)
00418 {
00419    uint_t i;
00420    MacFilterEntry *entry;
00421 
00422    //Filter out any invalid addresses
00423    error_t error = ERROR_INVALID_ADDRESS;
00424 
00425    //Host address?
00426    if(macCompAddr(macAddr, &interface->macAddr))
00427    {
00428       error = NO_ERROR;
00429    }
00430    //Broadcast address?
00431    else if(macCompAddr(macAddr, &MAC_BROADCAST_ADDR))
00432    {
00433       error = NO_ERROR;
00434    }
00435    //Multicast address?
00436    else if(macIsMulticastAddr(macAddr))
00437    {
00438       //Go through the multicast filter table
00439       for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++)
00440       {
00441          //Point to the current entry
00442          entry = &interface->macMulticastFilter[i];
00443 
00444          //Valid entry?
00445          if(entry->refCount > 0)
00446          {
00447             //Check whether the destination MAC address matches
00448             //a relevant multicast address
00449             if(macCompAddr(&entry->addr, macAddr))
00450             {
00451                //The MAC address is acceptable
00452                error = NO_ERROR;
00453                //Stop immediately
00454                break;
00455             }
00456          }
00457       }
00458    }
00459 
00460    //Return status code
00461    return error;
00462 }
00463 
00464 
00465 /**
00466  * @brief Add a multicast address to the MAC filter table
00467  * @param[in] interface Underlying network interface
00468  * @param[in] macAddr Multicast MAC address to accept
00469  * @return Error code
00470  **/
00471 
00472 error_t ethAcceptMulticastAddr(NetInterface *interface, const MacAddr *macAddr)
00473 {
00474    uint_t i;
00475    MacFilterEntry *entry;
00476    MacFilterEntry *firstFreeEntry;
00477 
00478    //Keep track of the first free entry
00479    firstFreeEntry = NULL;
00480 
00481    //Go through the multicast filter table
00482    for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++)
00483    {
00484       //Point to the current entry
00485       entry = &interface->macMulticastFilter[i];
00486 
00487       //Valid entry?
00488       if(entry->refCount > 0)
00489       {
00490          //Check whether the table already contains the specified MAC address
00491          if(macCompAddr(&entry->addr, macAddr))
00492          {
00493             //Increment the reference count
00494             entry->refCount++;
00495             //No error to report
00496             return NO_ERROR;
00497          }
00498       }
00499       else
00500       {
00501          //Keep track of the first free entry
00502          if(firstFreeEntry == NULL)
00503             firstFreeEntry = entry;
00504       }
00505    }
00506 
00507    //Check whether the multicast filter table is full
00508    if(firstFreeEntry == NULL)
00509    {
00510       //A new entry cannot be added
00511       return ERROR_FAILURE;
00512    }
00513 
00514    //Add a new entry to the table
00515    firstFreeEntry->addr = *macAddr;
00516    //Initialize the reference count
00517    firstFreeEntry->refCount = 1;
00518 
00519    //Force the network interface controller to add the current
00520    //entry to its MAC filter table
00521    firstFreeEntry->addFlag = TRUE;
00522    firstFreeEntry->deleteFlag = FALSE;
00523 
00524    //Update the MAC filter table
00525    nicSetMulticastFilter(interface);
00526 
00527    //Clear the flag
00528    firstFreeEntry->addFlag = FALSE;
00529 
00530    //No error to report
00531    return NO_ERROR;
00532 }
00533 
00534 
00535 /**
00536  * @brief Remove a multicast address from the MAC filter table
00537  * @param[in] interface Underlying network interface
00538  * @param[in] macAddr Multicast MAC address to drop
00539  * @return Error code
00540  **/
00541 
00542 error_t ethDropMulticastAddr(NetInterface *interface, const MacAddr *macAddr)
00543 {
00544    uint_t i;
00545    MacFilterEntry *entry;
00546 
00547    //Go through the multicast filter table
00548    for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++)
00549    {
00550       //Point to the current entry
00551       entry = &interface->macMulticastFilter[i];
00552 
00553       //Valid entry?
00554       if(entry->refCount > 0)
00555       {
00556          //Specified MAC address found?
00557          if(macCompAddr(&entry->addr, macAddr))
00558          {
00559             //Decrement the reference count
00560             entry->refCount--;
00561 
00562             //Remove the entry if the reference count drops to zero
00563             if(entry->refCount == 0)
00564             {
00565                //Force the network interface controller to remove the current
00566                //entry from its MAC filter table
00567                entry->deleteFlag = TRUE;
00568 
00569                //Update the MAC filter table
00570                nicSetMulticastFilter(interface);
00571 
00572                //Clear the flag
00573                entry->deleteFlag = FALSE;
00574                //Remove the multicast address from the list
00575                entry->addr = MAC_UNSPECIFIED_ADDR;
00576             }
00577 
00578             //No error to report
00579             return NO_ERROR;
00580          }
00581       }
00582    }
00583 
00584    //The specified MAC address does not exist
00585    return ERROR_ADDRESS_NOT_FOUND;
00586 }
00587 
00588 
00589 /**
00590  * @brief Ethernet CRC calculation
00591  * @param[in] data Pointer to the data over which to calculate the CRC
00592  * @param[in] length Number of bytes to process
00593  * @return Resulting CRC value
00594  **/
00595 
00596 uint32_t ethCalcCrc(const void *data, size_t length)
00597 {
00598 //A lookup table can be used to speed up CRC calculation
00599 #if (ETH_FAST_CRC_SUPPORT == ENABLED)
00600    uint_t i;
00601 
00602    //Point to the data over which to calculate the CRC
00603    const uint8_t *p = (uint8_t *) data;
00604    //CRC preset value
00605    uint32_t crc = 0xFFFFFFFF;
00606 
00607    //Loop through data
00608    for(i = 0; i < length; i++)
00609    {
00610       //The message is processed byte by byte
00611       crc = (crc >> 8) ^ crc32Table[(crc & 0xFF) ^ p[i]];
00612    }
00613 
00614    //Return 1's complement value
00615    return ~crc;
00616 
00617 //Bit by bit CRC calculation
00618 #else
00619    uint_t i;
00620    uint_t j;
00621 
00622    //Point to the data over which to calculate the CRC
00623    const uint8_t *p = (uint8_t *) data;
00624    //CRC preset value
00625    uint32_t crc = 0xFFFFFFFF;
00626 
00627    //Loop through data
00628    for(i = 0; i < length; i++)
00629    {
00630       //Update CRC value
00631       crc ^= p[i];
00632       //The message is processed bit by bit
00633       for(j = 0; j < 8; j++)
00634       {
00635          if(crc & 0x00000001)
00636             crc = (crc >> 1) ^ 0xEDB88320;
00637          else
00638             crc = crc >> 1;
00639       }
00640    }
00641 
00642    //Return 1's complement value
00643    return ~crc;
00644 #endif
00645 }
00646 
00647 
00648 /**
00649  * @brief Calculate CRC over a multi-part buffer
00650  * @param[in] buffer Pointer to the multi-part buffer
00651  * @param[in] offset Offset from the beginning of the buffer
00652  * @param[in] length Number of bytes to process
00653  * @return Resulting CRC value
00654  **/
00655 
00656 uint32_t ethCalcCrcEx(const NetBuffer *buffer, size_t offset, size_t length)
00657 {
00658    uint_t i;
00659    uint_t n;
00660    uint32_t crc;
00661    uint8_t *p;
00662 #if (ETH_FAST_CRC_SUPPORT == DISABLED)
00663    uint_t k;
00664 #endif
00665 
00666    //CRC preset value
00667    crc = 0xFFFFFFFF;
00668 
00669    //Loop through data chunks
00670    for(i = 0; i < buffer->chunkCount && length > 0; i++)
00671    {
00672       //Is there any data to process in the current chunk?
00673       if(offset < buffer->chunk[i].length)
00674       {
00675          //Point to the first data byte
00676          p = (uint8_t *) buffer->chunk[i].address + offset;
00677          //Compute the number of bytes to process
00678          n = MIN(buffer->chunk[i].length - offset, length);
00679          //Adjust byte counter
00680          length -= n;
00681 
00682          //Process current chunk
00683          while(n > 0)
00684          {
00685 #if (ETH_FAST_CRC_SUPPORT == ENABLED)
00686             //The message is processed byte by byte
00687             crc = (crc >> 8) ^ crc32Table[(crc & 0xFF) ^ *p];
00688 #else
00689             //Update CRC value
00690             crc ^= *p;
00691 
00692             //The message is processed bit by bit
00693             for(k = 0; k < 8; k++)
00694             {
00695                if(crc & 0x00000001)
00696                   crc = (crc >> 1) ^ 0xEDB88320;
00697                else
00698                   crc = crc >> 1;
00699             }
00700 #endif
00701             //Next byte
00702             p++;
00703             n--;
00704          }
00705 
00706          //Process the next block from the start
00707          offset = 0;
00708       }
00709       else
00710       {
00711          //Skip the current chunk
00712          offset -= buffer->chunk[i].length;
00713       }
00714    }
00715 
00716    //Return 1's complement value
00717    return ~crc;
00718 }
00719 
00720 
00721 /**
00722  * @brief Allocate a buffer to hold an Ethernet frame
00723  * @param[in] length Desired payload length
00724  * @param[out] offset Offset to the first byte of the payload
00725  * @return The function returns a pointer to the newly allocated
00726  *   buffer. If the system is out of resources, NULL is returned
00727  **/
00728 
00729 NetBuffer *ethAllocBuffer(size_t length, size_t *offset)
00730 {
00731    NetBuffer *buffer;
00732 
00733    //Allocate a buffer to hold the Ethernet header and the payload
00734    buffer = netBufferAlloc(length + sizeof(EthHeader));
00735    //Failed to allocate buffer?
00736    if(buffer == NULL)
00737       return NULL;
00738 
00739    //Offset to the first byte of the payload
00740    *offset = sizeof(EthHeader);
00741 
00742    //Return a pointer to the freshly allocated buffer
00743    return buffer;
00744 }
00745 
00746 
00747 /**
00748  * @brief Convert a string representation of a MAC address to a binary MAC address
00749  * @param[in] str NULL-terminated string representing the MAC address
00750  * @param[out] macAddr Binary representation of the MAC address
00751  * @return Error code
00752  **/
00753 
00754 error_t macStringToAddr(const char_t *str, MacAddr *macAddr)
00755 {
00756    error_t error;
00757    int_t i = 0;
00758    int_t value = -1;
00759 
00760    //Parse input string
00761    while(1)
00762    {
00763       //Hexadecimal digit found?
00764       if(isxdigit((uint8_t) *str))
00765       {
00766          //First digit to be decoded?
00767          if(value < 0) value = 0;
00768          //Update the value of the current byte
00769          if(isdigit((uint8_t) *str))
00770             value = (value * 16) + (*str - '0');
00771          else if(isupper((uint8_t) *str))
00772             value = (value * 16) + (*str - 'A' + 10);
00773          else
00774             value = (value * 16) + (*str - 'a' + 10);
00775          //Check resulting value
00776          if(value > 0xFF)
00777          {
00778             //The conversion failed
00779             error = ERROR_INVALID_SYNTAX;
00780             break;
00781          }
00782       }
00783       //Dash or colon separator found?
00784       else if((*str == '-' || *str == ':') && i < 6)
00785       {
00786          //Each separator must be preceded by a valid number
00787          if(value < 0)
00788          {
00789             //The conversion failed
00790             error = ERROR_INVALID_SYNTAX;
00791             break;
00792          }
00793 
00794          //Save the current byte
00795          macAddr->b[i++] = value;
00796          //Prepare to decode the next byte
00797          value = -1;
00798       }
00799       //End of string detected?
00800       else if(*str == '\0' && i == 5)
00801       {
00802          //The NULL character must be preceded by a valid number
00803          if(value < 0)
00804          {
00805             //The conversion failed
00806             error = ERROR_INVALID_SYNTAX;
00807          }
00808          else
00809          {
00810             //Save the last byte of the MAC address
00811             macAddr->b[i] = value;
00812             //The conversion succeeded
00813             error = NO_ERROR;
00814          }
00815 
00816          //We are done
00817          break;
00818       }
00819       //Invalid character...
00820       else
00821       {
00822          //The conversion failed
00823          error = ERROR_INVALID_SYNTAX;
00824          break;
00825       }
00826 
00827       //Point to the next character
00828       str++;
00829    }
00830 
00831    //Return status code
00832    return error;
00833 }
00834 
00835 
00836 /**
00837  * @brief Convert a MAC address to a dash delimited string
00838  * @param[in] macAddr Pointer to the MAC address
00839  * @param[out] str NULL-terminated string representing the MAC address
00840  * @return Pointer to the formatted string
00841  **/
00842 
00843 char_t *macAddrToString(const MacAddr *macAddr, char_t *str)
00844 {
00845    static char_t buffer[18];
00846 
00847    //The str parameter is optional
00848    if(str == NULL)
00849       str = buffer;
00850 
00851    //Format MAC address
00852    sprintf(str, "%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8,
00853       macAddr->b[0], macAddr->b[1], macAddr->b[2], macAddr->b[3], macAddr->b[4], macAddr->b[5]);
00854 
00855    //Return a pointer to the formatted string
00856    return str;
00857 }
00858 
00859 
00860 /**
00861  * @brief Convert a string representation of an EUI-64 address to a binary EUI-64 address
00862  * @param[in] str NULL-terminated string representing the EUI-64 address
00863  * @param[out] eui64 Binary representation of the EUI-64 address
00864  * @return Error code
00865  **/
00866 
00867 error_t eui64StringToAddr(const char_t *str, Eui64 *eui64)
00868 {
00869    error_t error;
00870    int_t i = 0;
00871    int_t value = -1;
00872 
00873    //Parse input string
00874    while(1)
00875    {
00876       //Hexadecimal digit found?
00877       if(isxdigit((uint8_t) *str))
00878       {
00879          //First digit to be decoded?
00880          if(value < 0) value = 0;
00881          //Update the value of the current byte
00882          if(isdigit((uint8_t) *str))
00883             value = (value * 16) + (*str - '0');
00884          else if(isupper((uint8_t) *str))
00885             value = (value * 16) + (*str - 'A' + 10);
00886          else
00887             value = (value * 16) + (*str - 'a' + 10);
00888          //Check resulting value
00889          if(value > 0xFF)
00890          {
00891             //The conversion failed
00892             error = ERROR_INVALID_SYNTAX;
00893             break;
00894          }
00895       }
00896       //Dash or colon separator found?
00897       else if((*str == '-' || *str == ':') && i < 8)
00898       {
00899          //Each separator must be preceded by a valid number
00900          if(value < 0)
00901          {
00902             //The conversion failed
00903             error = ERROR_INVALID_SYNTAX;
00904             break;
00905          }
00906 
00907          //Save the current byte
00908          eui64->b[i++] = value;
00909          //Prepare to decode the next byte
00910          value = -1;
00911       }
00912       //End of string detected?
00913       else if(*str == '\0' && i == 7)
00914       {
00915          //The NULL character must be preceded by a valid number
00916          if(value < 0)
00917          {
00918             //The conversion failed
00919             error = ERROR_INVALID_SYNTAX;
00920          }
00921          else
00922          {
00923             //Save the last byte of the EUI-64 address
00924             eui64->b[i] = value;
00925             //The conversion succeeded
00926             error = NO_ERROR;
00927          }
00928 
00929          //We are done
00930          break;
00931       }
00932       //Invalid character...
00933       else
00934       {
00935          //The conversion failed
00936          error = ERROR_INVALID_SYNTAX;
00937          break;
00938       }
00939 
00940       //Point to the next character
00941       str++;
00942    }
00943 
00944    //Return status code
00945    return error;
00946 }
00947 
00948 
00949 /**
00950  * @brief Convert an EUI-64 address to a dash delimited string
00951  * @param[in] eui64 Pointer to the EUI-64 address
00952  * @param[out] str NULL-terminated string representing the EUI-64 address
00953  * @return Pointer to the formatted string
00954  **/
00955 
00956 char_t *eui64AddrToString(const Eui64 *eui64, char_t *str)
00957 {
00958    static char_t buffer[24];
00959 
00960    //The str parameter is optional
00961    if(str == NULL)
00962       str = buffer;
00963 
00964    //Format EUI-64 identifier
00965    sprintf(str, "%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8
00966       "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8 "-%02" PRIX8,
00967       eui64->b[0], eui64->b[1], eui64->b[2], eui64->b[3],
00968       eui64->b[4], eui64->b[5], eui64->b[6], eui64->b[7]);
00969 
00970    //Return a pointer to the formatted string
00971    return str;
00972 }
00973 
00974 
00975 /**
00976  * @brief Map a MAC address to the IPv6 modified EUI-64 identifier
00977  * @param[in] macAddr Host MAC address
00978  * @param[out] interfaceId IPv6 modified EUI-64 identifier
00979  **/
00980 
00981 void macAddrToEui64(const MacAddr *macAddr, Eui64 *interfaceId)
00982 {
00983    //Copy the Organization Unique Identifier (OUI)
00984    interfaceId->b[0] = macAddr->b[0];
00985    interfaceId->b[1] = macAddr->b[1];
00986    interfaceId->b[2] = macAddr->b[2];
00987 
00988    //The middle 16 bits are given the value 0xFFFE
00989    interfaceId->b[3] = 0xFF;
00990    interfaceId->b[4] = 0xFE;
00991 
00992    //Copy the right-most 24 bits of the MAC address
00993    interfaceId->b[5] = macAddr->b[3];
00994    interfaceId->b[6] = macAddr->b[4];
00995    interfaceId->b[7] = macAddr->b[5];
00996 
00997    //Modified EUI-64 format interface identifiers are
00998    //formed by inverting the Universal/Local bit
00999    interfaceId->b[0] ^= MAC_ADDR_FLAG_LOCAL;
01000 }
01001 
01002 
01003 /**
01004  * @brief Dump Ethernet header for debugging purpose
01005  * @param[in] ethHeader Pointer to the Ethernet header
01006  **/
01007 
01008 void ethDumpHeader(const EthHeader *ethHeader)
01009 {
01010    //Dump Ethernet header contents
01011    TRACE_DEBUG("  Dest Addr = %s\r\n", macAddrToString(&ethHeader->destAddr, NULL));
01012    TRACE_DEBUG("  Src Addr = %s\r\n", macAddrToString(&ethHeader->srcAddr, NULL));
01013    TRACE_DEBUG("  Type = 0x%04" PRIX16 "\r\n", ntohs(ethHeader->type));
01014 }
01015 
01016 #endif
01017