• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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