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