Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers icmp.c Source File

icmp.c

Go to the documentation of this file.
00001 /**
00002  * @file icmp.c
00003  * @brief ICMP (Internet Control Message Protocol)
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @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 ICMP_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include <string.h>
00034 #include "core/net.h"
00035 #include "core/ip.h"
00036 #include "ipv4/ipv4.h"
00037 #include "ipv4/icmp.h"
00038 #include "mibs/mib2_module.h"
00039 #include "debug.h"
00040 
00041 //Check TCP/IP stack configuration
00042 #if (IPV4_SUPPORT == ENABLED)
00043 
00044 
00045 /**
00046  * @brief Incoming ICMP message processing
00047  * @param[in] interface Underlying network interface
00048  * @param[in] srcIpAddr Source IPv4 address
00049  * @param[in] buffer Multi-part buffer containing the incoming ICMP message
00050  * @param[in] offset Offset to the first byte of the ICMP message
00051  **/
00052 
00053 void icmpProcessMessage(NetInterface *interface,
00054    Ipv4Addr srcIpAddr, const NetBuffer *buffer, size_t offset)
00055 {
00056    size_t length;
00057    IcmpHeader *header;
00058 
00059    //Total number of ICMP messages which the entity received
00060    MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpInMsgs, 1);
00061 
00062    //Retrieve the length of the ICMP message
00063    length = netBufferGetLength(buffer) - offset;
00064 
00065    //Ensure the message length is correct
00066    if(length < sizeof(IcmpHeader))
00067    {
00068       //Number of ICMP messages which the entity received but determined
00069       //as having ICMP-specific errors
00070       MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpInErrors, 1);
00071       //Silently discard incoming message
00072       return;
00073    }
00074 
00075    //Point to the ICMP message header
00076    header = netBufferAt(buffer, offset);
00077    //Sanity check
00078    if(header == NULL)
00079       return;
00080 
00081    //Debug message
00082    TRACE_INFO("ICMP message received (%" PRIuSIZE " bytes)...\r\n", length);
00083    //Dump message contents for debugging purpose
00084    icmpDumpMessage(header);
00085 
00086    //Verify checksum value
00087    if(ipCalcChecksumEx(buffer, offset, length) != 0x0000)
00088    {
00089       //Debug message
00090       TRACE_WARNING("Wrong ICMP header checksum!\r\n");
00091       //Number of ICMP messages which the entity received but determined
00092       //as having ICMP-specific errors
00093       MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpInErrors, 1);
00094       //Drop incoming message
00095       return;
00096    }
00097 
00098    //Check the type of ICMP message
00099    switch(header->type)
00100    {
00101    //Echo Request?
00102    case ICMP_TYPE_ECHO_REQUEST:
00103       //Process Echo Request message
00104       icmpProcessEchoRequest(interface, srcIpAddr, buffer, offset);
00105       break;
00106    //Unknown type?
00107    default:
00108       //Debug message
00109       TRACE_WARNING("Unknown ICMP message type!\r\n");
00110       //Discard incoming ICMP message
00111       break;
00112    }
00113 }
00114 
00115 
00116 /**
00117  * @brief Echo Request message processing
00118  * @param[in] interface Underlying network interface
00119  * @param[in] srcIpAddr Source IPv4 address
00120  * @param[in] request Multi-part buffer containing the incoming Echo Request message
00121  * @param[in] requestOffset Offset to the first byte of the Echo Request message
00122  **/
00123 
00124 void icmpProcessEchoRequest(NetInterface *interface,
00125    Ipv4Addr srcIpAddr, const NetBuffer *request, size_t requestOffset)
00126 {
00127    error_t error;
00128    size_t requestLength;
00129    size_t replyOffset;
00130    size_t replyLength;
00131    NetBuffer *reply;
00132    IcmpEchoMessage *requestHeader;
00133    IcmpEchoMessage *replyHeader;
00134    Ipv4PseudoHeader pseudoHeader;
00135 
00136    //Number of ICMP Echo Request messages received
00137    MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpInEchos, 1);
00138 
00139    //Retrieve the length of the Echo Request message
00140    requestLength = netBufferGetLength(request) - requestOffset;
00141 
00142    //Ensure the packet length is correct
00143    if(requestLength < sizeof(IcmpEchoMessage))
00144       return;
00145 
00146    //Point to the Echo Request header
00147    requestHeader = netBufferAt(request, requestOffset);
00148    //Sanity check
00149    if(requestHeader == NULL)
00150       return;
00151 
00152    //Debug message
00153    TRACE_INFO("ICMP Echo Request message received (%" PRIuSIZE " bytes)...\r\n", requestLength);
00154    //Dump message contents for debugging purpose
00155    icmpDumpEchoMessage(requestHeader);
00156 
00157    //Allocate memory to hold the Echo Reply message
00158    reply = ipAllocBuffer(sizeof(IcmpEchoMessage), &replyOffset);
00159    //Failed to allocate memory?
00160    if(reply == NULL)
00161       return;
00162 
00163    //Point to the Echo Reply header
00164    replyHeader = netBufferAt(reply, replyOffset);
00165 
00166    //Format Echo Reply header
00167    replyHeader->type = ICMP_TYPE_ECHO_REPLY;
00168    replyHeader->code = 0;
00169    replyHeader->checksum = 0;
00170    replyHeader->identifier = requestHeader->identifier;
00171    replyHeader->sequenceNumber = requestHeader->sequenceNumber;
00172 
00173    //Point to the first data byte
00174    requestOffset += sizeof(IcmpEchoMessage);
00175    requestLength -= sizeof(IcmpEchoMessage);
00176 
00177    //Copy data
00178    error = netBufferConcat(reply, request, requestOffset, requestLength);
00179 
00180    //Check status code
00181    if(!error)
00182    {
00183       //Get the length of the resulting message
00184       replyLength = netBufferGetLength(reply) - replyOffset;
00185       //Calculate ICMP header checksum
00186       replyHeader->checksum = ipCalcChecksumEx(reply, replyOffset, replyLength);
00187 
00188       //Format IPv4 pseudo header
00189       pseudoHeader.srcAddr = interface->ipv4Context.addr;
00190       pseudoHeader.destAddr = srcIpAddr;
00191       pseudoHeader.reserved = 0;
00192       pseudoHeader.protocol = IPV4_PROTOCOL_ICMP;
00193       pseudoHeader.length = htons(replyLength);
00194 
00195       //Total number of ICMP messages which this entity attempted to send
00196       MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutMsgs, 1);
00197       //Number of ICMP Echo Reply messages sent
00198       MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutEchoReps, 1);
00199 
00200       //Debug message
00201       TRACE_INFO("Sending ICMP Echo Reply message (%" PRIuSIZE " bytes)...\r\n", replyLength);
00202       //Dump message contents for debugging purpose
00203       icmpDumpEchoMessage(replyHeader);
00204 
00205       //Send Echo Reply message
00206       ipv4SendDatagram(interface, &pseudoHeader, reply, replyOffset, IPV4_DEFAULT_TTL);
00207    }
00208 
00209    //Free previously allocated memory block
00210    netBufferFree(reply);
00211 }
00212 
00213 
00214 /**
00215  * @brief Send an ICMP Error message
00216  * @param[in] interface Underlying network interface
00217  * @param[in] type Message type
00218  * @param[in] code Specific message code
00219  * @param[in] parameter Specific message parameter
00220  * @param[in] ipPacket Multi-part buffer that holds the invoking IPv4 packet
00221  * @param[in] ipPacketOffset Offset to the first byte of the IPv4 packet
00222  * @return Error code
00223  **/
00224 
00225 error_t icmpSendErrorMessage(NetInterface *interface, uint8_t type, uint8_t code,
00226    uint8_t parameter, const NetBuffer *ipPacket, size_t ipPacketOffset)
00227 {
00228    error_t error;
00229    size_t offset;
00230    size_t length;
00231    Ipv4Header *ipHeader;
00232    NetBuffer *icmpMessage;
00233    IcmpErrorMessage *icmpHeader;
00234    Ipv4PseudoHeader pseudoHeader;
00235 
00236    //Retrieve the length of the invoking IPv4 packet
00237    length = netBufferGetLength(ipPacket) - ipPacketOffset;
00238 
00239    //Check the length of the IPv4 packet
00240    if(length < sizeof(Ipv4Header))
00241       return ERROR_INVALID_LENGTH;
00242 
00243    //Point to the header of the invoking packet
00244    ipHeader = netBufferAt(ipPacket, ipPacketOffset);
00245    //Sanity check
00246    if(ipHeader == NULL)
00247       return ERROR_FAILURE;
00248 
00249    //Never respond to a packet destined to a broadcast or a multicast address
00250    if(ipv4IsBroadcastAddr(interface, ipHeader->destAddr) ||
00251       ipv4IsMulticastAddr(ipHeader->destAddr))
00252    {
00253       //Report an error
00254       return ERROR_INVALID_ADDRESS;
00255    }
00256 
00257    //Length of the data that will be returned along with the ICMP header
00258    length = MIN(length, (size_t) ipHeader->headerLength * 4 + 8);
00259 
00260    //Allocate a memory buffer to hold the ICMP message
00261    icmpMessage = ipAllocBuffer(sizeof(IcmpErrorMessage), &offset);
00262    //Failed to allocate memory?
00263    if(icmpMessage == NULL)
00264       return ERROR_OUT_OF_MEMORY;
00265 
00266    //Point to the ICMP header
00267    icmpHeader = netBufferAt(icmpMessage, offset);
00268 
00269    //Format ICMP message
00270    icmpHeader->type = type;
00271    icmpHeader->code = code;
00272    icmpHeader->checksum = 0;
00273    icmpHeader->parameter = parameter;
00274    icmpHeader->unused = 0;
00275 
00276    //Copy the IP header and the first 8 bytes of the original datagram data
00277    error = netBufferConcat(icmpMessage, ipPacket, ipPacketOffset, length);
00278 
00279    //Check status code
00280    if(!error)
00281    {
00282       //Get the length of the resulting message
00283       length = netBufferGetLength(icmpMessage) - offset;
00284       //Message checksum calculation
00285       icmpHeader->checksum = ipCalcChecksumEx(icmpMessage, offset, length);
00286 
00287       //Format IPv4 pseudo header
00288       pseudoHeader.srcAddr = ipHeader->destAddr;
00289       pseudoHeader.destAddr = ipHeader->srcAddr;
00290       pseudoHeader.reserved = 0;
00291       pseudoHeader.protocol = IPV4_PROTOCOL_ICMP;
00292       pseudoHeader.length = htons(length);
00293 
00294       //Total number of ICMP messages which this entity attempted to send
00295       MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutMsgs, 1);
00296 
00297       //Check ICMP message type
00298       if(code == ICMP_TYPE_DEST_UNREACHABLE)
00299       {
00300          //Number of ICMP Destination Unreachable messages sent
00301          MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutDestUnreachs, 1);
00302       }
00303       else if(code == ICMP_TYPE_SOURCE_QUENCH)
00304       {
00305          //Number of ICMP Source Quench messages sent
00306          MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutSrcQuenchs, 1);
00307       }
00308       else if(code == ICMP_TYPE_REDIRECT)
00309       {
00310          //Number of ICMP Redirect messages sent
00311          MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutRedirects, 1);
00312       }
00313       else if(code == ICMP_TYPE_TIME_EXCEEDED)
00314       {
00315          //Number of ICMP Time Exceeded messages sent
00316          MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutTimeExcds, 1);
00317       }
00318       else if(code == ICMP_TYPE_PARAM_PROBLEM)
00319       {
00320          //Number of ICMP Parameter Problem messages sent
00321          MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutParmProbs, 1);
00322       }
00323 
00324       //Debug message
00325       TRACE_INFO("Sending ICMP Error message (%" PRIuSIZE " bytes)...\r\n", length);
00326       //Dump message contents for debugging purpose
00327       icmpDumpErrorMessage(icmpHeader);
00328 
00329       //Send ICMP Error message
00330       error = ipv4SendDatagram(interface, &pseudoHeader,
00331          icmpMessage, offset, IPV4_DEFAULT_TTL);
00332    }
00333 
00334    //Free previously allocated memory
00335    netBufferFree(icmpMessage);
00336 
00337    //Return status code
00338    return error;
00339 }
00340 
00341 
00342 /**
00343  * @brief Dump ICMP message for debugging purpose
00344  * @param[in] message Pointer to the ICMP message
00345  **/
00346 
00347 void icmpDumpMessage(const IcmpHeader *message)
00348 {
00349    //Dump ICMP message
00350    TRACE_DEBUG("  Type = %" PRIu8 "\r\n", message->type);
00351    TRACE_DEBUG("  Code = %" PRIu8 "\r\n", message->code);
00352    TRACE_DEBUG("  Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum));
00353 }
00354 
00355 
00356 /**
00357  * @brief Dump ICMP Echo Request or Echo Reply message
00358  * @param[in] message Pointer to the ICMP message
00359  **/
00360 
00361 void icmpDumpEchoMessage(const IcmpEchoMessage *message)
00362 {
00363    //Dump ICMP message
00364    TRACE_DEBUG("  Type = %" PRIu8 "\r\n", message->type);
00365    TRACE_DEBUG("  Code = %" PRIu8 "\r\n", message->code);
00366    TRACE_DEBUG("  Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum));
00367    TRACE_DEBUG("  Identifier = 0x%04" PRIX16 "\r\n", ntohs(message->identifier));
00368    TRACE_DEBUG("  Sequence Number = 0x%04" PRIX16 "\r\n", ntohs(message->sequenceNumber));
00369 }
00370 
00371 
00372 /**
00373  * @brief Dump generic ICMP Error message
00374  * @param[in] message Pointer to the ICMP message
00375  **/
00376 
00377 void icmpDumpErrorMessage(const IcmpErrorMessage *message)
00378 {
00379    //Dump ICMP message
00380    TRACE_DEBUG("  Type = %" PRIu8 "\r\n", message->type);
00381    TRACE_DEBUG("  Code = %" PRIu8 "\r\n", message->code);
00382    TRACE_DEBUG("  Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum));
00383    TRACE_DEBUG("  Parameter = %" PRIu8 "\r\n", message->parameter);
00384 }
00385 
00386 #endif
00387