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