Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
icmp.c
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
Generated on Tue Jul 12 2022 17:10:13 by
1.7.2