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