1 /*
2 * Copyright (c) 2016-2018, 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 /**
30 * @file
31 * This file implements the OpenThread Link Raw API.
32 */
33
34 #include "openthread-core-config.h"
35
36 #if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE
37
38 #include <string.h>
39 #include <openthread/diag.h>
40 #include <openthread/platform/diag.h>
41
42 #include "common/debug.hpp"
43 #include "common/instance.hpp"
44 #include "common/locator_getters.hpp"
45 #include "common/log.hpp"
46 #include "common/random.hpp"
47 #include "mac/mac_frame.hpp"
48
49 namespace ot {
50 namespace Mac {
51
52 RegisterLogModule("LinkRaw");
53
LinkRaw(Instance & aInstance)54 LinkRaw::LinkRaw(Instance &aInstance)
55 : InstanceLocator(aInstance)
56 , mReceiveChannel(OPENTHREAD_CONFIG_DEFAULT_CHANNEL)
57 , mPanId(kPanIdBroadcast)
58 , mReceiveDoneCallback(nullptr)
59 , mTransmitDoneCallback(nullptr)
60 , mEnergyScanDoneCallback(nullptr)
61 #if OPENTHREAD_RADIO
62 , mSubMac(aInstance)
63 #elif OPENTHREAD_CONFIG_LINK_RAW_ENABLE
64 , mSubMac(aInstance.Get<SubMac>())
65 #endif
66 {
67 Init();
68 }
69
Init(void)70 void LinkRaw::Init(void)
71 {
72 mEnergyScanDoneCallback = nullptr;
73 mTransmitDoneCallback = nullptr;
74 mReceiveDoneCallback = nullptr;
75
76 mReceiveChannel = OPENTHREAD_CONFIG_DEFAULT_CHANNEL;
77 mPanId = kPanIdBroadcast;
78 mReceiveDoneCallback = nullptr;
79 #if OPENTHREAD_RADIO
80 mSubMac.Init();
81 #endif
82 }
83
SetReceiveDone(otLinkRawReceiveDone aCallback)84 Error LinkRaw::SetReceiveDone(otLinkRawReceiveDone aCallback)
85 {
86 Error error = kErrorNone;
87 bool enable = aCallback != nullptr;
88
89 LogDebg("Enabled(%s)", (enable ? "true" : "false"));
90
91 #if OPENTHREAD_MTD || OPENTHREAD_FTD
92 VerifyOrExit(!Get<ThreadNetif>().IsUp(), error = kErrorInvalidState);
93
94 // In MTD/FTD build, `Mac` has already enabled sub-mac. We ensure to
95 // disable/enable MAC layer when link-raw is being enabled/disabled to
96 // avoid any conflict in control of radio and sub-mac between `Mac` and
97 // `LinkRaw`. in RADIO build, we directly enable/disable sub-mac.
98
99 if (!enable)
100 {
101 // When disabling link-raw, make sure there is no ongoing
102 // transmit or scan operation. Otherwise Mac will attempt to
103 // handle an unexpected "done" callback.
104 VerifyOrExit(!mSubMac.IsTransmittingOrScanning(), error = kErrorBusy);
105 }
106
107 Get<Mac>().SetEnabled(!enable);
108 #else
109 if (enable)
110 {
111 SuccessOrExit(error = mSubMac.Enable());
112 }
113 else
114 {
115 IgnoreError(mSubMac.Disable());
116 }
117 #endif
118
119 mReceiveDoneCallback = aCallback;
120
121 exit:
122 return error;
123 }
124
SetPanId(uint16_t aPanId)125 Error LinkRaw::SetPanId(uint16_t aPanId)
126 {
127 Error error = kErrorNone;
128
129 VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
130 mSubMac.SetPanId(aPanId);
131 mPanId = aPanId;
132
133 exit:
134 return error;
135 }
136
SetChannel(uint8_t aChannel)137 Error LinkRaw::SetChannel(uint8_t aChannel)
138 {
139 Error error = kErrorNone;
140
141 VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
142 mReceiveChannel = aChannel;
143
144 exit:
145 return error;
146 }
147
SetExtAddress(const ExtAddress & aExtAddress)148 Error LinkRaw::SetExtAddress(const ExtAddress &aExtAddress)
149 {
150 Error error = kErrorNone;
151
152 VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
153 mSubMac.SetExtAddress(aExtAddress);
154
155 exit:
156 return error;
157 }
158
SetShortAddress(ShortAddress aShortAddress)159 Error LinkRaw::SetShortAddress(ShortAddress aShortAddress)
160 {
161 Error error = kErrorNone;
162
163 VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
164 mSubMac.SetShortAddress(aShortAddress);
165
166 exit:
167 return error;
168 }
169
Receive(void)170 Error LinkRaw::Receive(void)
171 {
172 Error error = kErrorNone;
173
174 VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
175
176 SuccessOrExit(error = mSubMac.Receive(mReceiveChannel));
177
178 exit:
179 return error;
180 }
181
InvokeReceiveDone(RxFrame * aFrame,Error aError)182 void LinkRaw::InvokeReceiveDone(RxFrame *aFrame, Error aError)
183 {
184 LogDebg("ReceiveDone(%d bytes), error:%s", (aFrame != nullptr) ? aFrame->mLength : 0, ErrorToString(aError));
185
186 if (mReceiveDoneCallback && (aError == kErrorNone))
187 {
188 mReceiveDoneCallback(&GetInstance(), aFrame, aError);
189 }
190 }
191
Transmit(otLinkRawTransmitDone aCallback)192 Error LinkRaw::Transmit(otLinkRawTransmitDone aCallback)
193 {
194 Error error = kErrorNone;
195
196 VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
197
198 SuccessOrExit(error = mSubMac.Send());
199 mTransmitDoneCallback = aCallback;
200
201 exit:
202 return error;
203 }
204
InvokeTransmitDone(TxFrame & aFrame,RxFrame * aAckFrame,Error aError)205 void LinkRaw::InvokeTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError)
206 {
207 LogDebg("TransmitDone(%d bytes), error:%s", aFrame.mLength, ErrorToString(aError));
208
209 if (mTransmitDoneCallback)
210 {
211 mTransmitDoneCallback(&GetInstance(), &aFrame, aAckFrame, aError);
212 mTransmitDoneCallback = nullptr;
213 }
214 }
215
EnergyScan(uint8_t aScanChannel,uint16_t aScanDuration,otLinkRawEnergyScanDone aCallback)216 Error LinkRaw::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration, otLinkRawEnergyScanDone aCallback)
217 {
218 Error error = kErrorNone;
219
220 VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
221
222 SuccessOrExit(error = mSubMac.EnergyScan(aScanChannel, aScanDuration));
223 mEnergyScanDoneCallback = aCallback;
224
225 exit:
226 return error;
227 }
228
InvokeEnergyScanDone(int8_t aEnergyScanMaxRssi)229 void LinkRaw::InvokeEnergyScanDone(int8_t aEnergyScanMaxRssi)
230 {
231 if (IsEnabled() && mEnergyScanDoneCallback != nullptr)
232 {
233 mEnergyScanDoneCallback(&GetInstance(), aEnergyScanMaxRssi);
234 mEnergyScanDoneCallback = nullptr;
235 }
236 }
237
SetMacKey(uint8_t aKeyIdMode,uint8_t aKeyId,const Key & aPrevKey,const Key & aCurrKey,const Key & aNextKey)238 Error LinkRaw::SetMacKey(uint8_t aKeyIdMode,
239 uint8_t aKeyId,
240 const Key &aPrevKey,
241 const Key &aCurrKey,
242 const Key &aNextKey)
243 {
244 Error error = kErrorNone;
245 KeyMaterial prevKey;
246 KeyMaterial currKey;
247 KeyMaterial nextKey;
248
249 VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
250
251 prevKey.SetFrom(aPrevKey);
252 currKey.SetFrom(aCurrKey);
253 nextKey.SetFrom(aNextKey);
254
255 mSubMac.SetMacKey(aKeyIdMode, aKeyId, prevKey, currKey, nextKey);
256
257 exit:
258 return error;
259 }
260
SetMacFrameCounter(uint32_t aFrameCounter,bool aSetIfLarger)261 Error LinkRaw::SetMacFrameCounter(uint32_t aFrameCounter, bool aSetIfLarger)
262 {
263 Error error = kErrorNone;
264
265 VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
266 mSubMac.SetFrameCounter(aFrameCounter, aSetIfLarger);
267
268 exit:
269 return error;
270 }
271
272 // LCOV_EXCL_START
273
274 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
275
RecordFrameTransmitStatus(const TxFrame & aFrame,RxFrame * aAckFrame,Error aError,uint8_t aRetryCount,bool aWillRetx)276 void LinkRaw::RecordFrameTransmitStatus(const TxFrame &aFrame,
277 RxFrame *aAckFrame,
278 Error aError,
279 uint8_t aRetryCount,
280 bool aWillRetx)
281 {
282 OT_UNUSED_VARIABLE(aAckFrame);
283 OT_UNUSED_VARIABLE(aWillRetx);
284
285 if (aError != kErrorNone)
286 {
287 LogInfo("Frame tx failed, error:%s, retries:%d/%d, %s", ErrorToString(aError), aRetryCount,
288 aFrame.GetMaxFrameRetries(), aFrame.ToInfoString().AsCString());
289 }
290 }
291
292 #endif
293
294 // LCOV_EXCL_STOP
295
296 } // namespace Mac
297 } // namespace ot
298
299 #endif // OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE
300