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