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