1 /*
2  *    Copyright (c) 2019, 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" AND
17  *    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  *    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  *    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20  *    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  *    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  *    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  *    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  *    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /**
29  * @file
30  *   This file implements Thread Radio Encapsulation Link (TREL).
31  */
32 
33 #include "trel_link.hpp"
34 
35 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
36 
37 #include "common/code_utils.hpp"
38 #include "common/debug.hpp"
39 #include "common/locator_getters.hpp"
40 #include "common/log.hpp"
41 #include "instance/instance.hpp"
42 
43 namespace ot {
44 namespace Trel {
45 
46 RegisterLogModule("TrelLink");
47 
Link(Instance & aInstance)48 Link::Link(Instance &aInstance)
49     : InstanceLocator(aInstance)
50     , mState(kStateDisabled)
51     , mRxChannel(0)
52     , mPanId(Mac::kPanIdBroadcast)
53     , mTxPacketNumber(0)
54     , mTxTasklet(aInstance)
55     , mTimer(aInstance)
56     , mInterface(aInstance)
57 {
58     ClearAllBytes(mTxFrame);
59     ClearAllBytes(mRxFrame);
60     ClearAllBytes(mAckFrameBuffer);
61 
62     mTxFrame.mPsdu = &mTxPacketBuffer[kMaxHeaderSize];
63     mTxFrame.SetLength(0);
64 
65 #if OPENTHREAD_CONFIG_MULTI_RADIO
66     mTxFrame.SetRadioType(Mac::kRadioTypeTrel);
67     mRxFrame.SetRadioType(Mac::kRadioTypeTrel);
68 #endif
69 
70     mTimer.Start(kAckWaitWindow);
71 }
72 
AfterInit(void)73 void Link::AfterInit(void) { mInterface.Init(); }
74 
Enable(void)75 void Link::Enable(void)
76 {
77     mInterface.Enable();
78 
79     if (mState == kStateDisabled)
80     {
81         SetState(kStateSleep);
82     }
83 }
84 
Disable(void)85 void Link::Disable(void)
86 {
87     mInterface.Disable();
88 
89     if (mState != kStateDisabled)
90     {
91         SetState(kStateDisabled);
92     }
93 }
94 
Sleep(void)95 void Link::Sleep(void)
96 {
97     OT_ASSERT(mState != kStateDisabled);
98     SetState(kStateSleep);
99 }
100 
Receive(uint8_t aChannel)101 void Link::Receive(uint8_t aChannel)
102 {
103     OT_ASSERT(mState != kStateDisabled);
104     mRxChannel = aChannel;
105     SetState(kStateReceive);
106 }
107 
Send(void)108 void Link::Send(void)
109 {
110     OT_ASSERT(mState != kStateDisabled);
111 
112     SetState(kStateTransmit);
113     mTxTasklet.Post();
114 }
115 
HandleTxTasklet(void)116 void Link::HandleTxTasklet(void) { BeginTransmit(); }
117 
BeginTransmit(void)118 void Link::BeginTransmit(void)
119 {
120     Mac::Address  destAddr;
121     Mac::PanId    destPanId;
122     Header::Type  type;
123     Packet        txPacket;
124     Neighbor     *neighbor    = nullptr;
125     Mac::RxFrame *ackFrame    = nullptr;
126     bool          isDiscovery = false;
127 
128     VerifyOrExit(mState == kStateTransmit);
129 
130     // After sending a frame on a given channel we should
131     // continue to rx on same channel
132     mRxChannel = mTxFrame.GetChannel();
133 
134     VerifyOrExit(!mTxFrame.IsEmpty(), InvokeSendDone(kErrorAbort));
135 
136     IgnoreError(mTxFrame.GetDstAddr(destAddr));
137 
138     if (destAddr.IsNone() || destAddr.IsBroadcast())
139     {
140         type = Header::kTypeBroadcast;
141     }
142     else
143     {
144         type     = Header::kTypeUnicast;
145         neighbor = Get<NeighborTable>().FindNeighbor(destAddr, Neighbor::kInStateAnyExceptInvalid);
146 
147         if (destAddr.IsShort())
148         {
149             if (neighbor != nullptr)
150             {
151                 destAddr.SetExtended(neighbor->GetExtAddress());
152             }
153             else
154             {
155                 // Send as a broadcast since we don't know the dest
156                 // ext address to include in the packet header.
157                 type = Header::kTypeBroadcast;
158             }
159         }
160     }
161 
162     if (type == Header::kTypeBroadcast)
163     {
164         // Thread utilizes broadcast transmissions to discover
165         // neighboring devices. We determine whether this broadcast
166         // frame tx is a discovery or normal data. All messages
167         // used for discovery either disable MAC security or utilize
168         // MAC Key ID mode 2. All data communication uses MAC Key ID
169         // Mode 1.
170 
171         if (!mTxFrame.GetSecurityEnabled())
172         {
173             isDiscovery = true;
174         }
175         else
176         {
177             uint8_t keyIdMode;
178 
179             IgnoreError(mTxFrame.GetKeyIdMode(keyIdMode));
180             isDiscovery = (keyIdMode == Mac::Frame::kKeyIdMode2);
181         }
182     }
183 
184     if (mTxFrame.GetDstPanId(destPanId) != kErrorNone)
185     {
186         destPanId = Mac::kPanIdBroadcast;
187     }
188 
189     txPacket.Init(type, mTxFrame.GetPsdu(), mTxFrame.GetLength());
190 
191     if (neighbor == nullptr)
192     {
193         txPacket.GetHeader().SetAckMode(Header::kNoAck);
194         txPacket.GetHeader().SetPacketNumber(mTxPacketNumber++);
195     }
196     else
197     {
198         txPacket.GetHeader().SetAckMode(Header::kAckRequested);
199         txPacket.GetHeader().SetPacketNumber(neighbor->mTrelTxPacketNumber++);
200         neighbor->mTrelCurrentPendingAcks++;
201     }
202 
203     txPacket.GetHeader().SetChannel(mTxFrame.GetChannel());
204     txPacket.GetHeader().SetPanId(destPanId);
205     txPacket.GetHeader().SetSource(Get<Mac::Mac>().GetExtAddress());
206 
207     if (type == Header::kTypeUnicast)
208     {
209         OT_ASSERT(destAddr.IsExtended());
210         txPacket.GetHeader().SetDestination(destAddr.GetExtended());
211     }
212 
213     LogDebg("BeginTransmit() [%s] plen:%d", txPacket.GetHeader().ToString().AsCString(), txPacket.GetPayloadLength());
214 
215     VerifyOrExit(mInterface.Send(txPacket, isDiscovery) == kErrorNone, InvokeSendDone(kErrorAbort));
216 
217     if (mTxFrame.GetAckRequest())
218     {
219         uint16_t fcf = Mac::Frame::kTypeAck;
220 
221         if (!Get<Mle::MleRouter>().IsRxOnWhenIdle())
222         {
223             fcf |= kFcfFramePending;
224         }
225 
226         // Prepare the ack frame (FCF followed by sequence number)
227         LittleEndian::WriteUint16(fcf, mAckFrameBuffer);
228         mAckFrameBuffer[sizeof(fcf)] = mTxFrame.GetSequence();
229 
230         mRxFrame.mPsdu    = mAckFrameBuffer;
231         mRxFrame.mLength  = k154AckFrameSize;
232         mRxFrame.mChannel = mTxFrame.GetChannel();
233 #if OPENTHREAD_CONFIG_MULTI_RADIO
234         mRxFrame.mRadioType = Mac::kRadioTypeTrel;
235 #endif
236         mRxFrame.mInfo.mRxInfo.mTimestamp             = 0;
237         mRxFrame.mInfo.mRxInfo.mRssi                  = Radio::kInvalidRssi;
238         mRxFrame.mInfo.mRxInfo.mLqi                   = OT_RADIO_LQI_NONE;
239         mRxFrame.mInfo.mRxInfo.mAckedWithFramePending = false;
240 
241         ackFrame = &mRxFrame;
242     }
243 
244     InvokeSendDone(kErrorNone, ackFrame);
245 
246 exit:
247     return;
248 }
249 
InvokeSendDone(Error aError,Mac::RxFrame * aAckFrame)250 void Link::InvokeSendDone(Error aError, Mac::RxFrame *aAckFrame)
251 {
252     SetState(kStateReceive);
253 
254     Get<Mac::Mac>().RecordFrameTransmitStatus(mTxFrame, aError, /* aRetryCount */ 0, /* aWillRetx */ false);
255     Get<Mac::Mac>().HandleTransmitDone(mTxFrame, aAckFrame, aError);
256 }
257 
HandleTimer(void)258 void Link::HandleTimer(void)
259 {
260     mTimer.Start(kAckWaitWindow);
261 
262 #if OPENTHREAD_FTD
263     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateAnyExceptInvalid))
264     {
265         HandleTimer(child);
266     }
267 
268     for (Router &router : Get<RouterTable>())
269     {
270         HandleTimer(router);
271     }
272 #endif
273 
274     // Parent and ParentCandidate should also be updated as neighbors.
275     // Parent is considered only when the device is detached or child.
276     // When device becomes a router/leader the parent entry is copied
277     // into the router table but the MLE parent may still stay in
278     // valid state. Note that "Parent Candidate" may be in use on a
279     // router/leader during a partition merge, so it is always treated
280     // as a neighbor.
281 
282     switch (Get<Mle::MleRouter>().GetRole())
283     {
284     case Mle::kRoleDisabled:
285         break;
286 
287     case Mle::kRoleDetached:
288     case Mle::kRoleChild:
289         HandleTimer(Get<Mle::MleRouter>().GetParent());
290 
291         OT_FALL_THROUGH;
292 
293     case Mle::kRoleRouter:
294     case Mle::kRoleLeader:
295         HandleTimer(Get<Mle::MleRouter>().GetParentCandidate());
296         break;
297     }
298 }
299 
HandleTimer(Neighbor & aNeighbor)300 void Link::HandleTimer(Neighbor &aNeighbor)
301 {
302     VerifyOrExit(!aNeighbor.IsStateInvalid());
303 
304     // Any remaining previous pending ack has timed out.
305 
306     while (aNeighbor.mTrelPreviousPendingAcks > 0)
307     {
308         aNeighbor.mTrelPreviousPendingAcks--;
309 
310         ReportDeferredAckStatus(aNeighbor, kErrorNoAck);
311         VerifyOrExit(!aNeighbor.IsStateInvalid());
312     }
313 
314     aNeighbor.mTrelPreviousPendingAcks = aNeighbor.mTrelCurrentPendingAcks;
315     aNeighbor.mTrelCurrentPendingAcks  = 0;
316 
317 exit:
318     return;
319 }
320 
ProcessReceivedPacket(Packet & aPacket)321 void Link::ProcessReceivedPacket(Packet &aPacket)
322 {
323     Header::Type type;
324 
325     VerifyOrExit(aPacket.IsHeaderValid());
326 
327     type = aPacket.GetHeader().GetType();
328 
329     if (type != Header::kTypeAck)
330     {
331         // No need to check state or channel for a TREL ack packet.
332         // Note that TREL ack may be received much later than the tx
333         // and device can be on a different rx channel.
334 
335         VerifyOrExit((mState == kStateReceive) || (mState == kStateTransmit));
336         VerifyOrExit(aPacket.GetHeader().GetChannel() == mRxChannel);
337     }
338 
339     if (mPanId != Mac::kPanIdBroadcast)
340     {
341         Mac::PanId rxPanId = aPacket.GetHeader().GetPanId();
342 
343         VerifyOrExit((rxPanId == mPanId) || (rxPanId == Mac::kPanIdBroadcast));
344     }
345 
346     // Drop packets originating from same device.
347     VerifyOrExit(aPacket.GetHeader().GetSource() != Get<Mac::Mac>().GetExtAddress());
348 
349     if (type != Header::kTypeBroadcast)
350     {
351         VerifyOrExit(aPacket.GetHeader().GetDestination() == Get<Mac::Mac>().GetExtAddress());
352 
353         if (type == Header::kTypeAck)
354         {
355             HandleAck(aPacket);
356             ExitNow();
357         }
358     }
359 
360     LogDebg("ReceivedPacket() [%s] plen:%d", aPacket.GetHeader().ToString().AsCString(), aPacket.GetPayloadLength());
361 
362     if (aPacket.GetHeader().GetAckMode() == Header::kAckRequested)
363     {
364         SendAck(aPacket);
365     }
366 
367     mRxFrame.mPsdu    = aPacket.GetPayload();
368     mRxFrame.mLength  = aPacket.GetPayloadLength();
369     mRxFrame.mChannel = aPacket.GetHeader().GetChannel();
370 #if OPENTHREAD_CONFIG_MULTI_RADIO
371     mRxFrame.mRadioType = Mac::kRadioTypeTrel;
372 #endif
373     mRxFrame.mInfo.mRxInfo.mTimestamp             = 0;
374     mRxFrame.mInfo.mRxInfo.mRssi                  = kRxRssi;
375     mRxFrame.mInfo.mRxInfo.mLqi                   = OT_RADIO_LQI_NONE;
376     mRxFrame.mInfo.mRxInfo.mAckedWithFramePending = true;
377 
378     Get<Mac::Mac>().HandleReceivedFrame(&mRxFrame, kErrorNone);
379 
380 exit:
381     return;
382 }
383 
HandleAck(Packet & aAckPacket)384 void Link::HandleAck(Packet &aAckPacket)
385 {
386     Error        ackError;
387     Mac::Address srcAddress;
388     Neighbor    *neighbor;
389     uint32_t     ackNumber;
390 
391     LogDebg("HandleAck() [%s]", aAckPacket.GetHeader().ToString().AsCString());
392 
393     srcAddress.SetExtended(aAckPacket.GetHeader().GetSource());
394     neighbor = Get<NeighborTable>().FindNeighbor(srcAddress, Neighbor::kInStateAnyExceptInvalid);
395     VerifyOrExit(neighbor != nullptr);
396 
397     ackNumber = aAckPacket.GetHeader().GetPacketNumber();
398 
399     // Verify that neighbor is waiting for acks and the received ack
400     // number is within the range of expected ack numbers.
401 
402     VerifyOrExit(neighbor->IsRxAckNumberValid(ackNumber));
403 
404     do
405     {
406         // Check whether the received ack number matches the next
407         // expected one. If it does not, it indicates that some of
408         // packets missed their acks.
409 
410         ackError = (ackNumber == neighbor->GetExpectedTrelAckNumber()) ? kErrorNone : kErrorNoAck;
411 
412         neighbor->DecrementPendingTrelAckCount();
413 
414         ReportDeferredAckStatus(*neighbor, ackError);
415         VerifyOrExit(!neighbor->IsStateInvalid());
416 
417     } while (ackError == kErrorNoAck);
418 
419 exit:
420     return;
421 }
422 
SendAck(Packet & aRxPacket)423 void Link::SendAck(Packet &aRxPacket)
424 {
425     Packet ackPacket;
426 
427     ackPacket.Init(mAckPacketBuffer, sizeof(mAckPacketBuffer));
428 
429     ackPacket.GetHeader().Init(Header::kTypeAck);
430     ackPacket.GetHeader().SetAckMode(Header::kNoAck);
431     ackPacket.GetHeader().SetChannel(aRxPacket.GetHeader().GetChannel());
432     ackPacket.GetHeader().SetPanId(aRxPacket.GetHeader().GetPanId());
433     ackPacket.GetHeader().SetPacketNumber(aRxPacket.GetHeader().GetPacketNumber());
434     ackPacket.GetHeader().SetSource(Get<Mac::Mac>().GetExtAddress());
435     ackPacket.GetHeader().SetDestination(aRxPacket.GetHeader().GetSource());
436 
437     LogDebg("SendAck [%s]", ackPacket.GetHeader().ToString().AsCString());
438 
439     IgnoreError(mInterface.Send(ackPacket));
440 }
441 
ReportDeferredAckStatus(Neighbor & aNeighbor,Error aError)442 void Link::ReportDeferredAckStatus(Neighbor &aNeighbor, Error aError)
443 {
444     LogDebg("ReportDeferredAckStatus(): %s for %s", aNeighbor.GetExtAddress().ToString().AsCString(),
445             ErrorToString(aError));
446 
447     Get<MeshForwarder>().HandleDeferredAck(aNeighbor, aError);
448 }
449 
SetState(State aState)450 void Link::SetState(State aState)
451 {
452     if (mState != aState)
453     {
454         LogDebg("State: %s -> %s", StateToString(mState), StateToString(aState));
455         mState = aState;
456     }
457 }
458 
HandleNotifierEvents(Events aEvents)459 void Link::HandleNotifierEvents(Events aEvents)
460 {
461     if (aEvents.Contains(kEventThreadExtPanIdChanged))
462     {
463         mInterface.HandleExtPanIdChange();
464     }
465 }
466 
467 // LCOV_EXCL_START
468 
StateToString(State aState)469 const char *Link::StateToString(State aState)
470 {
471     static const char *const kStateStrings[] = {
472         "Disabled", // (0) kStateDisabled
473         "Sleep",    // (1) kStateSleep
474         "Receive",  // (2) kStateReceive
475         "Transmit", // (3) kStateTransmit
476     };
477 
478     static_assert(0 == kStateDisabled, "kStateDisabled value is incorrect");
479     static_assert(1 == kStateSleep, "kStateSleep value is incorrect");
480     static_assert(2 == kStateReceive, "kStateReceive value is incorrect");
481     static_assert(3 == kStateTransmit, "kStateTransmit value is incorrect");
482 
483     return kStateStrings[aState];
484 }
485 
486 // LCOV_EXCL_STOP
487 
488 } // namespace Trel
489 } // namespace ot
490 
491 #endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
492