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"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "mac_frame.h"
30
31 #include <assert.h>
32
33 #include <openthread/platform/radio.h>
34
35 #include "common/code_utils.hpp"
36 #include "mac/mac_frame.hpp"
37
38 using namespace ot;
39
otMacFrameDoesAddrMatch(const otRadioFrame * aFrame,otPanId aPanId,otShortAddress aShortAddress,const otExtAddress * aExtAddress)40 bool otMacFrameDoesAddrMatch(const otRadioFrame *aFrame,
41 otPanId aPanId,
42 otShortAddress aShortAddress,
43 const otExtAddress *aExtAddress)
44 {
45 return otMacFrameDoesAddrMatchAny(aFrame, aPanId, aShortAddress, Mac::kShortAddrInvalid, aExtAddress);
46 }
47
otMacFrameDoesAddrMatchAny(const otRadioFrame * aFrame,otPanId aPanId,otShortAddress aShortAddress,otShortAddress aAltShortAddress,const otExtAddress * aExtAddress)48 bool otMacFrameDoesAddrMatchAny(const otRadioFrame *aFrame,
49 otPanId aPanId,
50 otShortAddress aShortAddress,
51 otShortAddress aAltShortAddress,
52 const otExtAddress *aExtAddress)
53 {
54 const Mac::Frame &frame = *static_cast<const Mac::Frame *>(aFrame);
55 bool rval = true;
56 Mac::Address dst;
57 Mac::PanId panid;
58
59 VerifyOrExit(frame.GetDstAddr(dst) == kErrorNone, rval = false);
60
61 switch (dst.GetType())
62 {
63 case Mac::Address::kTypeShort:
64 VerifyOrExit(dst.GetShort() == Mac::kShortAddrBroadcast || dst.GetShort() == aShortAddress ||
65 (aAltShortAddress != Mac::kShortAddrInvalid && dst.GetShort() == aAltShortAddress),
66 rval = false);
67 break;
68
69 case Mac::Address::kTypeExtended:
70 VerifyOrExit(dst.GetExtended() == *static_cast<const Mac::ExtAddress *>(aExtAddress), rval = false);
71 break;
72
73 case Mac::Address::kTypeNone:
74 break;
75 }
76
77 SuccessOrExit(frame.GetDstPanId(panid));
78 VerifyOrExit(panid == Mac::kPanIdBroadcast || panid == aPanId, rval = false);
79
80 exit:
81 return rval;
82 }
83
otMacFrameIsAck(const otRadioFrame * aFrame)84 bool otMacFrameIsAck(const otRadioFrame *aFrame)
85 {
86 return static_cast<const Mac::Frame *>(aFrame)->GetType() == Mac::Frame::kTypeAck;
87 }
88
otMacFrameIsData(const otRadioFrame * aFrame)89 bool otMacFrameIsData(const otRadioFrame *aFrame)
90 {
91 return static_cast<const Mac::Frame *>(aFrame)->GetType() == Mac::Frame::kTypeData;
92 }
93
otMacFrameIsCommand(const otRadioFrame * aFrame)94 bool otMacFrameIsCommand(const otRadioFrame *aFrame)
95 {
96 return static_cast<const Mac::Frame *>(aFrame)->GetType() == Mac::Frame::kTypeMacCmd;
97 }
98
otMacFrameIsDataRequest(const otRadioFrame * aFrame)99 bool otMacFrameIsDataRequest(const otRadioFrame *aFrame)
100 {
101 return static_cast<const Mac::Frame *>(aFrame)->IsDataRequestCommand();
102 }
103
otMacFrameIsAckRequested(const otRadioFrame * aFrame)104 bool otMacFrameIsAckRequested(const otRadioFrame *aFrame)
105 {
106 return static_cast<const Mac::Frame *>(aFrame)->GetAckRequest();
107 }
108
GetOtMacAddress(const Mac::Address & aInAddress,otMacAddress * aOutAddress)109 static void GetOtMacAddress(const Mac::Address &aInAddress, otMacAddress *aOutAddress)
110 {
111 switch (aInAddress.GetType())
112 {
113 case Mac::Address::kTypeNone:
114 aOutAddress->mType = OT_MAC_ADDRESS_TYPE_NONE;
115 break;
116
117 case Mac::Address::kTypeShort:
118 aOutAddress->mType = OT_MAC_ADDRESS_TYPE_SHORT;
119 aOutAddress->mAddress.mShortAddress = aInAddress.GetShort();
120 break;
121
122 case Mac::Address::kTypeExtended:
123 aOutAddress->mType = OT_MAC_ADDRESS_TYPE_EXTENDED;
124 aOutAddress->mAddress.mExtAddress = aInAddress.GetExtended();
125 break;
126 }
127 }
128
otMacFrameGetSrcAddr(const otRadioFrame * aFrame,otMacAddress * aMacAddress)129 otError otMacFrameGetSrcAddr(const otRadioFrame *aFrame, otMacAddress *aMacAddress)
130 {
131 otError error;
132 Mac::Address address;
133
134 error = static_cast<const Mac::Frame *>(aFrame)->GetSrcAddr(address);
135 SuccessOrExit(error);
136
137 GetOtMacAddress(address, aMacAddress);
138
139 exit:
140 return error;
141 }
142
otMacFrameGetDstAddr(const otRadioFrame * aFrame,otMacAddress * aMacAddress)143 otError otMacFrameGetDstAddr(const otRadioFrame *aFrame, otMacAddress *aMacAddress)
144 {
145 otError error;
146 Mac::Address address;
147
148 error = static_cast<const Mac::Frame *>(aFrame)->GetDstAddr(address);
149 SuccessOrExit(error);
150
151 GetOtMacAddress(address, aMacAddress);
152
153 exit:
154 return error;
155 }
156
otMacFrameGetSequence(const otRadioFrame * aFrame,uint8_t * aSequence)157 otError otMacFrameGetSequence(const otRadioFrame *aFrame, uint8_t *aSequence)
158 {
159 otError error;
160
161 if (static_cast<const Mac::Frame *>(aFrame)->IsSequencePresent())
162 {
163 *aSequence = static_cast<const Mac::Frame *>(aFrame)->GetSequence();
164 error = kErrorNone;
165 }
166 else
167 {
168 error = kErrorParse;
169 }
170
171 return error;
172 }
173
otMacFrameProcessTransmitAesCcm(otRadioFrame * aFrame,const otExtAddress * aExtAddress)174 void otMacFrameProcessTransmitAesCcm(otRadioFrame *aFrame, const otExtAddress *aExtAddress)
175 {
176 static_cast<Mac::TxFrame *>(aFrame)->ProcessTransmitAesCcm(*static_cast<const Mac::ExtAddress *>(aExtAddress));
177 }
178
otMacFrameIsVersion2015(const otRadioFrame * aFrame)179 bool otMacFrameIsVersion2015(const otRadioFrame *aFrame)
180 {
181 return static_cast<const Mac::Frame *>(aFrame)->IsVersion2015();
182 }
183
otMacFrameGenerateImmAck(const otRadioFrame * aFrame,bool aIsFramePending,otRadioFrame * aAckFrame)184 void otMacFrameGenerateImmAck(const otRadioFrame *aFrame, bool aIsFramePending, otRadioFrame *aAckFrame)
185 {
186 assert(aFrame != nullptr && aAckFrame != nullptr);
187
188 static_cast<Mac::TxFrame *>(aAckFrame)->GenerateImmAck(*static_cast<const Mac::RxFrame *>(aFrame), aIsFramePending);
189 }
190
191 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
otMacFrameGenerateEnhAck(const otRadioFrame * aFrame,bool aIsFramePending,const uint8_t * aIeData,uint8_t aIeLength,otRadioFrame * aAckFrame)192 otError otMacFrameGenerateEnhAck(const otRadioFrame *aFrame,
193 bool aIsFramePending,
194 const uint8_t *aIeData,
195 uint8_t aIeLength,
196 otRadioFrame *aAckFrame)
197 {
198 assert(aFrame != nullptr && aAckFrame != nullptr);
199
200 return static_cast<Mac::TxFrame *>(aAckFrame)->GenerateEnhAck(*static_cast<const Mac::RxFrame *>(aFrame),
201 aIsFramePending, aIeData, aIeLength);
202 }
203 #endif
204
205 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
otMacFrameSetCslIe(otRadioFrame * aFrame,uint16_t aCslPeriod,uint16_t aCslPhase)206 void otMacFrameSetCslIe(otRadioFrame *aFrame, uint16_t aCslPeriod, uint16_t aCslPhase)
207 {
208 static_cast<Mac::Frame *>(aFrame)->SetCslIe(aCslPeriod, aCslPhase);
209 }
210 #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
211
otMacFrameIsSecurityEnabled(otRadioFrame * aFrame)212 bool otMacFrameIsSecurityEnabled(otRadioFrame *aFrame)
213 {
214 return static_cast<const Mac::Frame *>(aFrame)->GetSecurityEnabled();
215 }
216
otMacFrameIsKeyIdMode1(otRadioFrame * aFrame)217 bool otMacFrameIsKeyIdMode1(otRadioFrame *aFrame)
218 {
219 uint8_t keyIdMode;
220 otError error;
221
222 error = static_cast<const Mac::Frame *>(aFrame)->GetKeyIdMode(keyIdMode);
223
224 return (error == OT_ERROR_NONE) ? (keyIdMode == Mac::Frame::kKeyIdMode1) : false;
225 }
226
otMacFrameIsKeyIdMode2(otRadioFrame * aFrame)227 bool otMacFrameIsKeyIdMode2(otRadioFrame *aFrame)
228 {
229 uint8_t keyIdMode;
230 otError error;
231
232 error = static_cast<const Mac::Frame *>(aFrame)->GetKeyIdMode(keyIdMode);
233
234 return (error == OT_ERROR_NONE) ? (keyIdMode == Mac::Frame::kKeyIdMode2) : false;
235 }
236
otMacFrameGetKeyId(otRadioFrame * aFrame)237 uint8_t otMacFrameGetKeyId(otRadioFrame *aFrame)
238 {
239 uint8_t keyId = 0;
240
241 IgnoreError(static_cast<const Mac::Frame *>(aFrame)->GetKeyId(keyId));
242
243 return keyId;
244 }
245
otMacFrameSetKeyId(otRadioFrame * aFrame,uint8_t aKeyId)246 void otMacFrameSetKeyId(otRadioFrame *aFrame, uint8_t aKeyId) { static_cast<Mac::Frame *>(aFrame)->SetKeyId(aKeyId); }
247
otMacFrameGetFrameCounter(otRadioFrame * aFrame)248 uint32_t otMacFrameGetFrameCounter(otRadioFrame *aFrame)
249 {
250 uint32_t frameCounter = UINT32_MAX;
251
252 IgnoreError(static_cast<Mac::Frame *>(aFrame)->GetFrameCounter(frameCounter));
253
254 return frameCounter;
255 }
256
otMacFrameSetFrameCounter(otRadioFrame * aFrame,uint32_t aFrameCounter)257 void otMacFrameSetFrameCounter(otRadioFrame *aFrame, uint32_t aFrameCounter)
258 {
259 static_cast<Mac::Frame *>(aFrame)->SetFrameCounter(aFrameCounter);
260 }
261
262 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
otMacFrameGenerateCslIeTemplate(uint8_t * aDest)263 uint8_t otMacFrameGenerateCslIeTemplate(uint8_t *aDest)
264 {
265 assert(aDest != nullptr);
266
267 reinterpret_cast<Mac::HeaderIe *>(aDest)->SetId(Mac::CslIe::kHeaderIeId);
268 reinterpret_cast<Mac::HeaderIe *>(aDest)->SetLength(sizeof(Mac::CslIe));
269
270 return sizeof(Mac::HeaderIe) + sizeof(Mac::CslIe);
271 }
272 #endif
273
274 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
otMacFrameGenerateEnhAckProbingIe(uint8_t * aDest,const uint8_t * aIeData,uint8_t aIeDataLength)275 uint8_t otMacFrameGenerateEnhAckProbingIe(uint8_t *aDest, const uint8_t *aIeData, uint8_t aIeDataLength)
276 {
277 uint8_t len = sizeof(Mac::VendorIeHeader) + aIeDataLength;
278
279 assert(aDest != nullptr);
280
281 reinterpret_cast<Mac::HeaderIe *>(aDest)->SetId(Mac::ThreadIe::kHeaderIeId);
282 reinterpret_cast<Mac::HeaderIe *>(aDest)->SetLength(len);
283
284 aDest += sizeof(Mac::HeaderIe);
285
286 reinterpret_cast<Mac::VendorIeHeader *>(aDest)->SetVendorOui(Mac::ThreadIe::kVendorOuiThreadCompanyId);
287 reinterpret_cast<Mac::VendorIeHeader *>(aDest)->SetSubType(Mac::ThreadIe::kEnhAckProbingIe);
288
289 if (aIeData != nullptr)
290 {
291 aDest += sizeof(Mac::VendorIeHeader);
292 memcpy(aDest, aIeData, aIeDataLength);
293 }
294
295 return sizeof(Mac::HeaderIe) + len;
296 }
297
otMacFrameSetEnhAckProbingIe(otRadioFrame * aFrame,const uint8_t * aData,uint8_t aDataLen)298 void otMacFrameSetEnhAckProbingIe(otRadioFrame *aFrame, const uint8_t *aData, uint8_t aDataLen)
299 {
300 assert(aFrame != nullptr && aData != nullptr);
301
302 reinterpret_cast<Mac::Frame *>(aFrame)->SetEnhAckProbingIe(aData, aDataLen);
303 }
304 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
305 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
ComputeCslPhase(uint32_t aRadioTime,otRadioContext * aRadioContext)306 static uint16_t ComputeCslPhase(uint32_t aRadioTime, otRadioContext *aRadioContext)
307 {
308 return (aRadioContext->mCslSampleTime - aRadioTime) % (aRadioContext->mCslPeriod * OT_US_PER_TEN_SYMBOLS) /
309 OT_US_PER_TEN_SYMBOLS;
310 }
311 #endif
otMacFrameProcessTransmitSecurity(otRadioFrame * aFrame,otRadioContext * aRadioContext)312 otError otMacFrameProcessTransmitSecurity(otRadioFrame *aFrame, otRadioContext *aRadioContext)
313 {
314 otError error = OT_ERROR_NONE;
315 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
316 otMacKeyMaterial *key = nullptr;
317 uint8_t keyId;
318 uint32_t frameCounter;
319 bool processKeyId;
320
321 processKeyId =
322 #if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
323 otMacFrameIsKeyIdMode2(aFrame) ||
324 #endif
325 otMacFrameIsKeyIdMode1(aFrame);
326
327 VerifyOrExit(otMacFrameIsSecurityEnabled(aFrame) && processKeyId && !aFrame->mInfo.mTxInfo.mIsSecurityProcessed);
328
329 if (otMacFrameIsAck(aFrame))
330 {
331 keyId = otMacFrameGetKeyId(aFrame);
332
333 VerifyOrExit(keyId != 0, error = OT_ERROR_FAILED);
334
335 if (keyId == aRadioContext->mKeyId)
336 {
337 key = &aRadioContext->mCurrKey;
338 frameCounter = aRadioContext->mMacFrameCounter++;
339 }
340 else if (keyId == aRadioContext->mKeyId - 1)
341 {
342 key = &aRadioContext->mPrevKey;
343 frameCounter = aRadioContext->mPrevMacFrameCounter++;
344 }
345 else if (keyId == aRadioContext->mKeyId + 1)
346 {
347 key = &aRadioContext->mNextKey;
348 frameCounter = 0;
349 }
350 else
351 {
352 ExitNow(error = OT_ERROR_SECURITY);
353 }
354 }
355 else if (!aFrame->mInfo.mTxInfo.mIsHeaderUpdated)
356 {
357 key = &aRadioContext->mCurrKey;
358 keyId = aRadioContext->mKeyId;
359 frameCounter = aRadioContext->mMacFrameCounter++;
360 }
361
362 if (key != nullptr)
363 {
364 aFrame->mInfo.mTxInfo.mAesKey = key;
365
366 otMacFrameSetKeyId(aFrame, keyId);
367 otMacFrameSetFrameCounter(aFrame, frameCounter);
368 aFrame->mInfo.mTxInfo.mIsHeaderUpdated = true;
369 }
370 #else
371 VerifyOrExit(!aFrame->mInfo.mTxInfo.mIsSecurityProcessed);
372 #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
373
374 otMacFrameProcessTransmitAesCcm(aFrame, &aRadioContext->mExtAddress);
375
376 exit:
377 return error;
378 }
379
380 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
otMacFrameUpdateTimeIe(otRadioFrame * aFrame,uint64_t aRadioTime,otRadioContext * aRadioContext)381 void otMacFrameUpdateTimeIe(otRadioFrame *aFrame, uint64_t aRadioTime, otRadioContext *aRadioContext)
382 {
383 uint8_t *timeIe;
384 uint64_t time;
385
386 VerifyOrExit((aFrame->mInfo.mTxInfo.mIeInfo != nullptr) && (aFrame->mInfo.mTxInfo.mIeInfo->mTimeIeOffset != 0));
387
388 timeIe = aFrame->mPsdu + aFrame->mInfo.mTxInfo.mIeInfo->mTimeIeOffset;
389 time = aRadioTime + aFrame->mInfo.mTxInfo.mIeInfo->mNetworkTimeOffset;
390 *timeIe = aFrame->mInfo.mTxInfo.mIeInfo->mTimeSyncSeq;
391
392 *(++timeIe) = static_cast<uint8_t>(time & 0xff);
393 for (uint8_t i = 1; i < sizeof(uint64_t); i++)
394 {
395 time = time >> 8;
396 *(++timeIe) = static_cast<uint8_t>(time & 0xff);
397 }
398
399 exit:
400 return;
401 }
402 #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
403
otMacFrameProcessTxSfd(otRadioFrame * aFrame,uint64_t aRadioTime,otRadioContext * aRadioContext)404 otError otMacFrameProcessTxSfd(otRadioFrame *aFrame, uint64_t aRadioTime, otRadioContext *aRadioContext)
405 {
406 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
407 if (aRadioContext->mCslPeriod > 0) // CSL IE should be filled for every transmit attempt
408 {
409 otMacFrameSetCslIe(aFrame, aRadioContext->mCslPeriod, ComputeCslPhase(aRadioTime, aRadioContext));
410 }
411 #endif
412 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
413 otMacFrameUpdateTimeIe(aFrame, aRadioTime, aRadioContext);
414 #endif
415 aFrame->mInfo.mTxInfo.mTimestamp = aRadioTime;
416 return otMacFrameProcessTransmitSecurity(aFrame, aRadioContext);
417 }
418