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