Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 1 | /* |
Jonathan Hui | 4435017 | 2016-09-13 15:57:11 -0700 | [diff] [blame] | 2 | * Copyright (c) 2016, The OpenThread Authors. |
Marcin K Szczodrak | 99870fa | 2016-05-12 22:39:11 -0700 | [diff] [blame] | 3 | * All rights reserved. |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 4 | * |
Marcin K Szczodrak | 99870fa | 2016-05-12 22:39:11 -0700 | [diff] [blame] | 5 | * 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 Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 15 | * |
Marcin K Szczodrak | 99870fa | 2016-05-12 22:39:11 -0700 | [diff] [blame] | 16 | * 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 Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 27 | */ |
| 28 | |
| 29 | /** |
| 30 | * @file |
| 31 | * This file implements ICMPv6. |
| 32 | */ |
| 33 | |
Nick Banks | fbc5245 | 2016-10-03 10:45:25 -0700 | [diff] [blame] | 34 | #define WPP_NAME "icmp6.tmh" |
| 35 | |
DuaneEllis-TI | 358ca8e | 2017-04-20 20:55:40 -0700 | [diff] [blame] | 36 | #ifdef OPENTHREAD_CONFIG_FILE |
| 37 | #include OPENTHREAD_CONFIG_FILE |
| 38 | #else |
| 39 | #include <openthread-config.h> |
| 40 | #endif |
| 41 | |
Jonathan Hui | fbfd76a | 2017-05-05 11:28:29 -0700 | [diff] [blame^] | 42 | #include "icmp6.hpp" |
| 43 | |
DuaneEllis-TI | d65418c | 2017-04-27 10:17:09 -0700 | [diff] [blame] | 44 | #include "utils/wrap_string.h" |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 45 | |
Jonathan Hui | fbfd76a | 2017-05-05 11:28:29 -0700 | [diff] [blame^] | 46 | #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 Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 51 | |
Jonathan Hui | 1eabda6 | 2017-04-27 22:29:05 -0700 | [diff] [blame] | 52 | using ot::Encoding::BigEndian::HostSwap16; |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 53 | |
Jonathan Hui | 1eabda6 | 2017-04-27 22:29:05 -0700 | [diff] [blame] | 54 | namespace ot { |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 55 | namespace Ip6 { |
| 56 | |
Jonathan Hui | 2029ef6 | 2016-08-26 14:24:55 -0700 | [diff] [blame] | 57 | Icmp::Icmp(Ip6 &aIp6): |
| 58 | mHandlers(NULL), |
| 59 | mEchoSequence(1), |
Jonathan Hui | 2029ef6 | 2016-08-26 14:24:55 -0700 | [diff] [blame] | 60 | mIsEchoEnabled(true), |
| 61 | mIp6(aIp6) |
| 62 | { |
| 63 | } |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 64 | |
Abtin Keshavarzian | 70553d5 | 2017-04-03 08:50:22 -0700 | [diff] [blame] | 65 | otInstance *Icmp::GetInstance(void) |
Nick Banks | 1c18f45 | 2017-03-08 12:40:49 -0800 | [diff] [blame] | 66 | { |
| 67 | return mIp6.GetInstance(); |
| 68 | } |
| 69 | |
Jonathan Hui | 027e009 | 2016-08-29 09:31:26 -0700 | [diff] [blame] | 70 | Message *Icmp::NewMessage(uint16_t aReserved) |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 71 | { |
Jonathan Hui | 2029ef6 | 2016-08-26 14:24:55 -0700 | [diff] [blame] | 72 | return mIp6.NewMessage(sizeof(IcmpHeader) + aReserved); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 73 | } |
| 74 | |
Łukasz Duda | 4f35cdb | 2017-02-24 21:13:59 +0100 | [diff] [blame] | 75 | ThreadError Icmp::RegisterHandler(IcmpHandler &aHandler) |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 76 | { |
| 77 | ThreadError error = kThreadError_None; |
| 78 | |
Łukasz Duda | 4f35cdb | 2017-02-24 21:13:59 +0100 | [diff] [blame] | 79 | for (IcmpHandler *cur = mHandlers; cur; cur = cur->GetNext()) |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 80 | { |
| 81 | if (cur == &aHandler) |
| 82 | { |
Robert Quattlebaum | 104ca6d | 2016-10-12 14:18:55 -0700 | [diff] [blame] | 83 | ExitNow(error = kThreadError_Already); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 84 | } |
| 85 | } |
| 86 | |
Jonathan Hui | 2029ef6 | 2016-08-26 14:24:55 -0700 | [diff] [blame] | 87 | aHandler.mNext = mHandlers; |
| 88 | mHandlers = &aHandler; |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 89 | |
| 90 | exit: |
| 91 | return error; |
| 92 | } |
| 93 | |
Łukasz Duda | 4f35cdb | 2017-02-24 21:13:59 +0100 | [diff] [blame] | 94 | ThreadError Icmp::SendEchoRequest(Message &aMessage, const MessageInfo &aMessageInfo, |
| 95 | uint16_t aIdentifier) |
Jonathan Hui | 027e009 | 2016-08-29 09:31:26 -0700 | [diff] [blame] | 96 | { |
| 97 | ThreadError error = kThreadError_None; |
| 98 | MessageInfo messageInfoLocal; |
| 99 | IcmpHeader icmpHeader; |
| 100 | |
| 101 | messageInfoLocal = aMessageInfo; |
| 102 | |
| 103 | icmpHeader.Init(); |
Łukasz Duda | 4f35cdb | 2017-02-24 21:13:59 +0100 | [diff] [blame] | 104 | icmpHeader.SetType(kIcmp6TypeEchoRequest); |
| 105 | icmpHeader.SetId(aIdentifier); |
Jonathan Hui | 2029ef6 | 2016-08-26 14:24:55 -0700 | [diff] [blame] | 106 | icmpHeader.SetSequence(mEchoSequence++); |
Jonathan Hui | 027e009 | 2016-08-29 09:31:26 -0700 | [diff] [blame] | 107 | |
| 108 | SuccessOrExit(error = aMessage.Prepend(&icmpHeader, sizeof(icmpHeader))); |
| 109 | aMessage.SetOffset(0); |
Jonathan Hui | 2029ef6 | 2016-08-26 14:24:55 -0700 | [diff] [blame] | 110 | SuccessOrExit(error = mIp6.SendDatagram(aMessage, messageInfoLocal, kProtoIcmp6)); |
Jonathan Hui | 027e009 | 2016-08-29 09:31:26 -0700 | [diff] [blame] | 111 | |
Nick Banks | 1c18f45 | 2017-03-08 12:40:49 -0800 | [diff] [blame] | 112 | otLogInfoIcmp(GetInstance(), "Sent echo request: (seq = %d)", icmpHeader.GetSequence()); |
Jonathan Hui | 027e009 | 2016-08-29 09:31:26 -0700 | [diff] [blame] | 113 | |
| 114 | exit: |
| 115 | return error; |
| 116 | } |
| 117 | |
Łukasz Duda | 8b8f783 | 2017-01-13 02:41:40 +0100 | [diff] [blame] | 118 | ThreadError Icmp::SendError(IcmpHeader::Type aType, IcmpHeader::Code aCode, const MessageInfo &aMessageInfo, |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 119 | const Header &aHeader) |
| 120 | { |
| 121 | ThreadError error = kThreadError_None; |
Łukasz Duda | 8b8f783 | 2017-01-13 02:41:40 +0100 | [diff] [blame] | 122 | MessageInfo messageInfoLocal; |
Jonathan Hui | 3a439e5 | 2016-05-11 17:01:38 -0700 | [diff] [blame] | 123 | Message *message = NULL; |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 124 | IcmpHeader icmp6Header; |
| 125 | |
Łukasz Duda | 8b8f783 | 2017-01-13 02:41:40 +0100 | [diff] [blame] | 126 | messageInfoLocal = aMessageInfo; |
| 127 | |
Jonathan Hui | 2029ef6 | 2016-08-26 14:24:55 -0700 | [diff] [blame] | 128 | VerifyOrExit((message = mIp6.NewMessage(0)) != NULL, error = kThreadError_NoBufs); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 129 | 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 Duda | 8b8f783 | 2017-01-13 02:41:40 +0100 | [diff] [blame] | 138 | SuccessOrExit(error = mIp6.SendDatagram(*message, messageInfoLocal, kProtoIcmp6)); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 139 | |
Nick Banks | 1c18f45 | 2017-03-08 12:40:49 -0800 | [diff] [blame] | 140 | otLogInfoIcmp(GetInstance(), "Sent ICMPv6 Error"); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 141 | |
| 142 | exit: |
Jonathan Hui | 3a439e5 | 2016-05-11 17:01:38 -0700 | [diff] [blame] | 143 | |
| 144 | if (error != kThreadError_None && message != NULL) |
| 145 | { |
Jonathan Hui | e22c123 | 2016-08-29 18:45:17 -0700 | [diff] [blame] | 146 | message->Free(); |
Jonathan Hui | 3a439e5 | 2016-05-11 17:01:38 -0700 | [diff] [blame] | 147 | } |
| 148 | |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 149 | return error; |
| 150 | } |
| 151 | |
| 152 | ThreadError 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 Hui | 49ac7fb | 2017-04-05 09:44:22 -0700 | [diff] [blame] | 159 | VerifyOrExit(aMessage.Read(aMessage.GetOffset(), sizeof(icmp6Header), &icmp6Header) == sizeof(icmp6Header)); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 160 | payloadLength = aMessage.GetLength() - aMessage.GetOffset(); |
| 161 | |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 162 | // verify checksum |
| 163 | checksum = Ip6::ComputePseudoheaderChecksum(aMessageInfo.GetPeerAddr(), aMessageInfo.GetSockAddr(), |
| 164 | payloadLength, kProtoIcmp6); |
| 165 | checksum = aMessage.UpdateChecksum(checksum, aMessage.GetOffset(), payloadLength); |
Jonathan Hui | 49ac7fb | 2017-04-05 09:44:22 -0700 | [diff] [blame] | 166 | VerifyOrExit(checksum == 0xffff); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 167 | |
Łukasz Duda | 4f35cdb | 2017-02-24 21:13:59 +0100 | [diff] [blame] | 168 | if (mIsEchoEnabled && (icmp6Header.GetType() == kIcmp6TypeEchoRequest)) |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 169 | { |
Łukasz Duda | 4f35cdb | 2017-02-24 21:13:59 +0100 | [diff] [blame] | 170 | HandleEchoRequest(aMessage, aMessageInfo); |
| 171 | } |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 172 | |
Łukasz Duda | 4f35cdb | 2017-02-24 21:13:59 +0100 | [diff] [blame] | 173 | aMessage.MoveOffset(sizeof(icmp6Header)); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 174 | |
Łukasz Duda | 4f35cdb | 2017-02-24 21:13:59 +0100 | [diff] [blame] | 175 | for (IcmpHandler *handler = mHandlers; handler; handler = handler->GetNext()) |
| 176 | { |
| 177 | handler->HandleReceiveMessage(aMessage, aMessageInfo, icmp6Header); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 178 | } |
| 179 | |
| 180 | exit: |
| 181 | return error; |
| 182 | } |
| 183 | |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 184 | ThreadError Icmp::HandleEchoRequest(Message &aRequestMessage, const MessageInfo &aMessageInfo) |
| 185 | { |
| 186 | ThreadError error = kThreadError_None; |
| 187 | IcmpHeader icmp6Header; |
Jonathan Hui | 3a439e5 | 2016-05-11 17:01:38 -0700 | [diff] [blame] | 188 | Message *replyMessage = NULL; |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 189 | MessageInfo replyMessageInfo; |
| 190 | uint16_t payloadLength; |
| 191 | |
Nick Banks | 1c18f45 | 2017-03-08 12:40:49 -0800 | [diff] [blame] | 192 | otLogInfoIcmp(GetInstance(), "Received Echo Request"); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 193 | |
| 194 | icmp6Header.Init(); |
Łukasz Duda | 4f35cdb | 2017-02-24 21:13:59 +0100 | [diff] [blame] | 195 | icmp6Header.SetType(kIcmp6TypeEchoReply); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 196 | |
Nick Banks | fbc5245 | 2016-10-03 10:45:25 -0700 | [diff] [blame] | 197 | if ((replyMessage = mIp6.NewMessage(0)) == NULL) |
| 198 | { |
Nick Banks | 1c18f45 | 2017-03-08 12:40:49 -0800 | [diff] [blame] | 199 | otLogDebgIcmp(GetInstance(), "Failed to allocate a new message"); |
Nick Banks | fbc5245 | 2016-10-03 10:45:25 -0700 | [diff] [blame] | 200 | ExitNow(); |
| 201 | } |
| 202 | |
Jonathan Hui | a43fb45 | 2016-06-24 12:43:02 -0700 | [diff] [blame] | 203 | payloadLength = aRequestMessage.GetLength() - aRequestMessage.GetOffset() - IcmpHeader::GetDataOffset(); |
Jonathan Hui | aeee0b9 | 2016-10-07 15:51:20 -0700 | [diff] [blame] | 204 | SuccessOrExit(error = replyMessage->SetLength(IcmpHeader::GetDataOffset() + payloadLength)); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 205 | |
| 206 | replyMessage->Write(0, IcmpHeader::GetDataOffset(), &icmp6Header); |
| 207 | aRequestMessage.CopyTo(aRequestMessage.GetOffset() + IcmpHeader::GetDataOffset(), |
| 208 | IcmpHeader::GetDataOffset(), payloadLength, *replyMessage); |
| 209 | |
Jonathan Hui | f0a5239 | 2016-10-27 09:42:48 -0700 | [diff] [blame] | 210 | replyMessageInfo.SetPeerAddr(aMessageInfo.GetPeerAddr()); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 211 | |
| 212 | if (!aMessageInfo.GetSockAddr().IsMulticast()) |
| 213 | { |
Jonathan Hui | f0a5239 | 2016-10-27 09:42:48 -0700 | [diff] [blame] | 214 | replyMessageInfo.SetSockAddr(aMessageInfo.GetSockAddr()); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 215 | } |
| 216 | |
Jonathan Hui | f0a5239 | 2016-10-27 09:42:48 -0700 | [diff] [blame] | 217 | replyMessageInfo.SetInterfaceId(aMessageInfo.mInterfaceId); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 218 | |
Jonathan Hui | 2029ef6 | 2016-08-26 14:24:55 -0700 | [diff] [blame] | 219 | SuccessOrExit(error = mIp6.SendDatagram(*replyMessage, replyMessageInfo, kProtoIcmp6)); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 220 | |
rongli | add8639 | 2016-09-24 02:12:53 +0800 | [diff] [blame] | 221 | replyMessage->Read(replyMessage->GetOffset(), sizeof(icmp6Header), &icmp6Header); |
Nick Banks | 1c18f45 | 2017-03-08 12:40:49 -0800 | [diff] [blame] | 222 | otLogInfoIcmp(GetInstance(), "Sent Echo Reply (seq = %d)", icmp6Header.GetSequence()); |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 223 | |
| 224 | exit: |
Jonathan Hui | 3a439e5 | 2016-05-11 17:01:38 -0700 | [diff] [blame] | 225 | |
| 226 | if (error != kThreadError_None && replyMessage != NULL) |
| 227 | { |
Jonathan Hui | e22c123 | 2016-08-29 18:45:17 -0700 | [diff] [blame] | 228 | replyMessage->Free(); |
Jonathan Hui | 3a439e5 | 2016-05-11 17:01:38 -0700 | [diff] [blame] | 229 | } |
| 230 | |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 231 | return error; |
| 232 | } |
| 233 | |
Jonathan Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 234 | ThreadError 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 Hui | 4f9945c | 2016-05-10 20:48:47 -0700 | [diff] [blame] | 249 | } // namespace Ip6 |
Jonathan Hui | 1eabda6 | 2017-04-27 22:29:05 -0700 | [diff] [blame] | 250 | } // namespace ot |