Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ipv4.c Source File

ipv4.c

Go to the documentation of this file.
00001 /**
00002  * @file ipv4.c
00003  * @brief IPv4 (Internet Protocol Version 4)
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  * The Internet Protocol (IP) provides the functions necessary to deliver a
00028  * datagram from a source to a destination over an interconnected system of
00029  * networks. Refer to RFC 791 for complete details
00030  *
00031  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00032  * @version 1.7.6
00033  **/
00034 
00035 //Switch to the appropriate trace level
00036 #define TRACE_LEVEL IPV4_TRACE_LEVEL
00037 
00038 //Dependencies
00039 #include <string.h>
00040 #include <ctype.h>
00041 #include "core/net.h"
00042 #include "core/ethernet.h"
00043 #include "core/ip.h"
00044 #include "core/udp.h"
00045 #include "core/tcp_fsm.h"
00046 #include "core/raw_socket.h"
00047 #include "ipv4/arp.h"
00048 #include "ipv4/ipv4.h"
00049 #include "ipv4/ipv4_routing.h"
00050 #include "ipv4/icmp.h"
00051 #include "ipv4/igmp.h"
00052 #include "ipv4/auto_ip.h"
00053 #include "dhcp/dhcp_client.h"
00054 #include "mdns/mdns_responder.h"
00055 #include "mibs/mib2_module.h"
00056 #include "debug.h"
00057 
00058 //Check TCP/IP stack configuration
00059 #if (IPV4_SUPPORT == ENABLED)
00060 
00061 
00062 /**
00063  * @brief IPv4 related initialization
00064  * @param[in] interface Underlying network interface
00065  * @return Error code
00066  **/
00067 
00068 error_t ipv4Init(NetInterface *interface)
00069 {
00070    Ipv4Context *context;
00071 
00072    //Point to the IPv4 context
00073    context = &interface->ipv4Context;
00074 
00075    //Clear the IPv4 context
00076    memset(context, 0, sizeof(Ipv4Context));
00077 
00078    //Initialize interface specific variables
00079    context->linkMtu = interface->nicDriver->mtu;
00080    context->isRouter = FALSE;
00081 
00082    //Identification field is primarily used to identify
00083    //fragments of an original IP datagram
00084    context->identification = 0;
00085 
00086    //Initialize the list of DNS servers
00087    memset(context->dnsServerList, 0, sizeof(context->dnsServerList));
00088    //Initialize the multicast filter table
00089    memset(context->multicastFilter, 0, sizeof(context->multicastFilter));
00090 
00091 #if (IPV4_FRAG_SUPPORT == ENABLED)
00092    //Initialize the reassembly queue
00093    memset(context->fragQueue, 0, sizeof(context->fragQueue));
00094 #endif
00095 
00096    //Successful initialization
00097    return NO_ERROR;
00098 }
00099 
00100 
00101 /**
00102  * @brief Assign host address
00103  * @param[in] interface Pointer to the desired network interface
00104  * @param[in] addr IPv4 host address
00105  * @return Error code
00106  **/
00107 
00108 error_t ipv4SetHostAddr(NetInterface *interface, Ipv4Addr addr)
00109 {
00110    //Check parameters
00111    if(interface == NULL)
00112       return ERROR_INVALID_PARAMETER;
00113 
00114    //The IPv4 address must be a valid unicast address
00115    if(ipv4IsMulticastAddr(addr))
00116       return ERROR_INVALID_ADDRESS;
00117 
00118    //Get exclusive access
00119    osAcquireMutex(&netMutex);
00120 
00121    //Set up host address
00122    interface->ipv4Context.addr = addr;
00123    //Clear conflict flag
00124    interface->ipv4Context.addrConflict = FALSE;
00125 
00126    //Check whether the new host address is valid
00127    if(addr != IPV4_UNSPECIFIED_ADDR)
00128    {
00129       //The use of the IPv4 address is now unrestricted
00130       interface->ipv4Context.addrState = IPV4_ADDR_STATE_VALID;
00131    }
00132    else
00133    {
00134       //The IPv4 address is no longer valid
00135       interface->ipv4Context.addrState = IPV4_ADDR_STATE_INVALID;
00136    }
00137 
00138 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
00139    //Restart mDNS probing process
00140    mdnsResponderStartProbing(interface->mdnsResponderContext);
00141 #endif
00142 
00143    //Release exclusive access
00144    osReleaseMutex(&netMutex);
00145 
00146    //Successful processing
00147    return NO_ERROR;
00148 }
00149 
00150 
00151 /**
00152  * @brief Retrieve host address
00153  * @param[in] interface Pointer to the desired network interface
00154  * @param[out] addr IPv4 host address
00155  * @return Error code
00156  **/
00157 
00158 error_t ipv4GetHostAddr(NetInterface *interface, Ipv4Addr *addr)
00159 {
00160    //Check parameters
00161    if(interface == NULL || addr == NULL)
00162       return ERROR_INVALID_PARAMETER;
00163 
00164    //Get exclusive access
00165    osAcquireMutex(&netMutex);
00166 
00167    //Check whether the host address is valid
00168    if(interface->ipv4Context.addrState == IPV4_ADDR_STATE_VALID)
00169    {
00170       //Get IPv4 address
00171       *addr = interface->ipv4Context.addr;
00172    }
00173    else
00174    {
00175       //Return the unspecified address when no address has been assigned
00176       *addr = IPV4_UNSPECIFIED_ADDR;
00177    }
00178 
00179    //Release exclusive access
00180    osReleaseMutex(&netMutex);
00181 
00182    //Successful processing
00183    return NO_ERROR;
00184 }
00185 
00186 
00187 /**
00188  * @brief Configure subnet mask
00189  * @param[in] interface Pointer to the desired network interface
00190  * @param[in] mask Subnet mask
00191  * @return Error code
00192  **/
00193 
00194 error_t ipv4SetSubnetMask(NetInterface *interface, Ipv4Addr mask)
00195 {
00196    //Check parameters
00197    if(interface == NULL)
00198       return ERROR_INVALID_PARAMETER;
00199 
00200    //Get exclusive access
00201    osAcquireMutex(&netMutex);
00202    //Set up subnet mask
00203    interface->ipv4Context.subnetMask = mask;
00204    //Release exclusive access
00205    osReleaseMutex(&netMutex);
00206 
00207    //Successful processing
00208    return NO_ERROR;
00209 }
00210 
00211 
00212 /**
00213  * @brief Retrieve subnet mask
00214  * @param[in] interface Pointer to the desired network interface
00215  * @param[out] mask Subnet mask
00216  * @return Error code
00217  **/
00218 
00219 error_t ipv4GetSubnetMask(NetInterface *interface, Ipv4Addr *mask)
00220 {
00221    //Check parameters
00222    if(interface == NULL || mask == NULL)
00223       return ERROR_INVALID_PARAMETER;
00224 
00225    //Get exclusive access
00226    osAcquireMutex(&netMutex);
00227    //Get subnet mask
00228    *mask = interface->ipv4Context.subnetMask;
00229    //Release exclusive access
00230    osReleaseMutex(&netMutex);
00231 
00232    //Successful processing
00233    return NO_ERROR;
00234 }
00235 
00236 
00237 /**
00238  * @brief Configure default gateway
00239  * @param[in] interface Pointer to the desired network interface
00240  * @param[in] addr Default gateway address
00241  * @return Error code
00242  **/
00243 
00244 error_t ipv4SetDefaultGateway(NetInterface *interface, Ipv4Addr addr)
00245 {
00246    //Check parameters
00247    if(interface == NULL)
00248       return ERROR_INVALID_PARAMETER;
00249 
00250    //The IPv4 address must be a valid unicast address
00251    if(ipv4IsMulticastAddr(addr))
00252       return ERROR_INVALID_ADDRESS;
00253 
00254    //Get exclusive access
00255    osAcquireMutex(&netMutex);
00256    //Set up default gateway address
00257    interface->ipv4Context.defaultGateway = addr;
00258    //Release exclusive access
00259    osReleaseMutex(&netMutex);
00260 
00261    //Successful processing
00262    return NO_ERROR;
00263 }
00264 
00265 
00266 /**
00267  * @brief Retrieve default gateway
00268  * @param[in] interface Pointer to the desired network interface
00269  * @param[out] addr Default gateway address
00270  * @return Error code
00271  **/
00272 
00273 error_t ipv4GetDefaultGateway(NetInterface *interface, Ipv4Addr *addr)
00274 {
00275    //Check parameters
00276    if(interface == NULL || addr == NULL)
00277       return ERROR_INVALID_PARAMETER;
00278 
00279    //Get exclusive access
00280    osAcquireMutex(&netMutex);
00281    //Get default gateway address
00282    *addr = interface->ipv4Context.defaultGateway;
00283    //Release exclusive access
00284    osReleaseMutex(&netMutex);
00285 
00286    //Successful processing
00287    return NO_ERROR;
00288 }
00289 
00290 
00291 /**
00292  * @brief Configure DNS server
00293  * @param[in] interface Pointer to the desired network interface
00294  * @param[in] index This parameter selects between the primary and secondary DNS server
00295  * @param[in] addr DNS server address
00296  * @return Error code
00297  **/
00298 
00299 error_t ipv4SetDnsServer(NetInterface *interface, uint_t index, Ipv4Addr addr)
00300 {
00301    //Check parameters
00302    if(interface == NULL)
00303       return ERROR_INVALID_PARAMETER;
00304 
00305    //Make sure that the index is valid
00306    if(index >= IPV4_DNS_SERVER_LIST_SIZE)
00307       return ERROR_OUT_OF_RANGE;
00308 
00309    //The IPv4 address must be a valid unicast address
00310    if(ipv4IsMulticastAddr(addr))
00311       return ERROR_INVALID_ADDRESS;
00312 
00313    //Get exclusive access
00314    osAcquireMutex(&netMutex);
00315    //Set up DNS server address
00316    interface->ipv4Context.dnsServerList[index] = addr;
00317    //Release exclusive access
00318    osReleaseMutex(&netMutex);
00319 
00320    //Successful processing
00321    return NO_ERROR;
00322 }
00323 
00324 
00325 /**
00326  * @brief Retrieve DNS server
00327  * @param[in] interface Pointer to the desired network interface
00328  * @param[in] index This parameter selects between the primary and secondary DNS server
00329  * @param[out] addr DNS server address
00330  * @return Error code
00331  **/
00332 
00333 error_t ipv4GetDnsServer(NetInterface *interface, uint_t index, Ipv4Addr *addr)
00334 {
00335    //Check parameters
00336    if(interface == NULL || addr == NULL)
00337       return ERROR_INVALID_PARAMETER;
00338 
00339    //Make sure that the index is valid
00340    if(index >= IPV4_DNS_SERVER_LIST_SIZE)
00341    {
00342       //Return the unspecified address when the index is out of range
00343       *addr = IPV4_UNSPECIFIED_ADDR;
00344       //Report an error
00345       return ERROR_OUT_OF_RANGE;
00346    }
00347 
00348    //Get exclusive access
00349    osAcquireMutex(&netMutex);
00350    //Get DNS server address
00351    *addr = interface->ipv4Context.dnsServerList[index];
00352    //Release exclusive access
00353    osReleaseMutex(&netMutex);
00354 
00355    //Successful processing
00356    return NO_ERROR;
00357 }
00358 
00359 
00360 /**
00361  * @brief Get IPv4 broadcast address
00362  * @param[in] interface Pointer to the desired network interface
00363  * @param[out] addr IPv4 broadcast address
00364  **/
00365 
00366 error_t ipv4GetBroadcastAddr(NetInterface *interface, Ipv4Addr *addr)
00367 {
00368    //Check parameters
00369    if(interface == NULL || addr == NULL)
00370       return ERROR_INVALID_PARAMETER;
00371 
00372    //The broadcast address is obtained by performing a bitwise OR operation
00373    //between the bit complement of the subnet mask and the host IP address
00374    *addr = interface->ipv4Context.addr;
00375    *addr |= ~interface->ipv4Context.subnetMask;
00376 
00377    //Successful processing
00378    return NO_ERROR;
00379 }
00380 
00381 
00382 /**
00383  * @brief Callback function for link change event
00384  * @param[in] interface Underlying network interface
00385  **/
00386 
00387 void ipv4LinkChangeEvent(NetInterface *interface)
00388 {
00389    Ipv4Context *context;
00390 
00391    //Point to the IPv4 context
00392    context = &interface->ipv4Context;
00393 
00394    //Restore default MTU
00395    context->linkMtu = interface->nicDriver->mtu;
00396 
00397 #if (ETH_SUPPORT == ENABLED)
00398    //Flush ARP cache contents
00399    arpFlushCache(interface);
00400 #endif
00401 
00402 #if (IPV4_FRAG_SUPPORT == ENABLED)
00403    //Flush the reassembly queue
00404    ipv4FlushFragQueue(interface);
00405 #endif
00406 
00407 #if (IGMP_SUPPORT == ENABLED)
00408    //Notify IGMP of link state changes
00409    igmpLinkChangeEvent(interface);
00410 #endif
00411 
00412 #if (AUTO_IP_SUPPORT == ENABLED)
00413    //Notify Auto-IP of link state changes
00414    autoIpLinkChangeEvent(interface->autoIpContext);
00415 #endif
00416 
00417 #if (DHCP_CLIENT_SUPPORT == ENABLED)
00418    //Notify the DHCP client of link state changes
00419    dhcpClientLinkChangeEvent(interface->dhcpClientContext);
00420 #endif
00421 }
00422 
00423 
00424 /**
00425  * @brief Incoming IPv4 packet processing
00426  * @param[in] interface Underlying network interface
00427  * @param[in] packet Incoming IPv4 packet
00428  * @param[in] length Packet length including header and payload
00429  **/
00430 
00431 void ipv4ProcessPacket(NetInterface *interface, Ipv4Header *packet, size_t length)
00432 {
00433    //Total number of input datagrams received from interfaces,
00434    //including those received in error
00435    MIB2_INC_COUNTER32(mib2Base.ipGroup.ipInReceives, 1);
00436 
00437    //Ensure the packet length is greater than 20 bytes
00438    if(length < sizeof(Ipv4Header))
00439    {
00440       //Number of input datagrams discarded due to errors in their IP headers
00441       MIB2_INC_COUNTER32(mib2Base.ipGroup.ipInHdrErrors, 1);
00442       //Discard the received packet
00443       return;
00444    }
00445 
00446    //Debug message
00447    TRACE_INFO("IPv4 packet received (%" PRIuSIZE " bytes)...\r\n", length);
00448    //Dump IP header contents for debugging purpose
00449    ipv4DumpHeader(packet);
00450 
00451    //A packet whose version number is not 4 must be silently discarded
00452    if(packet->version != IPV4_VERSION)
00453    {
00454       //Number of input datagrams discarded due to errors in their IP headers
00455       MIB2_INC_COUNTER32(mib2Base.ipGroup.ipInHdrErrors, 1);
00456       //Discard the received packet
00457       return;
00458    }
00459 
00460    //Valid IPv4 header shall contains more than five 32-bit words
00461    if(packet->headerLength < 5)
00462    {
00463       //Number of input datagrams discarded due to errors in their IP headers
00464       MIB2_INC_COUNTER32(mib2Base.ipGroup.ipInHdrErrors, 1);
00465       //Discard the received packet
00466       return;
00467    }
00468 
00469    //Ensure the total length is correct before processing the packet
00470    if(ntohs(packet->totalLength) < (packet->headerLength * 4))
00471    {
00472       //Number of input datagrams discarded due to errors in their IP headers
00473       MIB2_INC_COUNTER32(mib2Base.ipGroup.ipInHdrErrors, 1);
00474       //Discard the received packet
00475       return;
00476    }
00477    if(ntohs(packet->totalLength) > length)
00478    {
00479       //Number of input datagrams discarded due to errors in their IP headers
00480       MIB2_INC_COUNTER32(mib2Base.ipGroup.ipInHdrErrors, 1);
00481       //Discard the received packet
00482       return;
00483    }
00484 
00485    //Source address filtering
00486    if(ipv4CheckSourceAddr(interface, packet->srcAddr))
00487    {
00488       //Number of input datagrams discarded due to errors in their IP headers
00489       MIB2_INC_COUNTER32(mib2Base.ipGroup.ipInHdrErrors, 1);
00490       //Discard the received packet
00491       return;
00492    }
00493 
00494 #if defined(IPV4_PACKET_FORWARD_HOOK)
00495    IPV4_PACKET_FORWARD_HOOK(interface, packet, length);
00496 #else
00497    //Destination address filtering
00498    if(ipv4CheckDestAddr(interface, packet->destAddr))
00499    {
00500 #if(IPV4_ROUTING_SUPPORT == ENABLED)
00501       NetBuffer1 buffer;
00502 
00503       //Unfragmented datagrams fit in a single chunk
00504       buffer.chunkCount = 1;
00505       buffer.maxChunkCount = 1;
00506       buffer.chunk[0].address = packet;
00507       buffer.chunk[0].length = length;
00508 
00509       //Forward the packet according to the routing table
00510       ipv4ForwardPacket(interface, (NetBuffer *) &buffer, 0);
00511 #else
00512       //Number of input datagrams discarded because the destination IP
00513       //address was not a valid address
00514       MIB2_INC_COUNTER32(mib2Base.ipGroup.ipInAddrErrors, 1);
00515 #endif
00516       //We are done
00517       return;
00518    }
00519 #endif
00520 
00521    //Packets addressed to a tentative address should be silently discarded
00522    if(ipv4IsTentativeAddr(interface, packet->destAddr))
00523    {
00524       //Number of input datagrams discarded because the destination IP
00525       //address was not a valid address
00526       MIB2_INC_COUNTER32(mib2Base.ipGroup.ipInAddrErrors, 1);
00527       //Discard the received packet
00528       return;
00529    }
00530 
00531    //The host must verify the IP header checksum on every received
00532    //datagram and silently discard every datagram that has a bad
00533    //checksum (see RFC 1122 3.2.1.2)
00534    if(ipCalcChecksum(packet, packet->headerLength * 4) != 0x0000)
00535    {
00536       //Debug message
00537       TRACE_WARNING("Wrong IP header checksum!\r\n");
00538       //Number of input datagrams discarded due to errors in their IP headers
00539       MIB2_INC_COUNTER32(mib2Base.ipGroup.ipInHdrErrors, 1);
00540       //Discard incoming packet
00541       return;
00542    }
00543 
00544    //Convert the total length from network byte order
00545    length = ntohs(packet->totalLength);
00546 
00547    //A fragmented packet was received?
00548    if(ntohs(packet->fragmentOffset) & (IPV4_FLAG_MF | IPV4_OFFSET_MASK))
00549    {
00550 #if (IPV4_FRAG_SUPPORT == ENABLED)
00551       //Reassemble the original datagram
00552       ipv4ReassembleDatagram(interface, packet, length);
00553 #endif
00554    }
00555    else
00556    {
00557       NetBuffer1 buffer;
00558 
00559       //Unfragmented datagrams fit in a single chunk
00560       buffer.chunkCount = 1;
00561       buffer.maxChunkCount = 1;
00562       buffer.chunk[0].address = packet;
00563       buffer.chunk[0].length = length;
00564 
00565       //Pass the IPv4 datagram to the higher protocol layer
00566       ipv4ProcessDatagram(interface, (NetBuffer *) &buffer);
00567    }
00568 }
00569 
00570 
00571 /**
00572  * @brief Incoming IPv4 datagram processing
00573  * @param[in] interface Underlying network interface
00574  * @param[in] buffer Multi-part buffer that holds the incoming IPv4 datagram
00575  **/
00576 
00577 void ipv4ProcessDatagram(NetInterface *interface, const NetBuffer *buffer)
00578 {
00579    error_t error;
00580    size_t offset;
00581    size_t length;
00582    Ipv4Header *header;
00583    IpPseudoHeader pseudoHeader;
00584 
00585    //Retrieve the length of the IPv4 datagram
00586    length = netBufferGetLength(buffer);
00587 
00588    //Point to the IPv4 header
00589    header = netBufferAt(buffer, 0);
00590    //Sanity check
00591    if(header == NULL)
00592       return;
00593 
00594    //Debug message
00595    TRACE_INFO("IPv4 datagram received (%" PRIuSIZE " bytes)...\r\n", length);
00596    //Dump IP header contents for debugging purpose
00597    ipv4DumpHeader(header);
00598 
00599    //Get the offset to the payload
00600    offset = header->headerLength * 4;
00601    //Compute the length of the payload
00602    length -= header->headerLength * 4;
00603 
00604    //Form the IPv4 pseudo header
00605    pseudoHeader.length = sizeof(Ipv4PseudoHeader);
00606    pseudoHeader.ipv4Data.srcAddr = header->srcAddr;
00607    pseudoHeader.ipv4Data.destAddr = header->destAddr;
00608    pseudoHeader.ipv4Data.reserved = 0;
00609    pseudoHeader.ipv4Data.protocol = header->protocol;
00610    pseudoHeader.ipv4Data.length = htons(length);
00611 
00612 #if defined(IPV4_DATAGRAM_FORWARD_HOOK)
00613    IPV4_DATAGRAM_FORWARD_HOOK(interface, &pseudoHeader, buffer, offset);
00614 #endif
00615 
00616    //Check the protocol field
00617    switch(header->protocol)
00618    {
00619    //ICMP protocol?
00620    case IPV4_PROTOCOL_ICMP:
00621       //Process incoming ICMP message
00622       icmpProcessMessage(interface, header->srcAddr, buffer, offset);
00623 #if (RAW_SOCKET_SUPPORT == ENABLED)
00624       //Allow raw sockets to process ICMP messages
00625       rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset);
00626 #endif
00627       //No error to report
00628       error = NO_ERROR;
00629       //Continue processing
00630       break;
00631 
00632 #if (IGMP_SUPPORT == ENABLED)
00633    //IGMP protocol?
00634    case IPV4_PROTOCOL_IGMP:
00635       //Process incoming IGMP message
00636       igmpProcessMessage(interface, buffer, offset);
00637 #if (RAW_SOCKET_SUPPORT == ENABLED)
00638       //Allow raw sockets to process IGMP messages
00639       rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset);
00640 #endif
00641       //No error to report
00642       error = NO_ERROR;
00643       //Continue processing
00644       break;
00645 #endif
00646 
00647 #if (TCP_SUPPORT == ENABLED)
00648    //TCP protocol?
00649    case IPV4_PROTOCOL_TCP:
00650       //Process incoming TCP segment
00651       tcpProcessSegment(interface, &pseudoHeader, buffer, offset);
00652       //No error to report
00653       error = NO_ERROR;
00654       //Continue processing
00655       break;
00656 #endif
00657 
00658 #if (UDP_SUPPORT == ENABLED)
00659    //UDP protocol?
00660    case IPV4_PROTOCOL_UDP:
00661       //Process incoming UDP datagram
00662       error = udpProcessDatagram(interface, &pseudoHeader, buffer, offset);
00663       //Continue processing
00664       break;
00665 #endif
00666 
00667    //Unknown protocol?
00668    default:
00669 #if (RAW_SOCKET_SUPPORT == ENABLED)
00670       //Allow raw sockets to process IPv4 packets
00671       error = rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset);
00672 #else
00673       //Report an error
00674       error = ERROR_PROTOCOL_UNREACHABLE;
00675 #endif
00676       //Continue processing
00677       break;
00678    }
00679 
00680    //Unreachable protocol?
00681    if(error == ERROR_PROTOCOL_UNREACHABLE)
00682    {
00683       //Number of locally-addressed datagrams received successfully but
00684       //discarded because of an unknown or unsupported protocol
00685       MIB2_INC_COUNTER32(mib2Base.ipGroup.ipInUnknownProtos, 1);
00686 
00687       //Send a Destination Unreachable message
00688       icmpSendErrorMessage(interface, ICMP_TYPE_DEST_UNREACHABLE,
00689          ICMP_CODE_PROTOCOL_UNREACHABLE, 0, buffer, 0);
00690    }
00691    else
00692    {
00693       //Total number of input datagrams successfully delivered to IP
00694       //user-protocols
00695       MIB2_INC_COUNTER32(mib2Base.ipGroup.ipInDelivers, 1);
00696    }
00697 
00698    //Unreachable port?
00699    if(error == ERROR_PORT_UNREACHABLE)
00700    {
00701       //Send a Destination Unreachable message
00702       icmpSendErrorMessage(interface, ICMP_TYPE_DEST_UNREACHABLE,
00703          ICMP_CODE_PORT_UNREACHABLE, 0, buffer, 0);
00704    }
00705 }
00706 
00707 
00708 /**
00709  * @brief Send an IPv4 datagram
00710  * @param[in] interface Underlying network interface
00711  * @param[in] pseudoHeader IPv4 pseudo header
00712  * @param[in] buffer Multi-part buffer containing the payload
00713  * @param[in] offset Offset to the first byte of the payload
00714  * @param[in] ttl TTL value. Default Time-To-Live is used when this parameter is zero
00715  * @return Error code
00716  **/
00717 
00718 error_t ipv4SendDatagram(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader,
00719    NetBuffer *buffer, size_t offset, uint8_t ttl)
00720 {
00721    error_t error;
00722    size_t length;
00723    uint16_t id;
00724 
00725    //Total number of IP datagrams which local IP user-protocols supplied
00726    //to IP in requests for transmission
00727    MIB2_INC_COUNTER32(mib2Base.ipGroup.ipOutRequests, 1);
00728 
00729    //Retrieve the length of payload
00730    length = netBufferGetLength(buffer) - offset;
00731 
00732    //Check whether the TTL value is zero
00733    if(ttl == 0)
00734    {
00735       //Use default Time-To-Live value
00736       ttl = IPV4_DEFAULT_TTL;
00737    }
00738 
00739    //Identification field is primarily used to identify
00740    //fragments of an original IP datagram
00741    id = interface->ipv4Context.identification++;
00742 
00743    //If the payload length is smaller than the network
00744    //interface MTU then no fragmentation is needed
00745    if((length + sizeof(Ipv4Header)) <= interface->ipv4Context.linkMtu)
00746    {
00747       //Send data as is
00748       error = ipv4SendPacket(interface,
00749          pseudoHeader, id, 0, buffer, offset, ttl);
00750    }
00751    //If the payload length exceeds the network interface MTU
00752    //then the device must fragment the data
00753    else
00754    {
00755 #if (IPV4_FRAG_SUPPORT == ENABLED)
00756       //Fragment IP datagram into smaller packets
00757       error = ipv4FragmentDatagram(interface,
00758          pseudoHeader, id, buffer, offset, ttl);
00759 #else
00760       //Fragmentation is not supported
00761       error = ERROR_MESSAGE_TOO_LONG;
00762 #endif
00763    }
00764 
00765    //Return status code
00766    return error;
00767 }
00768 
00769 
00770 /**
00771  * @brief Send an IPv4 packet
00772  * @param[in] interface Underlying network interface
00773  * @param[in] pseudoHeader IPv4 pseudo header
00774  * @param[in] fragId Fragment identification field
00775  * @param[in] fragOffset Fragment offset field
00776  * @param[in] buffer Multi-part buffer containing the payload
00777  * @param[in] offset Offset to the first byte of the payload
00778  * @param[in] ttl Time-To-Live value
00779  * @return Error code
00780  **/
00781 
00782 error_t ipv4SendPacket(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader,
00783    uint16_t fragId, size_t fragOffset, NetBuffer *buffer, size_t offset, uint8_t ttl)
00784 {
00785    error_t error;
00786    size_t length;
00787    Ipv4Header *packet;
00788 
00789    //Is there enough space for the IPv4 header?
00790    if(offset < sizeof(Ipv4Header))
00791       return ERROR_INVALID_PARAMETER;
00792 
00793    //Make room for the header
00794    offset -= sizeof(Ipv4Header);
00795    //Calculate the size of the entire packet, including header and data
00796    length = netBufferGetLength(buffer) - offset;
00797 
00798    //Point to the IPv4 header
00799    packet = netBufferAt(buffer, offset);
00800 
00801    //Format IPv4 header
00802    packet->version = IPV4_VERSION;
00803    packet->headerLength = 5;
00804    packet->typeOfService = 0;
00805    packet->totalLength = htons(length);
00806    packet->identification = htons(fragId);
00807    packet->fragmentOffset = htons(fragOffset);
00808    packet->timeToLive = ttl;
00809    packet->protocol = pseudoHeader->protocol;
00810    packet->headerChecksum = 0;
00811    packet->srcAddr = pseudoHeader->srcAddr;
00812    packet->destAddr = pseudoHeader->destAddr;
00813 
00814    //Calculate IP header checksum
00815    packet->headerChecksum = ipCalcChecksumEx(buffer, offset, packet->headerLength * 4);
00816 
00817    //Ensure the source address is valid
00818    error = ipv4CheckSourceAddr(interface, pseudoHeader->srcAddr);
00819    //Invalid source address?
00820    if(error)
00821       return error;
00822 
00823    //Destination address is the unspecified address?
00824    if(pseudoHeader->destAddr == IPV4_UNSPECIFIED_ADDR)
00825    {
00826       //Destination address is not acceptable
00827       return ERROR_INVALID_ADDRESS;
00828    }
00829    //Destination address is the loopback address?
00830    else if(pseudoHeader->destAddr == IPV4_LOOPBACK_ADDR)
00831    {
00832       //Not yet implemented...
00833       return ERROR_NOT_IMPLEMENTED;
00834    }
00835 
00836 #if (ETH_SUPPORT == ENABLED)
00837    //Ethernet interface?
00838    if(interface->nicDriver->type == NIC_TYPE_ETHERNET)
00839    {
00840       Ipv4Addr destIpAddr;
00841       MacAddr destMacAddr;
00842 
00843       //Get the destination IPv4 address
00844       destIpAddr = pseudoHeader->destAddr;
00845 
00846       //Destination address is a broadcast address?
00847       if(ipv4IsBroadcastAddr(interface, destIpAddr))
00848       {
00849          //Use of the broadcast MAC address to send the packet
00850          destMacAddr = MAC_BROADCAST_ADDR;
00851          //No error to report
00852          error = NO_ERROR;
00853       }
00854       //Destination address is a multicast address?
00855       else if(ipv4IsMulticastAddr(destIpAddr))
00856       {
00857          //Map IPv4 multicast address to MAC-layer multicast address
00858          error = ipv4MapMulticastAddrToMac(destIpAddr, &destMacAddr);
00859       }
00860       //Source or destination address is a link-local address?
00861       else if(ipv4IsLinkLocalAddr(pseudoHeader->srcAddr) ||
00862          ipv4IsLinkLocalAddr(destIpAddr))
00863       {
00864          //Packets with a link-local source or destination address are not
00865          //routable off the link
00866          error = arpResolve(interface, destIpAddr, &destMacAddr);
00867       }
00868       //Destination host is on the local subnet?
00869       else if(ipv4IsOnLocalSubnet(interface, destIpAddr))
00870       {
00871          //Resolve destination address before sending the packet
00872          error = arpResolve(interface, destIpAddr, &destMacAddr);
00873       }
00874       //Destination host is outside the local subnet?
00875       else
00876       {
00877          //Make sure the default gateway is properly set
00878          if(interface->ipv4Context.defaultGateway != IPV4_UNSPECIFIED_ADDR)
00879          {
00880             //Use the default gateway to forward the packet
00881             destIpAddr = interface->ipv4Context.defaultGateway;
00882             //Perform address resolution
00883             error = arpResolve(interface, destIpAddr, &destMacAddr);
00884          }
00885          else
00886          {
00887             //Number of IP datagrams discarded because no route could be found
00888             //to transmit them to their destination
00889             MIB2_INC_COUNTER32(mib2Base.ipGroup.ipOutNoRoutes, 1);
00890 
00891             //Report an error
00892             error = ERROR_NO_ROUTE;
00893          }
00894       }
00895 
00896       //Successful address resolution?
00897       if(!error)
00898       {
00899          //Debug message
00900          TRACE_INFO("Sending IPv4 packet (%" PRIuSIZE " bytes)...\r\n", length);
00901          //Dump IP header contents for debugging purpose
00902          ipv4DumpHeader(packet);
00903 
00904          //Send Ethernet frame
00905          error = ethSendFrame(interface, &destMacAddr, buffer, offset, ETH_TYPE_IPV4);
00906       }
00907       //Address resolution is in progress?
00908       else if(error == ERROR_IN_PROGRESS)
00909       {
00910          //Debug message
00911          TRACE_INFO("Enqueuing IPv4 packet (%" PRIuSIZE " bytes)...\r\n", length);
00912          //Dump IP header contents for debugging purpose
00913          ipv4DumpHeader(packet);
00914 
00915          //Enqueue packets waiting for address resolution
00916          error = arpEnqueuePacket(interface, destIpAddr, buffer, offset);
00917       }
00918       //Address resolution failed?
00919       else
00920       {
00921          //Debug message
00922          TRACE_WARNING("Cannot map IPv4 address to Ethernet address!\r\n");
00923       }
00924    }
00925    else
00926 #endif
00927 #if (PPP_SUPPORT == ENABLED)
00928    //PPP interface?
00929    if(interface->nicDriver->type == NIC_TYPE_PPP)
00930    {
00931       //Debug message
00932       TRACE_INFO("Sending IPv4 packet (%" PRIuSIZE " bytes)...\r\n", length);
00933       //Dump IP header contents for debugging purpose
00934       ipv4DumpHeader(packet);
00935 
00936       //Send PPP frame
00937       error = pppSendFrame(interface, buffer, offset, PPP_PROTOCOL_IP);
00938    }
00939    else
00940 #endif
00941    //Unknown interface type?
00942    {
00943       //Report an error
00944       error = ERROR_INVALID_INTERFACE;
00945    }
00946 
00947    //Return status code
00948    return error;
00949 }
00950 
00951 
00952 /**
00953  * @brief Source IPv4 address filtering
00954  * @param[in] interface Underlying network interface
00955  * @param[in] ipAddr Source IPv4 address to be checked
00956  * @return Error code
00957  **/
00958 
00959 error_t ipv4CheckSourceAddr(NetInterface *interface, Ipv4Addr ipAddr)
00960 {
00961    //Broadcast and multicast addresses must not be used as source
00962    //address (see RFC 1122 3.2.1.3)
00963    if(ipv4IsBroadcastAddr(interface, ipAddr) || ipv4IsMulticastAddr(ipAddr))
00964    {
00965       //Debug message
00966       TRACE_WARNING("Wrong source IPv4 address!\r\n");
00967       //The source address not is acceptable
00968       return ERROR_INVALID_ADDRESS;
00969    }
00970 
00971    //The source address is acceptable
00972    return NO_ERROR;
00973 }
00974 
00975 
00976 /**
00977  * @brief Destination IPv4 address filtering
00978  * @param[in] interface Underlying network interface
00979  * @param[in] ipAddr Destination IPv4 address to be checked
00980  * @return Error code
00981  **/
00982 
00983 error_t ipv4CheckDestAddr(NetInterface *interface, Ipv4Addr ipAddr)
00984 {
00985    error_t error;
00986    uint_t i;
00987    Ipv4FilterEntry *entry;
00988 
00989    //Filter out any invalid addresses
00990    error = ERROR_INVALID_ADDRESS;
00991 
00992    //Broadcast address?
00993    if(ipv4IsBroadcastAddr(interface, ipAddr))
00994    {
00995       //Always accept broadcast address
00996       error = NO_ERROR;
00997    }
00998    //Multicast address?
00999    else if(ipv4IsMulticastAddr(ipAddr))
01000    {
01001       //Go through the multicast filter table
01002       for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
01003       {
01004          //Point to the current entry
01005          entry = &interface->ipv4Context.multicastFilter[i];
01006 
01007          //Valid entry?
01008          if(entry->refCount > 0)
01009          {
01010             //Check whether the destination IPv4 address matches
01011             //a relevant multicast address
01012             if(entry->addr == ipAddr)
01013             {
01014                //The multicast address is acceptable
01015                error = NO_ERROR;
01016                //Stop immediately
01017                break;
01018             }
01019          }
01020       }
01021    }
01022    //Unicast address?
01023    else
01024    {
01025       //Valid host address?
01026       if(interface->ipv4Context.addrState != IPV4_ADDR_STATE_INVALID)
01027       {
01028          //Check whether the destination address matches the host address
01029          if(interface->ipv4Context.addr == ipAddr)
01030          {
01031             //The destination address is acceptable
01032             error = NO_ERROR;
01033          }
01034       }
01035    }
01036 
01037    //Return status code
01038    return error;
01039 }
01040 
01041 
01042 /**
01043  * @brief IPv4 source address selection
01044  *
01045  * This function selects the source address and the relevant network interface
01046  * to be used in order to join the specified destination address
01047  *
01048  * @param[in,out] interface A pointer to a valid network interface may be provided as
01049  *   a hint. The function returns a pointer identifying the interface to be used
01050  * @param[in] destAddr Destination IPv4 address
01051  * @param[out] srcAddr Local IPv4 address to be used
01052  * @return Error code
01053  **/
01054 
01055 error_t ipv4SelectSourceAddr(NetInterface **interface,
01056    Ipv4Addr destAddr, Ipv4Addr *srcAddr)
01057 {
01058    uint_t i;
01059    NetInterface *currentInterface;
01060    NetInterface *bestInterface;
01061 
01062    //Initialize variables
01063    bestInterface = NULL;
01064 
01065    //Loop through network interfaces
01066    for(i = 0; i < NET_INTERFACE_COUNT; i++)
01067    {
01068       //Point to the current interface
01069       currentInterface = &netInterface[i];
01070 
01071       //A network interface may be provided as a hint...
01072       if(*interface != currentInterface && *interface != NULL)
01073       {
01074          //Select the next interface in the list
01075          continue;
01076       }
01077 
01078       //Check the state of the address
01079       if(currentInterface->ipv4Context.addrState != IPV4_ADDR_STATE_VALID)
01080       {
01081          //Select the next interface in the list
01082          continue;
01083       }
01084 
01085       //Select the first interface as default
01086       if(bestInterface == NULL)
01087       {
01088          //Give the current interface the higher precedence
01089          bestInterface = currentInterface;
01090          //Select the next interface in the list
01091          continue;
01092       }
01093 
01094       //Prefer same address
01095       if(bestInterface->ipv4Context.addr == destAddr)
01096       {
01097          //Select the next interface in the list
01098          continue;
01099       }
01100       else if(currentInterface->ipv4Context.addr == destAddr)
01101       {
01102          //Give the current interface the higher precedence
01103          bestInterface = currentInterface;
01104          //Select the next interface in the list
01105          continue;
01106       }
01107 
01108       //Prefer appropriate scope
01109       if(ipv4GetAddrScope(currentInterface->ipv4Context.addr) <
01110          ipv4GetAddrScope(bestInterface->ipv4Context.addr))
01111       {
01112          if(ipv4GetAddrScope(currentInterface->ipv4Context.addr) >=
01113             ipv4GetAddrScope(destAddr))
01114          {
01115             //Give the current interface the higher precedence
01116             bestInterface = currentInterface;
01117          }
01118 
01119          //Select the next interface in the list
01120          continue;
01121       }
01122       else if(ipv4GetAddrScope(bestInterface->ipv4Context.addr) <
01123          ipv4GetAddrScope(currentInterface->ipv4Context.addr))
01124       {
01125          if(ipv4GetAddrScope(bestInterface->ipv4Context.addr) <
01126             ipv4GetAddrScope(destAddr))
01127          {
01128             //Give the current interface the higher precedence
01129             bestInterface = currentInterface;
01130          }
01131 
01132          //Select the next interface in the list
01133          continue;
01134       }
01135 
01136       //Prefer appropriate subnet mask
01137       if(ipv4IsOnLocalSubnet(bestInterface, destAddr))
01138       {
01139          //Select the next interface in the list
01140          continue;
01141       }
01142       else if(ipv4IsOnLocalSubnet(currentInterface, destAddr))
01143       {
01144          //Give the current interface the higher precedence
01145          bestInterface = currentInterface;
01146          //Select the next interface in the list
01147          continue;
01148       }
01149    }
01150 
01151    //Source address selection failed?
01152    if(bestInterface == NULL)
01153    {
01154       //Report an error
01155       return ERROR_NO_ADDRESS;
01156    }
01157 
01158    //Return the out-going interface and the source address to be used
01159    *interface = bestInterface;
01160    *srcAddr = bestInterface->ipv4Context.addr;
01161 
01162    //Successful source address selection
01163    return NO_ERROR;
01164 }
01165 
01166 
01167 /**
01168  * @brief Check whether an IPv4 address is a broadcast address
01169  * @param[in] interface Underlying network interface
01170  * @param[in] ipAddr IPv4 address to be checked
01171  * @return TRUE if the IPv4 address is a broadcast address, else FALSE
01172  **/
01173 
01174 bool_t ipv4IsBroadcastAddr(NetInterface *interface, Ipv4Addr ipAddr)
01175 {
01176    //Check whether the specified IPv4 address is the broadcast address
01177    if(ipAddr == IPV4_BROADCAST_ADDR)
01178       return TRUE;
01179 
01180    //Check whether the specified IPv4 address belongs to the local network
01181    if(ipv4IsOnLocalSubnet(interface, ipAddr))
01182    {
01183       //Make sure the subnet mask is not 255.255.255.255
01184       if(interface->ipv4Context.subnetMask != IPV4_BROADCAST_ADDR)
01185       {
01186          //Directed broadcast address?
01187          if((ipAddr | interface->ipv4Context.subnetMask) == IPV4_BROADCAST_ADDR)
01188             return TRUE;
01189       }
01190    }
01191 
01192    //The specified IPv4 address is not a broadcast address
01193    return FALSE;
01194 }
01195 
01196 
01197 /**
01198  * @brief Retrieve the scope of an IPv4 address
01199  * @param[in] ipAddr IPv4 address
01200  * @return IPv4 address scope
01201  **/
01202 
01203 uint_t ipv4GetAddrScope(Ipv4Addr ipAddr)
01204 {
01205    uint_t scope;
01206 
01207    //Broadcast address?
01208    if(ipAddr == IPV4_BROADCAST_ADDR)
01209    {
01210       //The broadcast address is never forwarded by the routers connecting
01211       //the local network to other networks
01212       scope = IPV4_ADDR_SCOPE_LINK_LOCAL;
01213    }
01214    //Multicast address?
01215    else if(ipv4IsMulticastAddr(ipAddr))
01216    {
01217       //Local Network Control Block?
01218       if((ipAddr & IPV4_MULTICAST_LNCB_MASK) == IPV4_MULTICAST_LNCB_PREFIX)
01219       {
01220          //Addresses in the Local Network Control Block are used for protocol
01221          //control traffic that is not forwarded off link
01222          scope = IPV4_ADDR_SCOPE_LINK_LOCAL;
01223       }
01224       //Any other multicast address?
01225       else
01226       {
01227          //Other addresses are assigned global scope
01228          scope = IPV4_ADDR_SCOPE_GLOBAL;
01229       }
01230    }
01231    //Unicast address?
01232    else
01233    {
01234       //Loopback address?
01235       if((ipAddr & IPV4_LOOPBACK_ADDR_MASK) == IPV4_LOOPBACK_ADDR_PREFIX)
01236       {
01237          //IPv4 loopback addresses, which have the prefix 127.0.0.0/8,
01238          //are assigned interface-local scope
01239          scope = IPV4_ADDR_SCOPE_INTERFACE_LOCAL;
01240       }
01241       //Link-local address?
01242       else if((ipAddr & IPV4_LINK_LOCAL_MASK) == IPV4_LINK_LOCAL_PREFIX)
01243       {
01244          //IPv4 auto-configuration addresses, which have the prefix
01245          //169.254.0.0/16, are assigned link-local scope
01246          scope = IPV4_ADDR_SCOPE_LINK_LOCAL;
01247       }
01248       //Any other unicast address?
01249       else
01250       {
01251          //Other addresses are assigned global scope
01252          scope = IPV4_ADDR_SCOPE_GLOBAL;
01253       }
01254    }
01255 
01256    //Return the scope of the specified IPv4 address
01257    return scope;
01258 }
01259 
01260 
01261 /**
01262  * @brief Join the specified host group
01263  * @param[in] interface Underlying network interface
01264  * @param[in] groupAddr IPv4 address identifying the host group to join
01265  * @return Error code
01266  **/
01267 
01268 error_t ipv4JoinMulticastGroup(NetInterface *interface, Ipv4Addr groupAddr)
01269 {
01270    error_t error;
01271    uint_t i;
01272    Ipv4FilterEntry *entry;
01273    Ipv4FilterEntry *firstFreeEntry;
01274 #if (ETH_SUPPORT == ENABLED)
01275    MacAddr macAddr;
01276 #endif
01277 
01278    //The IPv4 address must be a valid multicast address
01279    if(!ipv4IsMulticastAddr(groupAddr))
01280       return ERROR_INVALID_ADDRESS;
01281 
01282    //Initialize error code
01283    error = NO_ERROR;
01284    //Keep track of the first free entry
01285    firstFreeEntry = NULL;
01286 
01287    //Go through the multicast filter table
01288    for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
01289    {
01290       //Point to the current entry
01291       entry = &interface->ipv4Context.multicastFilter[i];
01292 
01293       //Valid entry?
01294       if(entry->refCount > 0)
01295       {
01296          //Check whether the table already contains the specified IPv4 address
01297          if(entry->addr == groupAddr)
01298          {
01299             //Increment the reference count
01300             entry->refCount++;
01301             //Successful processing
01302             return NO_ERROR;
01303          }
01304       }
01305       else
01306       {
01307          //Keep track of the first free entry
01308          if(firstFreeEntry == NULL)
01309             firstFreeEntry = entry;
01310       }
01311    }
01312 
01313    //Check whether the multicast filter table is full
01314    if(firstFreeEntry == NULL)
01315    {
01316       //A new entry cannot be added
01317       return ERROR_FAILURE;
01318    }
01319 
01320 #if (ETH_SUPPORT == ENABLED)
01321    //Map the IPv4 multicast address to a MAC-layer address
01322    ipv4MapMulticastAddrToMac(groupAddr, &macAddr);
01323    //Add the corresponding address to the MAC filter table
01324    error = ethAcceptMulticastAddr(interface, &macAddr);
01325 #endif
01326 
01327    //MAC filter table successfully updated?
01328    if(!error)
01329    {
01330       //Now we can safely add a new entry to the table
01331       firstFreeEntry->addr = groupAddr;
01332       //Initialize the reference count
01333       firstFreeEntry->refCount = 1;
01334 
01335 #if (IGMP_SUPPORT == ENABLED)
01336       //Report multicast group membership to the router
01337       igmpJoinGroup(interface, firstFreeEntry);
01338 #endif
01339    }
01340 
01341    //Return status code
01342    return error;
01343 }
01344 
01345 
01346 /**
01347  * @brief Leave the specified host group
01348  * @param[in] interface Underlying network interface
01349  * @param[in] groupAddr IPv4 address identifying the host group to leave
01350  * @return Error code
01351  **/
01352 
01353 error_t ipv4LeaveMulticastGroup(NetInterface *interface, Ipv4Addr groupAddr)
01354 {
01355    uint_t i;
01356    Ipv4FilterEntry *entry;
01357 #if (ETH_SUPPORT == ENABLED)
01358    MacAddr macAddr;
01359 #endif
01360 
01361    //The IPv4 address must be a valid multicast address
01362    if(!ipv4IsMulticastAddr(groupAddr))
01363       return ERROR_INVALID_ADDRESS;
01364 
01365    //Go through the multicast filter table
01366    for(i = 0; i < IPV4_MULTICAST_FILTER_SIZE; i++)
01367    {
01368       //Point to the current entry
01369       entry = &interface->ipv4Context.multicastFilter[i];
01370 
01371       //Valid entry?
01372       if(entry->refCount > 0)
01373       {
01374          //Specified IPv4 address found?
01375          if(entry->addr == groupAddr)
01376          {
01377             //Decrement the reference count
01378             entry->refCount--;
01379 
01380             //Remove the entry if the reference count drops to zero
01381             if(entry->refCount == 0)
01382             {
01383 #if (IGMP_SUPPORT == ENABLED)
01384                //Report group membership termination
01385                igmpLeaveGroup(interface, entry);
01386 #endif
01387 #if (ETH_SUPPORT == ENABLED)
01388                //Map the IPv4 multicast address to a MAC-layer address
01389                ipv4MapMulticastAddrToMac(groupAddr, &macAddr);
01390                //Drop the corresponding address from the MAC filter table
01391                ethDropMulticastAddr(interface, &macAddr);
01392 #endif
01393                //Remove the multicast address from the list
01394                entry->addr = IPV4_UNSPECIFIED_ADDR;
01395             }
01396 
01397             //Successful processing
01398             return NO_ERROR;
01399          }
01400       }
01401    }
01402 
01403    //The specified IPv4 address does not exist
01404    return ERROR_ADDRESS_NOT_FOUND;
01405 }
01406 
01407 
01408 /**
01409  * @brief Map an host group address to a MAC-layer multicast address
01410  * @param[in] ipAddr IPv4 host group address
01411  * @param[out] macAddr Corresponding MAC-layer multicast address
01412  * @return Error code
01413  **/
01414 
01415 error_t ipv4MapMulticastAddrToMac(Ipv4Addr ipAddr, MacAddr *macAddr)
01416 {
01417    uint8_t *p;
01418 
01419    //Ensure the specified IPv4 address is a valid host group address
01420    if(!ipv4IsMulticastAddr(ipAddr))
01421       return ERROR_INVALID_ADDRESS;
01422 
01423    //Cast the address to byte array
01424    p = (uint8_t *) &ipAddr;
01425 
01426    //An IP host group address is mapped to an Ethernet multicast address
01427    //by placing the low-order 23-bits of the IP address into the low-order
01428    //23 bits of the Ethernet multicast address 01-00-5E-00-00-00
01429    macAddr->b[0] = 0x01;
01430    macAddr->b[1] = 0x00;
01431    macAddr->b[2] = 0x5E;
01432    macAddr->b[3] = p[1] & 0x7F;
01433    macAddr->b[4] = p[2];
01434    macAddr->b[5] = p[3];
01435 
01436    //The specified host group address was successfully
01437    //mapped to a MAC-layer address
01438    return NO_ERROR;
01439 }
01440 
01441 
01442 /**
01443  * @brief Convert a dot-decimal string to a binary IPv4 address
01444  * @param[in] str NULL-terminated string representing the IPv4 address
01445  * @param[out] ipAddr Binary representation of the IPv4 address
01446  * @return Error code
01447  **/
01448 
01449 error_t ipv4StringToAddr(const char_t *str, Ipv4Addr *ipAddr)
01450 {
01451    error_t error;
01452    int_t i = 0;
01453    int_t value = -1;
01454 
01455    //Parse input string
01456    while(1)
01457    {
01458       //Decimal digit found?
01459       if(isdigit((uint8_t) *str))
01460       {
01461          //First digit to be decoded?
01462          if(value < 0) value = 0;
01463          //Update the value of the current byte
01464          value = (value * 10) + (*str - '0');
01465 
01466          //The resulting value shall be in range 0 to 255
01467          if(value > 255)
01468          {
01469             //The conversion failed
01470             error = ERROR_INVALID_SYNTAX;
01471             break;
01472          }
01473       }
01474       //Dot separator found?
01475       else if(*str == '.' && i < 4)
01476       {
01477          //Each dot must be preceded by a valid number
01478          if(value < 0)
01479          {
01480             //The conversion failed
01481             error = ERROR_INVALID_SYNTAX;
01482             break;
01483          }
01484 
01485          //Save the current byte
01486          ((uint8_t *) ipAddr)[i++] = value;
01487          //Prepare to decode the next byte
01488          value = -1;
01489       }
01490       //End of string detected?
01491       else if(*str == '\0' && i == 3)
01492       {
01493          //The NULL character must be preceded by a valid number
01494          if(value < 0)
01495          {
01496             //The conversion failed
01497             error = ERROR_INVALID_SYNTAX;
01498          }
01499          else
01500          {
01501             //Save the last byte of the IPv4 address
01502             ((uint8_t *) ipAddr)[i] = value;
01503             //The conversion succeeded
01504             error = NO_ERROR;
01505          }
01506 
01507          //We are done
01508          break;
01509       }
01510       //Invalid character...
01511       else
01512       {
01513          //The conversion failed
01514          error = ERROR_INVALID_SYNTAX;
01515          break;
01516       }
01517 
01518       //Point to the next character
01519       str++;
01520    }
01521 
01522    //Return status code
01523    return error;
01524 }
01525 
01526 
01527 /**
01528  * @brief Convert a binary IPv4 address to dot-decimal notation
01529  * @param[in] ipAddr Binary representation of the IPv4 address
01530  * @param[out] str NULL-terminated string representing the IPv4 address
01531  * @return Pointer to the formatted string
01532  **/
01533 
01534 char_t *ipv4AddrToString(Ipv4Addr ipAddr, char_t *str)
01535 {
01536    uint8_t *p;
01537    static char_t buffer[16];
01538 
01539    //If the NULL pointer is given as parameter, then the internal buffer is used
01540    if(str == NULL)
01541       str = buffer;
01542 
01543    //Cast the address to byte array
01544    p = (uint8_t *) &ipAddr;
01545    //Format IPv4 address
01546    sprintf(str, "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 "", p[0], p[1], p[2], p[3]);
01547 
01548    //Return a pointer to the formatted string
01549    return str;
01550 }
01551 
01552 
01553 /**
01554  * @brief Dump IPv4 header for debugging purpose
01555  * @param[in] ipHeader Pointer to the IPv4 header
01556  **/
01557 
01558 void ipv4DumpHeader(const Ipv4Header *ipHeader)
01559 {
01560    //Dump IP header contents
01561    TRACE_DEBUG("  Version = %" PRIu8 "\r\n", ipHeader->version);
01562    TRACE_DEBUG("  Header Length = %" PRIu8 "\r\n", ipHeader->headerLength);
01563    TRACE_DEBUG("  Type Of Service = %" PRIu8 "\r\n", ipHeader->typeOfService);
01564    TRACE_DEBUG("  Total Length = %" PRIu16 "\r\n", ntohs(ipHeader->totalLength));
01565    TRACE_DEBUG("  Identification = %" PRIu16 "\r\n", ntohs(ipHeader->identification));
01566    TRACE_DEBUG("  Flags = 0x%01X\r\n", ntohs(ipHeader->fragmentOffset) >> 13);
01567    TRACE_DEBUG("  Fragment Offset = %" PRIu16 "\r\n", ntohs(ipHeader->fragmentOffset) & 0x1FFF);
01568    TRACE_DEBUG("  Time To Live = %" PRIu8 "\r\n", ipHeader->timeToLive);
01569    TRACE_DEBUG("  Protocol = %" PRIu8 "\r\n", ipHeader->protocol);
01570    TRACE_DEBUG("  Header Checksum = 0x%04" PRIX16 "\r\n", ntohs(ipHeader->headerChecksum));
01571    TRACE_DEBUG("  Src Addr = %s\r\n", ipv4AddrToString(ipHeader->srcAddr, NULL));
01572    TRACE_DEBUG("  Dest Addr = %s\r\n", ipv4AddrToString(ipHeader->destAddr, NULL));
01573 }
01574 
01575 #endif
01576