• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2016, The OpenThread Authors.
3  *  All rights reserved.
4  *
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.
15  *
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.
27  */
28 
29 /**
30  * @file
31  *   This file implements ICMPv6.
32  */
33 
34 #include "icmp6.hpp"
35 
36 #include "instance/instance.hpp"
37 
38 namespace ot {
39 namespace Ip6 {
40 
41 RegisterLogModule("Icmp6");
42 
Icmp(Instance & aInstance)43 Icmp::Icmp(Instance &aInstance)
44     : InstanceLocator(aInstance)
45     , mEchoSequence(1)
46     , mEchoMode(OT_ICMP6_ECHO_HANDLER_ALL)
47 {
48 }
49 
NewMessage(void)50 Message *Icmp::NewMessage(void) { return Get<Ip6>().NewMessage(sizeof(Header)); }
51 
RegisterHandler(Handler & aHandler)52 Error Icmp::RegisterHandler(Handler &aHandler) { return mHandlers.Add(aHandler); }
53 
SendEchoRequest(Message & aMessage,const MessageInfo & aMessageInfo,uint16_t aIdentifier)54 Error Icmp::SendEchoRequest(Message &aMessage, const MessageInfo &aMessageInfo, uint16_t aIdentifier)
55 {
56     Error       error = kErrorNone;
57     MessageInfo messageInfoLocal;
58     Header      icmpHeader;
59 
60     messageInfoLocal = aMessageInfo;
61 
62     icmpHeader.Clear();
63     icmpHeader.SetType(Header::kTypeEchoRequest);
64     icmpHeader.SetId(aIdentifier);
65     icmpHeader.SetSequence(mEchoSequence++);
66 
67     SuccessOrExit(error = aMessage.Prepend(icmpHeader));
68     aMessage.SetOffset(0);
69     SuccessOrExit(error = Get<Ip6>().SendDatagram(aMessage, messageInfoLocal, kProtoIcmp6));
70 
71     LogInfo("Sent echo request: (seq = %d)", icmpHeader.GetSequence());
72 
73 exit:
74     return error;
75 }
76 
SendError(Header::Type aType,Header::Code aCode,const MessageInfo & aMessageInfo,const Message & aMessage)77 Error Icmp::SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Message &aMessage)
78 {
79     Error   error;
80     Headers headers;
81 
82     SuccessOrExit(error = headers.ParseFrom(aMessage));
83     error = SendError(aType, aCode, aMessageInfo, headers);
84 
85 exit:
86     return error;
87 }
88 
SendError(Header::Type aType,Header::Code aCode,const MessageInfo & aMessageInfo,const Headers & aHeaders)89 Error Icmp::SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Headers &aHeaders)
90 {
91     Error             error = kErrorNone;
92     MessageInfo       messageInfoLocal;
93     Message          *message = nullptr;
94     Header            icmp6Header;
95     Message::Settings settings(kWithLinkSecurity, Message::kPriorityNet);
96 
97     if (aHeaders.GetIpProto() == kProtoIcmp6)
98     {
99         VerifyOrExit(!aHeaders.GetIcmpHeader().IsError());
100     }
101 
102     messageInfoLocal = aMessageInfo;
103 
104     VerifyOrExit((message = Get<Ip6>().NewMessage(0, settings)) != nullptr, error = kErrorNoBufs);
105 
106     // Prepare the ICMPv6 error message. We only include the IPv6 header
107     // of the original message causing the error.
108 
109     icmp6Header.Clear();
110     icmp6Header.SetType(aType);
111     icmp6Header.SetCode(aCode);
112     SuccessOrExit(error = message->Append(icmp6Header));
113     SuccessOrExit(error = message->Append(aHeaders.GetIp6Header()));
114 
115     SuccessOrExit(error = Get<Ip6>().SendDatagram(*message, messageInfoLocal, kProtoIcmp6));
116 
117     LogInfo("Sent ICMPv6 Error");
118 
119 exit:
120     FreeMessageOnError(message, error);
121     return error;
122 }
123 
HandleMessage(Message & aMessage,MessageInfo & aMessageInfo)124 Error Icmp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo)
125 {
126     Error  error = kErrorNone;
127     Header icmp6Header;
128 
129     SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), icmp6Header));
130 
131     SuccessOrExit(error = Checksum::VerifyMessageChecksum(aMessage, aMessageInfo, kProtoIcmp6));
132 
133     if (icmp6Header.GetType() == Header::kTypeEchoRequest)
134     {
135         SuccessOrExit(error = HandleEchoRequest(aMessage, aMessageInfo));
136     }
137 
138     aMessage.MoveOffset(sizeof(icmp6Header));
139 
140     for (Handler &handler : mHandlers)
141     {
142         handler.HandleReceiveMessage(aMessage, aMessageInfo, icmp6Header);
143     }
144 
145 exit:
146     return error;
147 }
148 
ShouldHandleEchoRequest(const Address & aAddress)149 bool Icmp::ShouldHandleEchoRequest(const Address &aAddress)
150 {
151     bool rval = false;
152 
153     switch (mEchoMode)
154     {
155     case OT_ICMP6_ECHO_HANDLER_DISABLED:
156         rval = false;
157         break;
158     case OT_ICMP6_ECHO_HANDLER_UNICAST_ONLY:
159         rval = !aAddress.IsMulticast();
160         break;
161     case OT_ICMP6_ECHO_HANDLER_MULTICAST_ONLY:
162         rval = aAddress.IsMulticast();
163         break;
164     case OT_ICMP6_ECHO_HANDLER_ALL:
165         rval = true;
166         break;
167     case OT_ICMP6_ECHO_HANDLER_RLOC_ALOC_ONLY:
168         rval = aAddress.GetIid().IsLocator();
169         break;
170     }
171 
172     return rval;
173 }
174 
HandleEchoRequest(Message & aRequestMessage,const MessageInfo & aMessageInfo)175 Error Icmp::HandleEchoRequest(Message &aRequestMessage, const MessageInfo &aMessageInfo)
176 {
177     Error       error = kErrorNone;
178     Header      icmp6Header;
179     Message    *replyMessage = nullptr;
180     MessageInfo replyMessageInfo;
181     uint16_t    dataOffset;
182 
183     VerifyOrExit(ShouldHandleEchoRequest(aMessageInfo.GetSockAddr()));
184 
185     LogInfo("Received Echo Request");
186 
187     icmp6Header.Clear();
188     icmp6Header.SetType(Header::kTypeEchoReply);
189 
190     if ((replyMessage = Get<Ip6>().NewMessage(0)) == nullptr)
191     {
192         LogDebg("Failed to allocate a new message");
193         ExitNow();
194     }
195 
196     dataOffset = aRequestMessage.GetOffset() + Header::kDataFieldOffset;
197 
198     SuccessOrExit(error = replyMessage->AppendBytes(&icmp6Header, Header::kDataFieldOffset));
199     SuccessOrExit(error = replyMessage->AppendBytesFromMessage(aRequestMessage, dataOffset,
200                                                                aRequestMessage.GetLength() - dataOffset));
201 
202     replyMessageInfo.SetPeerAddr(aMessageInfo.GetPeerAddr());
203 
204     if (!aMessageInfo.GetSockAddr().IsMulticast())
205     {
206         replyMessageInfo.SetSockAddr(aMessageInfo.GetSockAddr());
207     }
208 
209     SuccessOrExit(error = Get<Ip6>().SendDatagram(*replyMessage, replyMessageInfo, kProtoIcmp6));
210 
211     IgnoreError(replyMessage->Read(replyMessage->GetOffset(), icmp6Header));
212     LogInfo("Sent Echo Reply (seq = %d)", icmp6Header.GetSequence());
213 
214 exit:
215     FreeMessageOnError(replyMessage, error);
216     return error;
217 }
218 
219 } // namespace Ip6
220 } // namespace ot
221