blob: 93542f688cf0c9268eaf16ac8b048c131cbeaa7d [file] [log] [blame]
Jonathan Hui4f9945c2016-05-10 20:48:47 -07001/*
Jonathan Hui44350172016-09-13 15:57:11 -07002 * Copyright (c) 2016, The OpenThread Authors.
Marcin K Szczodrak99870fa2016-05-12 22:39:11 -07003 * All rights reserved.
Jonathan Hui4f9945c2016-05-10 20:48:47 -07004 *
Marcin K Szczodrak99870fa2016-05-12 22:39:11 -07005 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
Jonathan Hui4f9945c2016-05-10 20:48:47 -070015 *
Marcin K Szczodrak99870fa2016-05-12 22:39:11 -070016 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
Jonathan Hui4f9945c2016-05-10 20:48:47 -070027 */
28
29/**
30 * @file
31 * This file implements ICMPv6.
32 */
33
Jonathan Huifbfd76a2017-05-05 11:28:29 -070034#include "icmp6.hpp"
35
Jonathan Huifbfd76a2017-05-05 11:28:29 -070036#include "common/code_utils.hpp"
37#include "common/debug.hpp"
Abtin Keshavarzian02c876e2017-11-13 08:27:57 -080038#include "common/instance.hpp"
Abtin Keshavarzianf7802d62021-04-10 10:16:01 -070039#include "common/locator_getters.hpp"
Abtin Keshavarzian564982c2022-02-17 15:50:45 -080040#include "common/log.hpp"
Jonathan Huifbfd76a2017-05-05 11:28:29 -070041#include "common/message.hpp"
Abtin Keshavarziand16d2022020-09-01 14:27:50 -070042#include "net/checksum.hpp"
Jonathan Huifbfd76a2017-05-05 11:28:29 -070043#include "net/ip6.hpp"
Jonathan Hui4f9945c2016-05-10 20:48:47 -070044
Jonathan Hui1eabda62017-04-27 22:29:05 -070045namespace ot {
Jonathan Hui4f9945c2016-05-10 20:48:47 -070046namespace Ip6 {
47
Abtin Keshavarzian564982c2022-02-17 15:50:45 -080048RegisterLogModule("Icmp6");
49
Jonathan Hui69d98d42018-02-06 14:14:57 -080050Icmp::Icmp(Instance &aInstance)
51 : InstanceLocator(aInstance)
Jonathan Hui69d98d42018-02-06 14:14:57 -080052 , mEchoSequence(1)
Jonathan Huif602dcd2018-03-13 18:10:28 +000053 , mEchoMode(OT_ICMP6_ECHO_HANDLER_ALL)
Jonathan Hui2029ef62016-08-26 14:24:55 -070054{
55}
Jonathan Hui4f9945c2016-05-10 20:48:47 -070056
Jonathan Hui027e0092016-08-29 09:31:26 -070057Message *Icmp::NewMessage(uint16_t aReserved)
Jonathan Hui4f9945c2016-05-10 20:48:47 -070058{
Abtin Keshavarzian04b35d02020-07-08 10:41:00 -070059 return Get<Ip6>().NewMessage(sizeof(Header) + aReserved);
Jonathan Hui4f9945c2016-05-10 20:48:47 -070060}
61
Abtin Keshavarzian7dca56e2021-03-15 21:07:07 -070062Error Icmp::RegisterHandler(Handler &aHandler)
Jonathan Hui4f9945c2016-05-10 20:48:47 -070063{
Abtin Keshavarziane17c82b2019-12-04 11:03:52 -080064 return mHandlers.Add(aHandler);
Jonathan Hui4f9945c2016-05-10 20:48:47 -070065}
66
Abtin Keshavarzian7dca56e2021-03-15 21:07:07 -070067Error Icmp::SendEchoRequest(Message &aMessage, const MessageInfo &aMessageInfo, uint16_t aIdentifier)
Jonathan Hui027e0092016-08-29 09:31:26 -070068{
Abtin Keshavarzian7dca56e2021-03-15 21:07:07 -070069 Error error = kErrorNone;
Jonathan Hui027e0092016-08-29 09:31:26 -070070 MessageInfo messageInfoLocal;
Abtin Keshavarzian04b35d02020-07-08 10:41:00 -070071 Header icmpHeader;
Jonathan Hui027e0092016-08-29 09:31:26 -070072
73 messageInfoLocal = aMessageInfo;
74
Abtin Keshavarzian04b35d02020-07-08 10:41:00 -070075 icmpHeader.Clear();
76 icmpHeader.SetType(Header::kTypeEchoRequest);
Łukasz Duda4f35cdb2017-02-24 21:13:59 +010077 icmpHeader.SetId(aIdentifier);
Jonathan Hui2029ef62016-08-26 14:24:55 -070078 icmpHeader.SetSequence(mEchoSequence++);
Jonathan Hui027e0092016-08-29 09:31:26 -070079
Abtin Keshavarzian1f407932020-10-03 08:28:42 -070080 SuccessOrExit(error = aMessage.Prepend(icmpHeader));
Jonathan Hui1ce50642020-05-11 21:51:46 -070081 aMessage.SetOffset(0);
Abtin Keshavarzian8f112ee2019-04-02 09:07:25 -070082 SuccessOrExit(error = Get<Ip6>().SendDatagram(aMessage, messageInfoLocal, kProtoIcmp6));
Jonathan Hui027e0092016-08-29 09:31:26 -070083
Abtin Keshavarzian564982c2022-02-17 15:50:45 -080084 LogInfo("Sent echo request: (seq = %d)", icmpHeader.GetSequence());
Jonathan Hui027e0092016-08-29 09:31:26 -070085
86exit:
87 return error;
88}
89
Abtin Keshavarzian7dca56e2021-03-15 21:07:07 -070090Error Icmp::SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Message &aMessage)
Jonathan Hui4f9945c2016-05-10 20:48:47 -070091{
Abtin Keshavarzian6e0eb8a2022-07-11 11:59:06 -070092 Error error;
93 Headers headers;
94
95 SuccessOrExit(error = headers.ParseFrom(aMessage));
96 error = SendError(aType, aCode, aMessageInfo, headers);
97
98exit:
99 return error;
100}
101
102Error Icmp::SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Headers &aHeaders)
103{
Abtin Keshavarzian7dca56e2021-03-15 21:07:07 -0700104 Error error = kErrorNone;
Duda, Lukasz7edb4552020-05-07 00:32:56 +0200105 MessageInfo messageInfoLocal;
Jonathan Hui1326d642020-06-17 22:44:54 -0700106 Message * message = nullptr;
Abtin Keshavarzian04b35d02020-07-08 10:41:00 -0700107 Header icmp6Header;
Abtin Keshavarzian8160f342020-05-18 21:44:30 -0700108 Message::Settings settings(Message::kWithLinkSecurity, Message::kPriorityNet);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700109
Abtin Keshavarzian6e0eb8a2022-07-11 11:59:06 -0700110 if (aHeaders.GetIpProto() == kProtoIcmp6)
Jonathan Huife736642020-04-07 15:47:12 -0700111 {
Abtin Keshavarzian6e0eb8a2022-07-11 11:59:06 -0700112 VerifyOrExit(!aHeaders.GetIcmpHeader().IsError());
Jonathan Huife736642020-04-07 15:47:12 -0700113 }
114
Łukasz Duda8b8f7832017-01-13 02:41:40 +0100115 messageInfoLocal = aMessageInfo;
116
Abtin Keshavarzian7dca56e2021-03-15 21:07:07 -0700117 VerifyOrExit((message = Get<Ip6>().NewMessage(0, settings)) != nullptr, error = kErrorNoBufs);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700118
Abtin Keshavarzian6e0eb8a2022-07-11 11:59:06 -0700119 // Prepare the ICMPv6 error message. We only include the IPv6 header
120 // of the original message causing the error.
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700121
Abtin Keshavarzian04b35d02020-07-08 10:41:00 -0700122 icmp6Header.Clear();
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700123 icmp6Header.SetType(aType);
124 icmp6Header.SetCode(aCode);
Abtin Keshavarzian6e0eb8a2022-07-11 11:59:06 -0700125 SuccessOrExit(error = message->Append(icmp6Header));
126 SuccessOrExit(error = message->Append(aHeaders.GetIp6Header()));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700127
Abtin Keshavarzian8f112ee2019-04-02 09:07:25 -0700128 SuccessOrExit(error = Get<Ip6>().SendDatagram(*message, messageInfoLocal, kProtoIcmp6));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700129
Abtin Keshavarzian564982c2022-02-17 15:50:45 -0800130 LogInfo("Sent ICMPv6 Error");
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700131
132exit:
Abtin Keshavarzian83072bb2020-09-24 13:06:17 -0700133 FreeMessageOnError(message, error);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700134 return error;
135}
136
Abtin Keshavarzian7dca56e2021-03-15 21:07:07 -0700137Error Icmp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo)
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700138{
Abtin Keshavarzian7dca56e2021-03-15 21:07:07 -0700139 Error error = kErrorNone;
140 Header icmp6Header;
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700141
Abtin Keshavarzian1f407932020-10-03 08:28:42 -0700142 SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), icmp6Header));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700143
Abtin Keshavarziand16d2022020-09-01 14:27:50 -0700144 SuccessOrExit(error = Checksum::VerifyMessageChecksum(aMessage, aMessageInfo, kProtoIcmp6));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700145
Abtin Keshavarzian04b35d02020-07-08 10:41:00 -0700146 if (icmp6Header.GetType() == Header::kTypeEchoRequest)
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700147 {
Łukasz Duda704511c2018-09-18 18:30:56 +0200148 SuccessOrExit(error = HandleEchoRequest(aMessage, aMessageInfo));
Łukasz Duda4f35cdb2017-02-24 21:13:59 +0100149 }
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700150
Jonathan Hui03d65252020-05-11 21:59:02 -0700151 aMessage.MoveOffset(sizeof(icmp6Header));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700152
Abtin Keshavarzian6895edd2021-08-23 14:50:14 -0700153 for (Handler &handler : mHandlers)
Łukasz Duda4f35cdb2017-02-24 21:13:59 +0100154 {
Abtin Keshavarzian6895edd2021-08-23 14:50:14 -0700155 handler.HandleReceiveMessage(aMessage, aMessageInfo, icmp6Header);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700156 }
157
158exit:
159 return error;
160}
161
Jonathan Huif602dcd2018-03-13 18:10:28 +0000162bool Icmp::ShouldHandleEchoRequest(const MessageInfo &aMessageInfo)
163{
164 bool rval = false;
165
166 switch (mEchoMode)
167 {
168 case OT_ICMP6_ECHO_HANDLER_DISABLED:
169 rval = false;
170 break;
171 case OT_ICMP6_ECHO_HANDLER_UNICAST_ONLY:
172 rval = !aMessageInfo.GetSockAddr().IsMulticast();
173 break;
174 case OT_ICMP6_ECHO_HANDLER_MULTICAST_ONLY:
175 rval = aMessageInfo.GetSockAddr().IsMulticast();
176 break;
177 case OT_ICMP6_ECHO_HANDLER_ALL:
178 rval = true;
179 break;
180 }
181
182 return rval;
183}
184
Abtin Keshavarzian7dca56e2021-03-15 21:07:07 -0700185Error Icmp::HandleEchoRequest(Message &aRequestMessage, const MessageInfo &aMessageInfo)
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700186{
Abtin Keshavarzian7dca56e2021-03-15 21:07:07 -0700187 Error error = kErrorNone;
Abtin Keshavarzian04b35d02020-07-08 10:41:00 -0700188 Header icmp6Header;
Jonathan Hui1326d642020-06-17 22:44:54 -0700189 Message * replyMessage = nullptr;
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700190 MessageInfo replyMessageInfo;
Jonathan Hui69d98d42018-02-06 14:14:57 -0800191 uint16_t payloadLength;
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700192
rongli9f9d76b2018-09-01 08:55:32 +0800193 // always handle Echo Request destined for RLOC or ALOC
Abtin Keshavarzianc9c0cf42020-10-13 23:26:02 -0700194 VerifyOrExit(ShouldHandleEchoRequest(aMessageInfo) || aMessageInfo.GetSockAddr().GetIid().IsLocator());
Jonathan Huif602dcd2018-03-13 18:10:28 +0000195
Abtin Keshavarzian564982c2022-02-17 15:50:45 -0800196 LogInfo("Received Echo Request");
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700197
Abtin Keshavarzian04b35d02020-07-08 10:41:00 -0700198 icmp6Header.Clear();
199 icmp6Header.SetType(Header::kTypeEchoReply);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700200
Jonathan Hui1326d642020-06-17 22:44:54 -0700201 if ((replyMessage = Get<Ip6>().NewMessage(0)) == nullptr)
Nick Banksfbc52452016-10-03 10:45:25 -0700202 {
Abtin Keshavarzian564982c2022-02-17 15:50:45 -0800203 LogDebg("Failed to allocate a new message");
Nick Banksfbc52452016-10-03 10:45:25 -0700204 ExitNow();
205 }
206
Abtin Keshavarzian04b35d02020-07-08 10:41:00 -0700207 payloadLength = aRequestMessage.GetLength() - aRequestMessage.GetOffset() - Header::kDataFieldOffset;
208 SuccessOrExit(error = replyMessage->SetLength(Header::kDataFieldOffset + payloadLength));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700209
Abtin Keshavarzian1f407932020-10-03 08:28:42 -0700210 replyMessage->WriteBytes(0, &icmp6Header, Header::kDataFieldOffset);
Abtin Keshavarzian04b35d02020-07-08 10:41:00 -0700211 aRequestMessage.CopyTo(aRequestMessage.GetOffset() + Header::kDataFieldOffset, Header::kDataFieldOffset,
Jonathan Hui69d98d42018-02-06 14:14:57 -0800212 payloadLength, *replyMessage);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700213
Jonathan Huif0a52392016-10-27 09:42:48 -0700214 replyMessageInfo.SetPeerAddr(aMessageInfo.GetPeerAddr());
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700215
216 if (!aMessageInfo.GetSockAddr().IsMulticast())
217 {
Jonathan Huif0a52392016-10-27 09:42:48 -0700218 replyMessageInfo.SetSockAddr(aMessageInfo.GetSockAddr());
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700219 }
220
Abtin Keshavarzian8f112ee2019-04-02 09:07:25 -0700221 SuccessOrExit(error = Get<Ip6>().SendDatagram(*replyMessage, replyMessageInfo, kProtoIcmp6));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700222
Abtin Keshavarzian1f407932020-10-03 08:28:42 -0700223 IgnoreError(replyMessage->Read(replyMessage->GetOffset(), icmp6Header));
Abtin Keshavarzian564982c2022-02-17 15:50:45 -0800224 LogInfo("Sent Echo Reply (seq = %d)", icmp6Header.GetSequence());
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700225
226exit:
Abtin Keshavarzian83072bb2020-09-24 13:06:17 -0700227 FreeMessageOnError(replyMessage, error);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700228 return error;
229}
230
Jonathan Hui69d98d42018-02-06 14:14:57 -0800231} // namespace Ip6
232} // namespace ot