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