blob: f4014bf32651b2a5624ba538acb44e6cb8137e85 [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
Nick Banksfbc52452016-10-03 10:45:25 -070034#define WPP_NAME "icmp6.tmh"
35
DuaneEllis-TI358ca8e2017-04-20 20:55:40 -070036#ifdef OPENTHREAD_CONFIG_FILE
37#include OPENTHREAD_CONFIG_FILE
38#else
39#include <openthread-config.h>
40#endif
41
Jonathan Huifbfd76a2017-05-05 11:28:29 -070042#include "icmp6.hpp"
43
DuaneEllis-TId65418c2017-04-27 10:17:09 -070044#include "utils/wrap_string.h"
Jonathan Hui4f9945c2016-05-10 20:48:47 -070045
Jonathan Huifbfd76a2017-05-05 11:28:29 -070046#include "common/code_utils.hpp"
47#include "common/debug.hpp"
48#include "common/logging.hpp"
49#include "common/message.hpp"
50#include "net/ip6.hpp"
Jonathan Hui4f9945c2016-05-10 20:48:47 -070051
Jonathan Hui1eabda62017-04-27 22:29:05 -070052using ot::Encoding::BigEndian::HostSwap16;
Jonathan Hui4f9945c2016-05-10 20:48:47 -070053
Jonathan Hui1eabda62017-04-27 22:29:05 -070054namespace ot {
Jonathan Hui4f9945c2016-05-10 20:48:47 -070055namespace Ip6 {
56
Jonathan Hui2029ef62016-08-26 14:24:55 -070057Icmp::Icmp(Ip6 &aIp6):
58 mHandlers(NULL),
59 mEchoSequence(1),
Jonathan Hui2029ef62016-08-26 14:24:55 -070060 mIsEchoEnabled(true),
61 mIp6(aIp6)
62{
63}
Jonathan Hui4f9945c2016-05-10 20:48:47 -070064
Abtin Keshavarzian70553d52017-04-03 08:50:22 -070065otInstance *Icmp::GetInstance(void)
Nick Banks1c18f452017-03-08 12:40:49 -080066{
67 return mIp6.GetInstance();
68}
69
Jonathan Hui027e0092016-08-29 09:31:26 -070070Message *Icmp::NewMessage(uint16_t aReserved)
Jonathan Hui4f9945c2016-05-10 20:48:47 -070071{
Jonathan Hui2029ef62016-08-26 14:24:55 -070072 return mIp6.NewMessage(sizeof(IcmpHeader) + aReserved);
Jonathan Hui4f9945c2016-05-10 20:48:47 -070073}
74
Łukasz Duda4f35cdb2017-02-24 21:13:59 +010075ThreadError Icmp::RegisterHandler(IcmpHandler &aHandler)
Jonathan Hui4f9945c2016-05-10 20:48:47 -070076{
77 ThreadError error = kThreadError_None;
78
Łukasz Duda4f35cdb2017-02-24 21:13:59 +010079 for (IcmpHandler *cur = mHandlers; cur; cur = cur->GetNext())
Jonathan Hui4f9945c2016-05-10 20:48:47 -070080 {
81 if (cur == &aHandler)
82 {
Robert Quattlebaum104ca6d2016-10-12 14:18:55 -070083 ExitNow(error = kThreadError_Already);
Jonathan Hui4f9945c2016-05-10 20:48:47 -070084 }
85 }
86
Jonathan Hui2029ef62016-08-26 14:24:55 -070087 aHandler.mNext = mHandlers;
88 mHandlers = &aHandler;
Jonathan Hui4f9945c2016-05-10 20:48:47 -070089
90exit:
91 return error;
92}
93
Łukasz Duda4f35cdb2017-02-24 21:13:59 +010094ThreadError Icmp::SendEchoRequest(Message &aMessage, const MessageInfo &aMessageInfo,
95 uint16_t aIdentifier)
Jonathan Hui027e0092016-08-29 09:31:26 -070096{
97 ThreadError error = kThreadError_None;
98 MessageInfo messageInfoLocal;
99 IcmpHeader icmpHeader;
100
101 messageInfoLocal = aMessageInfo;
102
103 icmpHeader.Init();
Łukasz Duda4f35cdb2017-02-24 21:13:59 +0100104 icmpHeader.SetType(kIcmp6TypeEchoRequest);
105 icmpHeader.SetId(aIdentifier);
Jonathan Hui2029ef62016-08-26 14:24:55 -0700106 icmpHeader.SetSequence(mEchoSequence++);
Jonathan Hui027e0092016-08-29 09:31:26 -0700107
108 SuccessOrExit(error = aMessage.Prepend(&icmpHeader, sizeof(icmpHeader)));
109 aMessage.SetOffset(0);
Jonathan Hui2029ef62016-08-26 14:24:55 -0700110 SuccessOrExit(error = mIp6.SendDatagram(aMessage, messageInfoLocal, kProtoIcmp6));
Jonathan Hui027e0092016-08-29 09:31:26 -0700111
Nick Banks1c18f452017-03-08 12:40:49 -0800112 otLogInfoIcmp(GetInstance(), "Sent echo request: (seq = %d)", icmpHeader.GetSequence());
Jonathan Hui027e0092016-08-29 09:31:26 -0700113
114exit:
115 return error;
116}
117
Łukasz Duda8b8f7832017-01-13 02:41:40 +0100118ThreadError Icmp::SendError(IcmpHeader::Type aType, IcmpHeader::Code aCode, const MessageInfo &aMessageInfo,
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700119 const Header &aHeader)
120{
121 ThreadError error = kThreadError_None;
Łukasz Duda8b8f7832017-01-13 02:41:40 +0100122 MessageInfo messageInfoLocal;
Jonathan Hui3a439e52016-05-11 17:01:38 -0700123 Message *message = NULL;
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700124 IcmpHeader icmp6Header;
125
Łukasz Duda8b8f7832017-01-13 02:41:40 +0100126 messageInfoLocal = aMessageInfo;
127
Jonathan Hui2029ef62016-08-26 14:24:55 -0700128 VerifyOrExit((message = mIp6.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700129 SuccessOrExit(error = message->SetLength(sizeof(icmp6Header) + sizeof(aHeader)));
130
131 message->Write(sizeof(icmp6Header), sizeof(aHeader), &aHeader);
132
133 icmp6Header.Init();
134 icmp6Header.SetType(aType);
135 icmp6Header.SetCode(aCode);
136 message->Write(0, sizeof(icmp6Header), &icmp6Header);
137
Łukasz Duda8b8f7832017-01-13 02:41:40 +0100138 SuccessOrExit(error = mIp6.SendDatagram(*message, messageInfoLocal, kProtoIcmp6));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700139
Nick Banks1c18f452017-03-08 12:40:49 -0800140 otLogInfoIcmp(GetInstance(), "Sent ICMPv6 Error");
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700141
142exit:
Jonathan Hui3a439e52016-05-11 17:01:38 -0700143
144 if (error != kThreadError_None && message != NULL)
145 {
Jonathan Huie22c1232016-08-29 18:45:17 -0700146 message->Free();
Jonathan Hui3a439e52016-05-11 17:01:38 -0700147 }
148
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700149 return error;
150}
151
152ThreadError Icmp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo)
153{
154 ThreadError error = kThreadError_None;
155 uint16_t payloadLength;
156 IcmpHeader icmp6Header;
157 uint16_t checksum;
158
Jonathan Hui49ac7fb2017-04-05 09:44:22 -0700159 VerifyOrExit(aMessage.Read(aMessage.GetOffset(), sizeof(icmp6Header), &icmp6Header) == sizeof(icmp6Header));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700160 payloadLength = aMessage.GetLength() - aMessage.GetOffset();
161
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700162 // verify checksum
163 checksum = Ip6::ComputePseudoheaderChecksum(aMessageInfo.GetPeerAddr(), aMessageInfo.GetSockAddr(),
164 payloadLength, kProtoIcmp6);
165 checksum = aMessage.UpdateChecksum(checksum, aMessage.GetOffset(), payloadLength);
Jonathan Hui49ac7fb2017-04-05 09:44:22 -0700166 VerifyOrExit(checksum == 0xffff);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700167
Łukasz Duda4f35cdb2017-02-24 21:13:59 +0100168 if (mIsEchoEnabled && (icmp6Header.GetType() == kIcmp6TypeEchoRequest))
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700169 {
Łukasz Duda4f35cdb2017-02-24 21:13:59 +0100170 HandleEchoRequest(aMessage, aMessageInfo);
171 }
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700172
Łukasz Duda4f35cdb2017-02-24 21:13:59 +0100173 aMessage.MoveOffset(sizeof(icmp6Header));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700174
Łukasz Duda4f35cdb2017-02-24 21:13:59 +0100175 for (IcmpHandler *handler = mHandlers; handler; handler = handler->GetNext())
176 {
177 handler->HandleReceiveMessage(aMessage, aMessageInfo, icmp6Header);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700178 }
179
180exit:
181 return error;
182}
183
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700184ThreadError Icmp::HandleEchoRequest(Message &aRequestMessage, const MessageInfo &aMessageInfo)
185{
186 ThreadError error = kThreadError_None;
187 IcmpHeader icmp6Header;
Jonathan Hui3a439e52016-05-11 17:01:38 -0700188 Message *replyMessage = NULL;
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700189 MessageInfo replyMessageInfo;
190 uint16_t payloadLength;
191
Nick Banks1c18f452017-03-08 12:40:49 -0800192 otLogInfoIcmp(GetInstance(), "Received Echo Request");
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700193
194 icmp6Header.Init();
Łukasz Duda4f35cdb2017-02-24 21:13:59 +0100195 icmp6Header.SetType(kIcmp6TypeEchoReply);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700196
Nick Banksfbc52452016-10-03 10:45:25 -0700197 if ((replyMessage = mIp6.NewMessage(0)) == NULL)
198 {
Nick Banks1c18f452017-03-08 12:40:49 -0800199 otLogDebgIcmp(GetInstance(), "Failed to allocate a new message");
Nick Banksfbc52452016-10-03 10:45:25 -0700200 ExitNow();
201 }
202
Jonathan Huia43fb452016-06-24 12:43:02 -0700203 payloadLength = aRequestMessage.GetLength() - aRequestMessage.GetOffset() - IcmpHeader::GetDataOffset();
Jonathan Huiaeee0b92016-10-07 15:51:20 -0700204 SuccessOrExit(error = replyMessage->SetLength(IcmpHeader::GetDataOffset() + payloadLength));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700205
206 replyMessage->Write(0, IcmpHeader::GetDataOffset(), &icmp6Header);
207 aRequestMessage.CopyTo(aRequestMessage.GetOffset() + IcmpHeader::GetDataOffset(),
208 IcmpHeader::GetDataOffset(), payloadLength, *replyMessage);
209
Jonathan Huif0a52392016-10-27 09:42:48 -0700210 replyMessageInfo.SetPeerAddr(aMessageInfo.GetPeerAddr());
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700211
212 if (!aMessageInfo.GetSockAddr().IsMulticast())
213 {
Jonathan Huif0a52392016-10-27 09:42:48 -0700214 replyMessageInfo.SetSockAddr(aMessageInfo.GetSockAddr());
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700215 }
216
Jonathan Huif0a52392016-10-27 09:42:48 -0700217 replyMessageInfo.SetInterfaceId(aMessageInfo.mInterfaceId);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700218
Jonathan Hui2029ef62016-08-26 14:24:55 -0700219 SuccessOrExit(error = mIp6.SendDatagram(*replyMessage, replyMessageInfo, kProtoIcmp6));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700220
rongliadd86392016-09-24 02:12:53 +0800221 replyMessage->Read(replyMessage->GetOffset(), sizeof(icmp6Header), &icmp6Header);
Nick Banks1c18f452017-03-08 12:40:49 -0800222 otLogInfoIcmp(GetInstance(), "Sent Echo Reply (seq = %d)", icmp6Header.GetSequence());
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700223
224exit:
Jonathan Hui3a439e52016-05-11 17:01:38 -0700225
226 if (error != kThreadError_None && replyMessage != NULL)
227 {
Jonathan Huie22c1232016-08-29 18:45:17 -0700228 replyMessage->Free();
Jonathan Hui3a439e52016-05-11 17:01:38 -0700229 }
230
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700231 return error;
232}
233
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700234ThreadError Icmp::UpdateChecksum(Message &aMessage, uint16_t aChecksum)
235{
236 aChecksum = aMessage.UpdateChecksum(aChecksum, aMessage.GetOffset(),
237 aMessage.GetLength() - aMessage.GetOffset());
238
239 if (aChecksum != 0xffff)
240 {
241 aChecksum = ~aChecksum;
242 }
243
244 aChecksum = HostSwap16(aChecksum);
245 aMessage.Write(aMessage.GetOffset() + IcmpHeader::GetChecksumOffset(), sizeof(aChecksum), &aChecksum);
246 return kThreadError_None;
247}
248
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700249} // namespace Ip6
Jonathan Hui1eabda62017-04-27 22:29:05 -0700250} // namespace ot