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