mirror of
https://github.com/espressif/openthread.git
synced 2026-08-13 06:07:48 +00:00
[mle] adding DeviceMode class (#4035)
This commit adds a `Mle::DeviceMode` class which is warpper over a device mode bitmask (`uint8_t`) and provides the common helper functions like `IsRxOnWhenIdle()`, `IsFullThreadDevice()`, etc.
This commit is contained in:
committed by
Jonathan Hui
parent
3d3315bf61
commit
0546a2f972
@@ -193,6 +193,7 @@ LOCAL_SRC_FILES := \
|
||||
src/core/thread/announce_begin_server.cpp \
|
||||
src/core/thread/announce_sender.cpp \
|
||||
src/core/thread/child_table.cpp \
|
||||
src/core/thread/device_mode.cpp \
|
||||
src/core/thread/energy_scan_server.cpp \
|
||||
src/core/thread/indirect_sender.cpp \
|
||||
src/core/thread/key_manager.cpp \
|
||||
|
||||
@@ -199,6 +199,7 @@ SOURCES_COMMON = \
|
||||
thread/announce_begin_server.cpp \
|
||||
thread/announce_sender.cpp \
|
||||
thread/child_table.cpp \
|
||||
thread/device_mode.cpp \
|
||||
thread/energy_scan_server.cpp \
|
||||
thread/indirect_sender.cpp \
|
||||
thread/key_manager.cpp \
|
||||
@@ -371,6 +372,7 @@ HEADERS_COMMON = \
|
||||
thread/announce_begin_server.hpp \
|
||||
thread/announce_sender.hpp \
|
||||
thread/child_table.hpp \
|
||||
thread/device_mode.hpp \
|
||||
thread/energy_scan_server.hpp \
|
||||
thread/indirect_sender.hpp \
|
||||
thread/key_manager.hpp \
|
||||
|
||||
@@ -103,59 +103,17 @@ otLinkModeConfig otThreadGetLinkMode(otInstance *aInstance)
|
||||
{
|
||||
otLinkModeConfig config;
|
||||
Instance & instance = *static_cast<Instance *>(aInstance);
|
||||
uint8_t mode = instance.Get<Mle::MleRouter>().GetDeviceMode();
|
||||
|
||||
memset(&config, 0, sizeof(otLinkModeConfig));
|
||||
|
||||
if (mode & Mle::ModeTlv::kModeRxOnWhenIdle)
|
||||
{
|
||||
config.mRxOnWhenIdle = 1;
|
||||
}
|
||||
|
||||
if (mode & Mle::ModeTlv::kModeSecureDataRequest)
|
||||
{
|
||||
config.mSecureDataRequests = 1;
|
||||
}
|
||||
|
||||
if (mode & Mle::ModeTlv::kModeFullThreadDevice)
|
||||
{
|
||||
config.mDeviceType = 1;
|
||||
}
|
||||
|
||||
if (mode & Mle::ModeTlv::kModeFullNetworkData)
|
||||
{
|
||||
config.mNetworkData = 1;
|
||||
}
|
||||
instance.Get<Mle::MleRouter>().GetDeviceMode().Get(config);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
otError otThreadSetLinkMode(otInstance *aInstance, otLinkModeConfig aConfig)
|
||||
{
|
||||
uint8_t mode = 0;
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
if (aConfig.mRxOnWhenIdle)
|
||||
{
|
||||
mode |= Mle::ModeTlv::kModeRxOnWhenIdle;
|
||||
}
|
||||
|
||||
if (aConfig.mSecureDataRequests)
|
||||
{
|
||||
mode |= Mle::ModeTlv::kModeSecureDataRequest;
|
||||
}
|
||||
|
||||
if (aConfig.mDeviceType)
|
||||
{
|
||||
mode |= Mle::ModeTlv::kModeFullThreadDevice;
|
||||
}
|
||||
|
||||
if (aConfig.mNetworkData)
|
||||
{
|
||||
mode |= Mle::ModeTlv::kModeFullNetworkData;
|
||||
}
|
||||
|
||||
return instance.Get<Mle::MleRouter>().SetDeviceMode(mode);
|
||||
return instance.Get<Mle::MleRouter>().SetDeviceMode(Mle::DeviceMode(aConfig));
|
||||
}
|
||||
|
||||
const otMasterKey *otThreadGetMasterKey(otInstance *aInstance)
|
||||
|
||||
@@ -138,7 +138,7 @@ void AnnounceSender::CheckState(void)
|
||||
break;
|
||||
|
||||
case OT_DEVICE_ROLE_CHILD:
|
||||
if (mle.IsRouterRoleEnabled() && (mle.GetDeviceMode() & Mle::ModeTlv::kModeRxOnWhenIdle))
|
||||
if (mle.IsRouterRoleEnabled() && mle.IsRxOnWhenIdle())
|
||||
{
|
||||
period = kReedTxInterval;
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements of MLE device mode.
|
||||
*/
|
||||
|
||||
#include "device_mode.hpp"
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Mle {
|
||||
|
||||
void DeviceMode::Get(ModeConfig &aModeConfig) const
|
||||
{
|
||||
aModeConfig.mRxOnWhenIdle = IsRxOnWhenIdle();
|
||||
aModeConfig.mSecureDataRequests = IsSecureDataRequest();
|
||||
aModeConfig.mDeviceType = IsFullThreadDevice();
|
||||
aModeConfig.mNetworkData = IsFullNetworkData();
|
||||
}
|
||||
|
||||
void DeviceMode::Set(const ModeConfig &aModeConfig)
|
||||
{
|
||||
mMode = 0;
|
||||
mMode |= aModeConfig.mRxOnWhenIdle ? kModeRxOnWhenIdle : 0;
|
||||
mMode |= aModeConfig.mSecureDataRequests ? kModeSecureDataRequest : 0;
|
||||
mMode |= aModeConfig.mDeviceType ? kModeFullThreadDevice : 0;
|
||||
mMode |= aModeConfig.mNetworkData ? kModeFullNetworkData : 0;
|
||||
}
|
||||
|
||||
DeviceMode::InfoString DeviceMode::ToString(void) const
|
||||
{
|
||||
return InfoString("rx-on:%s sec-poll:%s ftd:%s full-net:%s", IsRxOnWhenIdle() ? "yes" : "no",
|
||||
IsSecureDataRequest() ? "yes" : "no", IsFullThreadDevice() ? "yes" : "no",
|
||||
IsFullNetworkData() ? "yes" : "no");
|
||||
}
|
||||
|
||||
} // namespace Mle
|
||||
} // namespace ot
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for MLE device mode.
|
||||
*/
|
||||
|
||||
#ifndef DEVICE_MODE_HPP_
|
||||
#define DEVICE_MODE_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include <openthread/thread.h>
|
||||
|
||||
#include "common/string.hpp"
|
||||
#include "utils/wrap_stdint.h"
|
||||
|
||||
namespace ot {
|
||||
namespace Mle {
|
||||
|
||||
/**
|
||||
* @addtogroup core-mle-core
|
||||
*
|
||||
* @brief
|
||||
* This module includes definition for MLE device mode.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This type represents a MLE device mode.
|
||||
*
|
||||
*/
|
||||
class DeviceMode
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kModeRxOnWhenIdle = 1 << 3, ///< If the device has its receiver on when not transmitting.
|
||||
kModeSecureDataRequest = 1 << 2, ///< If the device uses link layer security for all data requests.
|
||||
kModeFullThreadDevice = 1 << 1, ///< If the device is an FTD.
|
||||
kModeFullNetworkData = 1 << 0, ///< If the device requires the full Network Data.
|
||||
|
||||
kInfoStringSize = 45, ///< String buffer size used for `ToString()`.
|
||||
};
|
||||
|
||||
/**
|
||||
* This type defines the fixed-length `String` object returned from `ToString()`.
|
||||
*
|
||||
*/
|
||||
typedef String<kInfoStringSize> InfoString;
|
||||
|
||||
/**
|
||||
* This structure represents an MLE Mode configuration.
|
||||
*
|
||||
*/
|
||||
typedef otLinkModeConfig ModeConfig;
|
||||
|
||||
/**
|
||||
* This is the default constructor for `DeviceMode` object.
|
||||
*
|
||||
*/
|
||||
DeviceMode(void) {}
|
||||
|
||||
/**
|
||||
* This constructor initializes a `DeviceMode` object from a given mode TLV bitmask.
|
||||
*
|
||||
* @param[in] aMode A mode TLV bitmask to initialize the `DeviceMode` object.
|
||||
*
|
||||
*/
|
||||
explicit DeviceMode(uint8_t aMode)
|
||||
: mMode(aMode)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor initializes a `DeviceMode` object from a given mode configuration structure.
|
||||
*
|
||||
* @param[in] aModeConfig A mode configuration to initialize the `DeviceMode` object.
|
||||
*
|
||||
*/
|
||||
explicit DeviceMode(ModeConfig aModeConfig) { Set(aModeConfig); }
|
||||
|
||||
/**
|
||||
* This method gets the device mode as a mode TLV bitmask.
|
||||
*
|
||||
* @returns The device mode as a mode TLV bitmask.
|
||||
*
|
||||
*/
|
||||
uint8_t Get(void) const { return mMode; }
|
||||
|
||||
/**
|
||||
* This method sets the device mode from a given mode TLV bitmask.
|
||||
*
|
||||
* @param[in] aMode A mode TLV bitmask.
|
||||
*
|
||||
*/
|
||||
void Set(uint8_t aMode) { mMode = aMode; }
|
||||
|
||||
/**
|
||||
* This method gets the device mode as a mode configuration structure.
|
||||
*
|
||||
* @param[out] aModeConfig A reference to a mode configuration structure to output the device mode.
|
||||
*
|
||||
*/
|
||||
void Get(ModeConfig &aModeConfig) const;
|
||||
|
||||
/**
|
||||
* this method sets the device mode from a given mode configuration structure.
|
||||
*
|
||||
* @param[in] aModeConfig A mode configuration structure.
|
||||
*
|
||||
*/
|
||||
void Set(const ModeConfig &aModeConfig);
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device is rx-on-when-idle.
|
||||
*
|
||||
* @retval TRUE If the device is rx-on-when-idle (non-sleepy).
|
||||
* @retval FALSE If the device is not rx-on-when-idle (sleepy).
|
||||
*
|
||||
*/
|
||||
bool IsRxOnWhenIdle(void) const { return (mMode & kModeRxOnWhenIdle) != 0; }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device uses secure IEEE 802.15.4 Data Request messages.
|
||||
*
|
||||
* @retval TRUE If the device uses secure IEEE 802.15.4 Data Request (data poll) messages.
|
||||
* @retval FALSE If the device uses any IEEE 802.15.4 Data Request (data poll) messages.
|
||||
*
|
||||
*/
|
||||
bool IsSecureDataRequest(void) const { return (mMode & kModeSecureDataRequest) != 0; }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device is a Full Thread Device.
|
||||
*
|
||||
* @retval TRUE If the device is Full Thread Device.
|
||||
* @retval FALSE If the device if not Full Thread Device.
|
||||
*
|
||||
*/
|
||||
bool IsFullThreadDevice(void) const { return (mMode & kModeFullThreadDevice) != 0; }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device requests Full Network Data.
|
||||
*
|
||||
* @retval TRUE If the device requests Full Network Data.
|
||||
* @retval FALSE If the device does not request Full Network Data (only stable Network Data).
|
||||
*
|
||||
*/
|
||||
bool IsFullNetworkData(void) const { return (mMode & kModeFullNetworkData) != 0; }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device is a Minimal End Device.
|
||||
*
|
||||
* @retval TRUE If the device is a Minimal End Device.
|
||||
* @retval FALSE If the device is not a Minimal End Device.
|
||||
*
|
||||
*/
|
||||
bool IsMinimalEndDevice(void) const
|
||||
{
|
||||
return (mMode & (kModeFullThreadDevice | kModeRxOnWhenIdle)) != (kModeFullThreadDevice | kModeRxOnWhenIdle);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device mode flags are valid.
|
||||
*
|
||||
* An FTD which is not rx-on-when-idle (is sleepy) is considered invalid.
|
||||
*
|
||||
* @returns TRUE if , FALSE otherwise.
|
||||
* @retval TRUE If the device mode flags are valid.
|
||||
* @retval FALSE If the device mode flags are not valid.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const { return !IsFullThreadDevice() || IsRxOnWhenIdle(); }
|
||||
|
||||
/**
|
||||
* This method overloads operator `==` to evaluate whether or not two device modes are equal
|
||||
*
|
||||
* @param[in] aOther The other device mode to compare with.
|
||||
*
|
||||
* @retval TRUE If the device modes are equal.
|
||||
* @retval FALSE If the device modes are not equal.
|
||||
*
|
||||
*/
|
||||
bool operator==(const DeviceMode &aOther) const { return (mMode == aOther.mMode); }
|
||||
|
||||
/**
|
||||
* This method overloads operator `!=` to evaluate whether or not two device modes are not equal.
|
||||
*
|
||||
* @param[in] aOther The other device mode to compare with.
|
||||
*
|
||||
* @retval TRUE If the device modes are not equal.
|
||||
* @retval FALSE If the device modes are equal.
|
||||
*
|
||||
*/
|
||||
bool operator!=(const DeviceMode &aOther) const { return (mMode != aOther.mMode); }
|
||||
|
||||
/**
|
||||
* This method converts the device mode into a human-readable string.
|
||||
*
|
||||
* @returns An `InfoString` object representing the device mode.
|
||||
*
|
||||
*/
|
||||
InfoString ToString(void) const;
|
||||
|
||||
private:
|
||||
uint8_t mMode;
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
} // namespace Mle
|
||||
} // namespace ot
|
||||
|
||||
#endif // DEVICE_MODE_HPP_
|
||||
@@ -164,10 +164,8 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void IndirectSender::HandleChildModeChange(Child &aChild, uint8_t aOldMode)
|
||||
void IndirectSender::HandleChildModeChange(Child &aChild, Mle::DeviceMode aOldMode)
|
||||
{
|
||||
bool wasRxOnWhenIdle = ((aOldMode & Mle::ModeTlv::kModeRxOnWhenIdle) != 0);
|
||||
|
||||
if (!aChild.IsRxOnWhenIdle() && (aChild.GetState() == Neighbor::kStateValid))
|
||||
{
|
||||
SetChildUseShortAddress(aChild, true);
|
||||
@@ -176,7 +174,7 @@ void IndirectSender::HandleChildModeChange(Child &aChild, uint8_t aOldMode)
|
||||
// On sleepy to non-sleepy mode change, convert indirect messages in
|
||||
// the send queue destined to the child to direct.
|
||||
|
||||
if (!wasRxOnWhenIdle && aChild.IsRxOnWhenIdle() && (aChild.GetIndirectMessageCount() > 0))
|
||||
if (!aOldMode.IsRxOnWhenIdle() && aChild.IsRxOnWhenIdle() && (aChild.GetIndirectMessageCount() > 0))
|
||||
{
|
||||
uint8_t childIndex = Get<ChildTable>().GetChildIndex(aChild);
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "common/message.hpp"
|
||||
#include "mac/data_poll_handler.hpp"
|
||||
#include "mac/mac_frame.hpp"
|
||||
#include "thread/device_mode.hpp"
|
||||
#include "thread/src_match_controller.hpp"
|
||||
|
||||
namespace ot {
|
||||
@@ -193,7 +194,7 @@ public:
|
||||
* @param[in] aOldMode The old device mode of the child.
|
||||
*
|
||||
*/
|
||||
void HandleChildModeChange(Child &aChild, uint8_t aOldMode);
|
||||
void HandleChildModeChange(Child &aChild, Mle::DeviceMode aOldMode);
|
||||
|
||||
private:
|
||||
enum
|
||||
|
||||
+15
-21
@@ -65,7 +65,7 @@ Mle::Mle(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mRetrieveNewNetworkData(false)
|
||||
, mRole(OT_DEVICE_ROLE_DISABLED)
|
||||
, mDeviceMode(ModeTlv::kModeRxOnWhenIdle | ModeTlv::kModeSecureDataRequest)
|
||||
, mDeviceMode(DeviceMode::kModeRxOnWhenIdle | DeviceMode::kModeSecureDataRequest)
|
||||
, mAttachState(kAttachStateIdle)
|
||||
, mReattachState(kReattachStop)
|
||||
, mAttachCounter(0)
|
||||
@@ -380,7 +380,7 @@ otError Mle::Restore(void)
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
mDeviceMode = networkInfo.mDeviceMode;
|
||||
mDeviceMode.Set(networkInfo.mDeviceMode);
|
||||
Get<Mac::Mac>().SetShortAddress(networkInfo.mRloc16);
|
||||
Get<Mac::Mac>().SetExtAddress(networkInfo.mExtAddress);
|
||||
|
||||
@@ -411,8 +411,8 @@ otError Mle::Restore(void)
|
||||
|
||||
memset(&mParent, 0, sizeof(mParent));
|
||||
mParent.SetExtAddress(*static_cast<Mac::ExtAddress *>(&parentInfo.mExtAddress));
|
||||
mParent.SetDeviceMode(ModeTlv::kModeFullThreadDevice | ModeTlv::kModeRxOnWhenIdle |
|
||||
ModeTlv::kModeFullNetworkData | ModeTlv::kModeSecureDataRequest);
|
||||
mParent.SetDeviceMode(DeviceMode(DeviceMode::kModeFullThreadDevice | DeviceMode::kModeRxOnWhenIdle |
|
||||
DeviceMode::kModeFullNetworkData | DeviceMode::kModeSecureDataRequest));
|
||||
mParent.SetRloc16(GetRloc16(GetRouterId(networkInfo.mRloc16)));
|
||||
mParent.SetState(Neighbor::kStateRestored);
|
||||
|
||||
@@ -444,7 +444,7 @@ otError Mle::Store(void)
|
||||
// avoid losing/overwriting previous information when a reboot
|
||||
// occurs after a message is sent but before attaching.
|
||||
|
||||
networkInfo.mDeviceMode = mDeviceMode;
|
||||
networkInfo.mDeviceMode = mDeviceMode.Get();
|
||||
networkInfo.mRole = mRole;
|
||||
networkInfo.mRloc16 = GetRloc16();
|
||||
networkInfo.mPreviousPartitionId = mLeaderData.GetPartitionId();
|
||||
@@ -817,23 +817,17 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
otError Mle::SetDeviceMode(uint8_t aDeviceMode)
|
||||
otError Mle::SetDeviceMode(DeviceMode aDeviceMode)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint8_t oldMode = mDeviceMode;
|
||||
otError error = OT_ERROR_NONE;
|
||||
DeviceMode oldMode = mDeviceMode;
|
||||
|
||||
VerifyOrExit((aDeviceMode & ModeTlv::kModeFullThreadDevice) == 0 || (aDeviceMode & ModeTlv::kModeRxOnWhenIdle) != 0,
|
||||
error = OT_ERROR_INVALID_ARGS);
|
||||
VerifyOrExit(aDeviceMode.IsValid(), error = OT_ERROR_INVALID_ARGS);
|
||||
VerifyOrExit(mDeviceMode != aDeviceMode);
|
||||
|
||||
otLogNoteMle("Mode 0x%02x -> 0x%02x [rx-on:%s, sec-data-req:%s, ftd:%s, full-netdata:%s]", mDeviceMode, aDeviceMode,
|
||||
(aDeviceMode & ModeTlv::kModeRxOnWhenIdle) ? "yes" : " no",
|
||||
(aDeviceMode & ModeTlv::kModeSecureDataRequest) ? "yes" : " no",
|
||||
(aDeviceMode & ModeTlv::kModeFullThreadDevice) ? "yes" : "no",
|
||||
(aDeviceMode & ModeTlv::kModeFullNetworkData) ? "yes" : "no");
|
||||
|
||||
mDeviceMode = aDeviceMode;
|
||||
|
||||
otLogNoteMle("Mode 0x%02x -> 0x%02x [%s]", oldMode.Get(), mDeviceMode.Get(), mDeviceMode.ToString().AsCString());
|
||||
|
||||
switch (mRole)
|
||||
{
|
||||
case OT_DEVICE_ROLE_DISABLED:
|
||||
@@ -852,7 +846,7 @@ otError Mle::SetDeviceMode(uint8_t aDeviceMode)
|
||||
|
||||
case OT_DEVICE_ROLE_ROUTER:
|
||||
case OT_DEVICE_ROLE_LEADER:
|
||||
if ((oldMode & ModeTlv::kModeFullThreadDevice) != 0 && (aDeviceMode & ModeTlv::kModeFullThreadDevice) == 0)
|
||||
if (oldMode.IsFullThreadDevice() && !mDeviceMode.IsFullThreadDevice())
|
||||
{
|
||||
BecomeDetached();
|
||||
}
|
||||
@@ -1151,7 +1145,7 @@ otError Mle::AppendStatus(Message &aMessage, StatusTlv::Status aStatus)
|
||||
return aMessage.AppendTlv(tlv);
|
||||
}
|
||||
|
||||
otError Mle::AppendMode(Message &aMessage, uint8_t aMode)
|
||||
otError Mle::AppendMode(Message &aMessage, DeviceMode aMode)
|
||||
{
|
||||
ModeTlv tlv;
|
||||
|
||||
@@ -3355,8 +3349,8 @@ otError Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInf
|
||||
mParentCandidate.SetRloc16(sourceAddress.GetRloc16());
|
||||
mParentCandidate.SetLinkFrameCounter(linkFrameCounter.GetFrameCounter());
|
||||
mParentCandidate.SetMleFrameCounter(mleFrameCounter.GetFrameCounter());
|
||||
mParentCandidate.SetDeviceMode(ModeTlv::kModeFullThreadDevice | ModeTlv::kModeRxOnWhenIdle |
|
||||
ModeTlv::kModeFullNetworkData | ModeTlv::kModeSecureDataRequest);
|
||||
mParentCandidate.SetDeviceMode(DeviceMode(DeviceMode::kModeFullThreadDevice | DeviceMode::kModeRxOnWhenIdle |
|
||||
DeviceMode::kModeFullNetworkData | DeviceMode::kModeSecureDataRequest));
|
||||
mParentCandidate.GetLinkInfo().Clear();
|
||||
mParentCandidate.GetLinkInfo().AddRss(Get<Mac::Mac>().GetNoiseFloor(), linkInfo->mRss);
|
||||
mParentCandidate.ResetLinkFailures();
|
||||
|
||||
+11
-14
@@ -42,6 +42,7 @@
|
||||
#include "mac/mac.hpp"
|
||||
#include "meshcop/joiner_router.hpp"
|
||||
#include "net/udp6.hpp"
|
||||
#include "thread/device_mode.hpp"
|
||||
#include "thread/mle_constants.hpp"
|
||||
#include "thread/mle_tlvs.hpp"
|
||||
#include "thread/topology.hpp"
|
||||
@@ -631,7 +632,7 @@ public:
|
||||
* @returns The Device Mode as reported in the Mode TLV.
|
||||
*
|
||||
*/
|
||||
uint8_t GetDeviceMode(void) const { return mDeviceMode; }
|
||||
DeviceMode GetDeviceMode(void) const { return mDeviceMode; }
|
||||
|
||||
/**
|
||||
* This method sets the Device Mode as reported in the Mode TLV.
|
||||
@@ -642,7 +643,7 @@ public:
|
||||
* @retval OT_ERROR_INVALID_ARGS The mode combination specified in @p aMode is invalid.
|
||||
*
|
||||
*/
|
||||
otError SetDeviceMode(uint8_t aDeviceMode);
|
||||
otError SetDeviceMode(DeviceMode aDeviceMode);
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device is rx-on-when-idle.
|
||||
@@ -650,7 +651,7 @@ public:
|
||||
* @returns TRUE if rx-on-when-idle, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsRxOnWhenIdle(void) const { return (mDeviceMode & ModeTlv::kModeRxOnWhenIdle) != 0; }
|
||||
bool IsRxOnWhenIdle(void) const { return mDeviceMode.IsRxOnWhenIdle(); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device is a Full Thread Device.
|
||||
@@ -658,7 +659,7 @@ public:
|
||||
* @returns TRUE if a Full Thread Device, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsFullThreadDevice(void) const { return (mDeviceMode & ModeTlv::kModeFullThreadDevice) != 0; }
|
||||
bool IsFullThreadDevice(void) const { return mDeviceMode.IsFullThreadDevice(); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device uses secure IEEE 802.15.4 Data Request messages.
|
||||
@@ -666,7 +667,7 @@ public:
|
||||
* @returns TRUE if using secure IEEE 802.15.4 Data Request messages, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsSecureDataRequest(void) const { return (mDeviceMode & ModeTlv::kModeSecureDataRequest) != 0; }
|
||||
bool IsSecureDataRequest(void) const { return mDeviceMode.IsSecureDataRequest(); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device requests Full Network Data.
|
||||
@@ -674,7 +675,7 @@ public:
|
||||
* @returns TRUE if requests Full Network Data, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsFullNetworkData(void) const { return (mDeviceMode & ModeTlv::kModeFullNetworkData) != 0; }
|
||||
bool IsFullNetworkData(void) const { return mDeviceMode.IsFullNetworkData(); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device is a Minimal End Device.
|
||||
@@ -682,11 +683,7 @@ public:
|
||||
* @returns TRUE if the device is a Minimal End Device, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsMinimalEndDevice(void) const
|
||||
{
|
||||
return (mDeviceMode & (ModeTlv::kModeFullThreadDevice | ModeTlv::kModeRxOnWhenIdle)) !=
|
||||
(ModeTlv::kModeFullThreadDevice | ModeTlv::kModeRxOnWhenIdle);
|
||||
}
|
||||
bool IsMinimalEndDevice(void) const { return mDeviceMode.IsMinimalEndDevice(); }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the Mesh Local Prefix.
|
||||
@@ -1177,13 +1174,13 @@ protected:
|
||||
* This method appends a Mode TLV to a message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
* @param[in] aMode The Device Mode value.
|
||||
* @param[in] aMode The Device Mode.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully appended the Mode TLV.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffers available to append the Mode TLV.
|
||||
*
|
||||
*/
|
||||
otError AppendMode(Message &aMessage, uint8_t aMode);
|
||||
otError AppendMode(Message &aMessage, DeviceMode aMode);
|
||||
|
||||
/**
|
||||
* This method appends a Timeout TLV to a message.
|
||||
@@ -1643,7 +1640,7 @@ protected:
|
||||
bool mRetrieveNewNetworkData; ///< Indicating new Network Data is needed if set.
|
||||
otDeviceRole mRole; ///< Current Thread role.
|
||||
Router mParent; ///< Parent information.
|
||||
uint8_t mDeviceMode; ///< Device mode setting.
|
||||
DeviceMode mDeviceMode; ///< Device mode setting.
|
||||
AttachState mAttachState; ///< The parent request state.
|
||||
ReattachState mReattachState; ///< Reattach state
|
||||
uint16_t mAttachCounter; ///< Attach attempt counter.
|
||||
|
||||
@@ -81,7 +81,7 @@ MleRouter::MleRouter(Instance &aInstance)
|
||||
, mRouterSelectionJitterTimeout(0)
|
||||
, mParentPriority(kParentPriorityUnspecified)
|
||||
{
|
||||
mDeviceMode |= ModeTlv::kModeFullThreadDevice | ModeTlv::kModeFullNetworkData;
|
||||
mDeviceMode.Set(mDeviceMode.Get() | DeviceMode::kModeFullThreadDevice | DeviceMode::kModeFullNetworkData);
|
||||
|
||||
SetRouterId(kInvalidRouterId);
|
||||
}
|
||||
@@ -974,7 +974,8 @@ otError MleRouter::HandleLinkAccept(const Message & aMessage,
|
||||
router->SetLinkFrameCounter(linkFrameCounter.GetFrameCounter());
|
||||
router->SetMleFrameCounter(mleFrameCounter.GetFrameCounter());
|
||||
router->SetLastHeard(TimerMilli::GetNow());
|
||||
router->SetDeviceMode(ModeTlv::kModeFullThreadDevice | ModeTlv::kModeRxOnWhenIdle | ModeTlv::kModeFullNetworkData);
|
||||
router->SetDeviceMode(DeviceMode(DeviceMode::kModeFullThreadDevice | DeviceMode::kModeRxOnWhenIdle |
|
||||
DeviceMode::kModeFullNetworkData));
|
||||
router->GetLinkInfo().Clear();
|
||||
router->GetLinkInfo().AddRss(Get<Mac::Mac>().GetNoiseFloor(), linkInfo->mRss);
|
||||
router->SetLinkQualityOut(LinkQualityInfo::ConvertLinkMarginToLinkQuality(linkMargin.GetLinkMargin()));
|
||||
@@ -2134,7 +2135,7 @@ otError MleRouter::HandleChildIdRequest(const Message & aMessage,
|
||||
VerifyOrExit(pendingTimestamp.IsValid(), error = OT_ERROR_PARSE);
|
||||
}
|
||||
|
||||
if ((mode.GetMode() & ModeTlv::kModeFullThreadDevice) == 0)
|
||||
if (!mode.GetMode().IsFullThreadDevice())
|
||||
{
|
||||
SuccessOrExit(error = Tlv::GetOffset(aMessage, Tlv::kAddressRegistration, addressRegistrationOffset));
|
||||
SuccessOrExit(error = UpdateChildAddresses(aMessage, addressRegistrationOffset, *child));
|
||||
@@ -2164,7 +2165,7 @@ otError MleRouter::HandleChildIdRequest(const Message & aMessage,
|
||||
child->GetLinkInfo().AddRss(Get<Mac::Mac>().GetNoiseFloor(), linkInfo->mRss);
|
||||
child->SetTimeout(timeout.GetTimeout());
|
||||
|
||||
if (mode.GetMode() & ModeTlv::kModeFullNetworkData)
|
||||
if (mode.GetMode().IsFullNetworkData())
|
||||
{
|
||||
child->SetNetworkDataVersion(mLeaderData.GetDataVersion());
|
||||
}
|
||||
@@ -2225,7 +2226,7 @@ otError MleRouter::HandleChildUpdateRequest(const Message & aMessage,
|
||||
LeaderDataTlv leaderData;
|
||||
TimeoutTlv timeout;
|
||||
Child * child;
|
||||
uint8_t oldMode;
|
||||
DeviceMode oldMode;
|
||||
TlvRequestTlv tlvRequest;
|
||||
uint8_t tlvs[kMaxResponseTlvs];
|
||||
uint8_t tlvslength = 0;
|
||||
@@ -2249,7 +2250,7 @@ otError MleRouter::HandleChildUpdateRequest(const Message & aMessage,
|
||||
if (child == NULL || child->GetState() == Neighbor::kStateInvalid)
|
||||
{
|
||||
// For invalid non-sleepy child, Send Child Update Response with status TLV (error)
|
||||
if (mode.GetMode() & ModeTlv::kModeRxOnWhenIdle)
|
||||
if (mode.GetMode().IsRxOnWhenIdle())
|
||||
{
|
||||
tlvs[tlvslength++] = Tlv::kStatus;
|
||||
SendChildUpdateResponse(NULL, aMessageInfo, tlvs, tlvslength, NULL);
|
||||
@@ -2325,12 +2326,8 @@ otError MleRouter::HandleChildUpdateRequest(const Message & aMessage,
|
||||
|
||||
if (oldMode != child->GetDeviceMode())
|
||||
{
|
||||
otLogNoteMle("Child 0x%04x mode change 0x%02x -> 0x%02x [rx-on:%s, sec-data-req:%s, ftd:%s, full-netdata:%s]",
|
||||
child->GetRloc16(), oldMode, mode.GetMode(),
|
||||
(mode.GetMode() & ModeTlv::kModeRxOnWhenIdle) ? "yes" : "no",
|
||||
(mode.GetMode() & ModeTlv::kModeSecureDataRequest) ? "yes" : "no",
|
||||
(mode.GetMode() & ModeTlv::kModeFullThreadDevice) ? "yes" : "no",
|
||||
(mode.GetMode() & ModeTlv::kModeFullNetworkData) ? "yes" : "no");
|
||||
otLogNoteMle("Child 0x%04x mode change 0x%02x -> 0x%02x [%s]", child->GetRloc16(), oldMode.Get(),
|
||||
child->GetDeviceMode().Get(), child->GetDeviceMode().ToString().AsCString());
|
||||
|
||||
childDidChange = true;
|
||||
|
||||
@@ -3156,7 +3153,7 @@ void MleRouter::RemoveNeighbor(Neighbor &aNeighbor)
|
||||
Get<IndirectSender>().ClearAllMessagesForSleepyChild(static_cast<Child &>(aNeighbor));
|
||||
Get<NetworkData::Leader>().SendServerDataNotification(aNeighbor.GetRloc16());
|
||||
|
||||
if (aNeighbor.GetDeviceMode() & ModeTlv::kModeFullThreadDevice)
|
||||
if (aNeighbor.IsFullThreadDevice())
|
||||
{
|
||||
// Clear all EID-to-RLOC entries associated with the child.
|
||||
Get<AddressResolver>().Remove(aNeighbor.GetRloc16());
|
||||
@@ -3524,7 +3521,7 @@ void MleRouter::RestoreChildren(void)
|
||||
child->GetLinkInfo().Clear();
|
||||
child->SetRloc16(childInfo.mRloc16);
|
||||
child->SetTimeout(childInfo.mTimeout);
|
||||
child->SetDeviceMode(childInfo.mMode);
|
||||
child->SetDeviceMode(DeviceMode(childInfo.mMode));
|
||||
child->SetState(Neighbor::kStateRestored);
|
||||
child->SetLastHeard(TimerMilli::GetNow());
|
||||
Get<IndirectSender>().SetChildUseShortAddress(*child, true);
|
||||
@@ -3572,7 +3569,7 @@ otError MleRouter::StoreChild(const Child &aChild)
|
||||
childInfo.mExtAddress = aChild.GetExtAddress();
|
||||
childInfo.mTimeout = aChild.GetTimeout();
|
||||
childInfo.mRloc16 = aChild.GetRloc16();
|
||||
childInfo.mMode = aChild.GetDeviceMode();
|
||||
childInfo.mMode = aChild.GetDeviceMode().Get();
|
||||
|
||||
return Get<Settings>().AddChildInfo(childInfo);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "common/tlvs.hpp"
|
||||
#include "meshcop/timestamp.hpp"
|
||||
#include "net/ip6_address.hpp"
|
||||
#include "thread/device_mode.hpp"
|
||||
#include "thread/mle_constants.hpp"
|
||||
|
||||
namespace ot {
|
||||
@@ -245,21 +246,13 @@ public:
|
||||
*/
|
||||
bool IsValid(void) const { return GetLength() >= sizeof(*this) - sizeof(Tlv); }
|
||||
|
||||
enum
|
||||
{
|
||||
kModeRxOnWhenIdle = 1 << 3,
|
||||
kModeSecureDataRequest = 1 << 2,
|
||||
kModeFullThreadDevice = 1 << 1,
|
||||
kModeFullNetworkData = 1 << 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* This method returns the Mode value.
|
||||
*
|
||||
* @returns The Mode value.
|
||||
*
|
||||
*/
|
||||
uint8_t GetMode(void) const { return mMode; }
|
||||
DeviceMode GetMode(void) const { return DeviceMode(mMode); }
|
||||
|
||||
/**
|
||||
* This method sets the Mode value.
|
||||
@@ -267,7 +260,7 @@ public:
|
||||
* @param[in] aMode The Mode value.
|
||||
*
|
||||
*/
|
||||
void SetMode(uint8_t aMode) { mMode = aMode; }
|
||||
void SetMode(DeviceMode aMode) { mMode = aMode.Get(); }
|
||||
|
||||
private:
|
||||
uint8_t mMode;
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "meshcop/meshcop_tlvs.hpp"
|
||||
#include "net/ip6_address.hpp"
|
||||
#include "phy/phy.hpp"
|
||||
#include "thread/device_mode.hpp"
|
||||
#include "thread/mle_constants.hpp"
|
||||
|
||||
namespace ot {
|
||||
@@ -275,29 +276,21 @@ public:
|
||||
*/
|
||||
bool IsValid(void) const { return GetLength() >= sizeof(*this) - sizeof(NetworkDiagnosticTlv); }
|
||||
|
||||
enum
|
||||
{
|
||||
kModeRxOnWhenIdle = 1 << 3,
|
||||
kModeSecureDataRequest = 1 << 2,
|
||||
kModeFullThreadDevice = 1 << 1,
|
||||
kModeFullNetworkData = 1 << 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* This method returns the Mode value.
|
||||
* This method returns the Device Mode.
|
||||
*
|
||||
* @returns The Mode value.
|
||||
* @returns The Device Mode.
|
||||
*
|
||||
*/
|
||||
uint8_t GetMode(void) const { return mMode; }
|
||||
Mle::DeviceMode GetMode(void) const { return Mle::DeviceMode(mMode); }
|
||||
|
||||
/**
|
||||
* This method sets the Mode value.
|
||||
* This method sets the Device Mode
|
||||
*
|
||||
* @param[in] aMode The Mode value.
|
||||
* @param[in] aMode The Device Mode
|
||||
*
|
||||
*/
|
||||
void SetMode(uint8_t aMode) { mMode = aMode; }
|
||||
void SetMode(Mle::DeviceMode aMode) { mMode = aMode.Get(); }
|
||||
|
||||
private:
|
||||
uint8_t mMode;
|
||||
@@ -1255,20 +1248,20 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the Mode value.
|
||||
* This method returns the Device Mode
|
||||
*
|
||||
* @returns The Mode value.
|
||||
* @returns The Device Mode
|
||||
*
|
||||
*/
|
||||
uint8_t GetMode(void) const { return mMode; }
|
||||
Mle::DeviceMode GetMode(void) const { return Mle::DeviceMode(mMode); }
|
||||
|
||||
/**
|
||||
* This method sets the Mode value.
|
||||
* This method sets the Device Mode.
|
||||
*
|
||||
* @param[in] aMode The Mode value.
|
||||
* @param[in] aMode The Device Mode.
|
||||
*
|
||||
*/
|
||||
void SetMode(uint8_t aMode) { mMode = aMode; }
|
||||
void SetMode(Mle::DeviceMode aMode) { mMode = aMode.Get(); }
|
||||
|
||||
/**
|
||||
* This method returns the Reserved value.
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "common/random.hpp"
|
||||
#include "mac/mac_frame.hpp"
|
||||
#include "net/ip6.hpp"
|
||||
#include "thread/device_mode.hpp"
|
||||
#include "thread/indirect_sender.hpp"
|
||||
#include "thread/link_quality.hpp"
|
||||
#include "thread/mle_tlvs.hpp"
|
||||
@@ -113,7 +114,7 @@ public:
|
||||
* @returns The device mode flags.
|
||||
*
|
||||
*/
|
||||
uint8_t GetDeviceMode(void) const { return mMode; }
|
||||
Mle::DeviceMode GetDeviceMode(void) const { return Mle::DeviceMode(mMode); }
|
||||
|
||||
/**
|
||||
* This method sets the device mode flags.
|
||||
@@ -121,7 +122,7 @@ public:
|
||||
* @param[in] aMode The device mode flags.
|
||||
*
|
||||
*/
|
||||
void SetDeviceMode(uint8_t aMode) { mMode = aMode; }
|
||||
void SetDeviceMode(Mle::DeviceMode aMode) { mMode = aMode.Get(); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device is rx-on-when-idle.
|
||||
@@ -129,7 +130,7 @@ public:
|
||||
* @returns TRUE if rx-on-when-idle, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsRxOnWhenIdle(void) const { return (mMode & Mle::ModeTlv::kModeRxOnWhenIdle) != 0; }
|
||||
bool IsRxOnWhenIdle(void) const { return GetDeviceMode().IsRxOnWhenIdle(); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device is a Full Thread Device.
|
||||
@@ -137,7 +138,7 @@ public:
|
||||
* @returns TRUE if a Full Thread Device, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsFullThreadDevice(void) const { return (mMode & Mle::ModeTlv::kModeFullThreadDevice) != 0; }
|
||||
bool IsFullThreadDevice(void) const { return GetDeviceMode().IsFullThreadDevice(); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device uses secure IEEE 802.15.4 Data Request messages.
|
||||
@@ -145,7 +146,7 @@ public:
|
||||
* @returns TRUE if using secure IEEE 802.15.4 Data Request messages, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsSecureDataRequest(void) const { return (mMode & Mle::ModeTlv::kModeSecureDataRequest) != 0; }
|
||||
bool IsSecureDataRequest(void) const { return GetDeviceMode().IsSecureDataRequest(); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device requests Full Network Data.
|
||||
@@ -153,7 +154,7 @@ public:
|
||||
* @returns TRUE if requests Full Network Data, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsFullNetworkData(void) const { return (mMode & Mle::ModeTlv::kModeFullNetworkData) != 0; }
|
||||
bool IsFullNetworkData(void) const { return GetDeviceMode().IsFullNetworkData(); }
|
||||
|
||||
/**
|
||||
* This method sets all bytes of the Extended Address to zero.
|
||||
|
||||
Reference in New Issue
Block a user