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