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