1 /*
2  *  Copyright (c) 2021, 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 Anycast Locator functionality.
32  */
33 
34 #include "anycast_locator.hpp"
35 
36 #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE
37 
38 #include "common/as_core_type.hpp"
39 #include "common/code_utils.hpp"
40 #include "common/instance.hpp"
41 #include "common/locator_getters.hpp"
42 #include "thread/thread_tlvs.hpp"
43 #include "thread/uri_paths.hpp"
44 
45 namespace ot {
46 
AnycastLocator(Instance & aInstance)47 AnycastLocator::AnycastLocator(Instance &aInstance)
48     : InstanceLocator(aInstance)
49 
50 {
51 }
52 
Locate(const Ip6::Address & aAnycastAddress,LocatorCallback aCallback,void * aContext)53 Error AnycastLocator::Locate(const Ip6::Address &aAnycastAddress, LocatorCallback aCallback, void *aContext)
54 {
55     Error            error   = kErrorNone;
56     Coap::Message   *message = nullptr;
57     Tmf::MessageInfo messageInfo(GetInstance());
58 
59     VerifyOrExit((aCallback != nullptr) && Get<Mle::Mle>().IsAnycastLocator(aAnycastAddress),
60                  error = kErrorInvalidArgs);
61 
62     message = Get<Tmf::Agent>().NewConfirmablePostMessage(kUriAnycastLocate);
63     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
64 
65     if (mCallback.IsSet())
66     {
67         IgnoreError(Get<Tmf::Agent>().AbortTransaction(HandleResponse, this));
68     }
69 
70     messageInfo.SetSockAddrToRlocPeerAddrTo(aAnycastAddress);
71 
72     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, HandleResponse, this));
73 
74     mCallback.Set(aCallback, aContext);
75 
76 exit:
77     FreeMessageOnError(message, error);
78     return error;
79 }
80 
HandleResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aError)81 void AnycastLocator::HandleResponse(void                *aContext,
82                                     otMessage           *aMessage,
83                                     const otMessageInfo *aMessageInfo,
84                                     Error                aError)
85 {
86     static_cast<AnycastLocator *>(aContext)->HandleResponse(AsCoapMessagePtr(aMessage), AsCoreTypePtr(aMessageInfo),
87                                                             aError);
88 }
89 
HandleResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aError)90 void AnycastLocator::HandleResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aError)
91 {
92     OT_UNUSED_VARIABLE(aMessageInfo);
93 
94     uint16_t            rloc16  = Mac::kShortAddrInvalid;
95     const Ip6::Address *address = nullptr;
96     Ip6::Address        meshLocalAddress;
97 
98     SuccessOrExit(aError);
99     OT_ASSERT(aMessage != nullptr);
100 
101     meshLocalAddress.SetPrefix(Get<Mle::Mle>().GetMeshLocalPrefix());
102     SuccessOrExit(Tlv::Find<ThreadMeshLocalEidTlv>(*aMessage, meshLocalAddress.GetIid()));
103     SuccessOrExit(Tlv::Find<ThreadRloc16Tlv>(*aMessage, rloc16));
104 
105 #if OPENTHREAD_FTD
106     Get<AddressResolver>().UpdateSnoopedCacheEntry(meshLocalAddress, rloc16, Get<Mac::Mac>().GetShortAddress());
107 #endif
108 
109     address = &meshLocalAddress;
110 
111 exit:
112     if (mCallback.IsSet())
113     {
114         Callback<LocatorCallback> callbackCopy = mCallback;
115 
116         mCallback.Clear();
117         callbackCopy.Invoke(aError, address, rloc16);
118     }
119 }
120 
121 #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_SEND_RESPONSE
122 
123 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)124 void AnycastLocator::HandleTmf<kUriAnycastLocate>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
125 {
126     Coap::Message *message = nullptr;
127 
128     VerifyOrExit(aMessage.IsConfirmablePostRequest());
129 
130     message = Get<Tmf::Agent>().NewResponseMessage(aMessage);
131     VerifyOrExit(message != nullptr);
132 
133     SuccessOrExit(Tlv::Append<ThreadMeshLocalEidTlv>(*message, Get<Mle::Mle>().GetMeshLocal64().GetIid()));
134     SuccessOrExit(Tlv::Append<ThreadRloc16Tlv>(*message, Get<Mle::Mle>().GetRloc16()));
135 
136     SuccessOrExit(Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
137     message = nullptr;
138 
139 exit:
140     FreeMessage(message);
141 }
142 
143 #endif // OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_SEND_RESPONSE
144 
145 } // namespace ot
146 
147 #endif // OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE
148