diff --git a/examples/drivers/windows/include/otLwfIoctl.h b/examples/drivers/windows/include/otLwfIoctl.h index bf4f78d1f..5dbdf6dab 100644 --- a/examples/drivers/windows/include/otLwfIoctl.h +++ b/examples/drivers/windows/include/otLwfIoctl.h @@ -694,8 +694,13 @@ typedef struct otCommissionConfig // GUID - InterfaceGuid // otPSKc - aPSKc +#define IOCTL_OTLWF_OT_PARENT_PRIORITY \ + OTLWF_CTL_CODE(196, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) + // GUID - InterfaceGuid + // int8_t - aParentPriority + // OpenThread function IOCTL codes #define MIN_OTLWF_IOCTL_FUNC_CODE 100 -#define MAX_OTLWF_IOCTL_FUNC_CODE 195 +#define MAX_OTLWF_IOCTL_FUNC_CODE 196 #endif //__OTLWFIOCTL_H__ diff --git a/examples/drivers/windows/otApi/otApi.cpp b/examples/drivers/windows/otApi/otApi.cpp index 65e3dab07..f3bdc0e9d 100644 --- a/examples/drivers/windows/otApi/otApi.cpp +++ b/examples/drivers/windows/otApi/otApi.cpp @@ -3843,3 +3843,27 @@ otJoinerStop( if (aInstance == nullptr) return OT_ERROR_INVALID_ARGS; return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_JOINER_STOP)); } + +OTAPI +int8_t +OTCALL +otThreadGetParentPriority( + _In_ otInstance *aInstance +) +{ + int8_t Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_PARENT_PRIORITY, &Result); + return Result; +} + +OTAPI +otError +OTCALL +otThreadSetParentPriority( + _In_ otInstance *aInstance, + int8_t aParentPriority + ) +{ + if (aInstance == nullptr) return OT_ERROR_INVALID_ARGS; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_PARENT_PRIORITY, aParentPriority)); +} diff --git a/examples/drivers/windows/otLwf/iocontrol.c b/examples/drivers/windows/otLwf/iocontrol.c index a13603345..a1b343ded 100644 --- a/examples/drivers/windows/otLwf/iocontrol.c +++ b/examples/drivers/windows/otLwf/iocontrol.c @@ -141,6 +141,7 @@ OTLWF_IOCTL_HANDLER IoCtls[] = { "IOCTL_OTLWF_OT_THREAD_AUTO_START", REF_IOCTL_FUNC(otThreadAutoStart) }, { "IOCTL_OTLWF_OT_PREFERRED_ROUTER_ID", REF_IOCTL_FUNC(otThreadPreferredRouterId) }, { "IOCTL_OTLWF_OT_PSKC", REF_IOCTL_FUNC_WITH_TUN(otPSKc) }, + { "IOCTL_OTLWF_OT_PARENT_PRIORITY", REF_IOCTL_FUNC(otParentPriority) }, }; static_assert(ARRAYSIZE(IoCtls) == (MAX_OTLWF_IOCTL_FUNC_CODE - MIN_OTLWF_IOCTL_FUNC_CODE) + 1, @@ -6225,3 +6226,38 @@ otLwfIoCtl_otThreadPreferredRouterId( return status; } + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +otLwfIoCtl_otParentPriority( + _In_ PMS_FILTER pFilter, + _In_reads_bytes_(InBufferLength) + PUCHAR InBuffer, + _In_ ULONG InBufferLength, + _Out_writes_bytes_(*OutBufferLength) + PVOID OutBuffer, + _Inout_ PULONG OutBufferLength + ) +{ + NTSTATUS status = STATUS_INVALID_PARAMETER; + + if (InBufferLength >= sizeof(int8_t)) + { + otThreadSetParentPriority(pFilter->otCtx, *(int8_t*)InBuffer); + status = STATUS_SUCCESS; + *OutBufferLength = 0; + } + else if (*OutBufferLength >= sizeof(int8_t)) + { + *(uint16_t*)OutBuffer = otThreadGetParentPriority(pFilter->otCtx); + status = STATUS_SUCCESS; + *OutBufferLength = sizeof(int8_t); + } + else + { + *OutBufferLength = 0; + } + + return status; +} + diff --git a/examples/drivers/windows/otLwf/iocontrol.h b/examples/drivers/windows/otLwf/iocontrol.h index 724c2caa7..67eb72416 100644 --- a/examples/drivers/windows/otLwf/iocontrol.h +++ b/examples/drivers/windows/otLwf/iocontrol.h @@ -227,5 +227,6 @@ DECL_IOCTL_FUNC(otFactoryReset); DECL_IOCTL_FUNC(otThreadAutoStart); DECL_IOCTL_FUNC(otThreadPreferredRouterId); DECL_IOCTL_FUNC_WITH_TUN2(otPSKc); +DECL_IOCTL_FUNC(otParentPriority); #endif // _IOCONTROL_H diff --git a/include/openthread/thread_ftd.h b/include/openthread/thread_ftd.h index 6bc2cfb94..eeffdf573 100644 --- a/include/openthread/thread_ftd.h +++ b/include/openthread/thread_ftd.h @@ -424,6 +424,30 @@ OTAPI const uint8_t *OTCALL otThreadGetPSKc(otInstance *aInstance); */ OTAPI otError OTCALL otThreadSetPSKc(otInstance *aInstance, const uint8_t *aPSKc); +/** + * Get the assigned parent priority. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns The assigned parent priority value, -2 means not assigned. + * + * @sa otThreadSetParentPriority + */ +OTAPI int8_t OTCALL otThreadGetParentPriority(otInstance *aInstance); + +/** + * Set the parent priority. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aParentPriority The parent priority value. + * + * @retval OT_ERROR_NONE Successfully set the parent priority. + * @retval OT_ERROR_INVALID_ARGS If the parent priority value is not among 1, 0, -1 and -2. + * + * @sa otThreadGetParentPriority + */ +OTAPI otError OTCALL otThreadSetParentPriority(otInstance *aInstance, int8_t aParentPriority); + /** * @} * diff --git a/src/cli/README.md b/src/cli/README.md index 46e3afab2..a8969c4ae 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -46,6 +46,7 @@ OpenThread test scripts use the CLI to execute test cases. * [networkname](#networkname) * [panid](#panid) * [parent](#parent) +* [parentpriority](#parentpriority) * [ping](#ping-ipaddr-size-count-interval) * [pollperiod](#pollperiod-pollperiod) * [prefix](#prefix-add-prefix-pvdcsr-prf) @@ -1243,6 +1244,25 @@ Age: 20 Done ``` +### parentpriority + +Get the assigned parent priority value, -2 means not assigned. + +```bash +> parentpriority +1 +Done +``` + +### parentpriority \ + +Set the assigned parent priority value: 1, 0, -1 or -2. + +```bash +> parentpriority 1 +Done +``` + ### ping \ [size] [count] [interval] Send an ICMPv6 Echo Request. diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 084356f7f..98c0da094 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -165,6 +165,9 @@ const struct Command Interpreter::sCommands[] = { "networkname", &Interpreter::ProcessNetworkName }, { "panid", &Interpreter::ProcessPanId }, { "parent", &Interpreter::ProcessParent }, +#if OPENTHREAD_FTD + { "parentpriority", &Interpreter::ProcessParentPriority }, +#endif #ifndef OTDLL { "ping", &Interpreter::ProcessPing }, #endif @@ -1552,6 +1555,27 @@ exit: AppendResult(error); } +#if OPENTHREAD_FTD +void Interpreter::ProcessParentPriority(int argc, char *argv[]) +{ + otError error = OT_ERROR_NONE; + long value; + + if (argc == 0) + { + mServer->OutputFormat("%d\r\n", otThreadGetParentPriority(mInstance)); + } + else + { + SuccessOrExit(error = ParseLong(argv[0], value)); + error = otThreadSetParentPriority(mInstance, static_cast(value)); + } + +exit: + AppendResult(error); +} +#endif + #ifndef OTDLL void Interpreter::s_HandleIcmpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo, const otIcmp6Header *aIcmpHeader) diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index e9fd4708c..41bf28f76 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -237,6 +237,9 @@ private: void ProcessNetworkName(int argc, char *argv[]); void ProcessPanId(int argc, char *argv[]); void ProcessParent(int argc, char *argv[]); +#if OPENTHREAD_FTD + void ProcessParentPriority(int argc, char *argv[]); +#endif void ProcessPing(int argc, char *argv[]); void ProcessPollPeriod(int argc, char *argv[]); #if OPENTHREAD_ENABLE_BORDER_ROUTER diff --git a/src/core/api/thread_ftd_api.cpp b/src/core/api/thread_ftd_api.cpp index beb7a44a2..6a87fb093 100644 --- a/src/core/api/thread_ftd_api.cpp +++ b/src/core/api/thread_ftd_api.cpp @@ -273,4 +273,14 @@ exit: return error; } +int8_t otThreadGetParentPriority(otInstance *aInstance) +{ + return aInstance->mThreadNetif.GetMle().GetAssignParentPriority(); +} + +otError otThreadSetParentPriority(otInstance *aInstance, const int8_t aParentPriority) +{ + return aInstance->mThreadNetif.GetMle().SetAssignParentPriority(aParentPriority); +} + #endif // OPENTHREAD_FTD diff --git a/src/core/thread/mle_constants.hpp b/src/core/thread/mle_constants.hpp index 5fa1f4870..eaba6f9dd 100644 --- a/src/core/thread/mle_constants.hpp +++ b/src/core/thread/mle_constants.hpp @@ -105,6 +105,18 @@ enum kMleEndDeviceTimeout = OPENTHREAD_CONFIG_DEFAULT_CHILD_TIMEOUT, ///< MLE_END_DEVICE_TIMEOUT (seconds) }; +/** + * Parent Priority values + * + */ +enum +{ + kParentPriorityHigh = 1, // Parent Priority High + kParentPriorityMedium = 0, // Parent Priority Medium (default) + kParentPriorityLow = -1, // Parent Priority Low + kParentPriorityUnspecified = -2, // Parent Priority Unspecified +}; + enum { kLinkQuality3LinkCost = 1, ///< Link Cost for Link Quality 3 diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 30e146643..c47d00627 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -77,7 +77,8 @@ MleRouter::MleRouter(ThreadNetif &aThreadNetif): mIsRouterRestoringChildren(false), mPreviousPartitionId(0), mRouterSelectionJitter(kRouterSelectionJitter), - mRouterSelectionJitterTimeout(0) + mRouterSelectionJitterTimeout(0), + mParentPriority(kParentPriorityUnspecified) { mDeviceMode |= ModeTlv::kModeFFD | ModeTlv::kModeFullNetworkData; @@ -4212,24 +4213,34 @@ void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv) uint8_t cost; uint8_t linkQuality; uint8_t numChildren = 0; + int8_t parentPriority = kParentPriorityMedium; - for (int i = 0; i < mMaxChildrenAllowed; i++) + if (mParentPriority != kParentPriorityUnspecified) { - if (mChildren[i].GetState() == Neighbor::kStateValid) - { - numChildren++; - } - } - - if ((mMaxChildrenAllowed - numChildren) < (mMaxChildrenAllowed / 3)) - { - tlv.SetParentPriority(-1); + parentPriority = mParentPriority; } else { - tlv.SetParentPriority(0); + for (int i = 0; i < mMaxChildrenAllowed; i++) + { + if (mChildren[i].GetState() == Neighbor::kStateValid) + { + numChildren++; + } + } + + if ((mMaxChildrenAllowed - numChildren) < (mMaxChildrenAllowed / 3)) + { + parentPriority = kParentPriorityLow; + } + else + { + parentPriority = kParentPriorityMedium; + } } + tlv.SetParentPriority(parentPriority); + // compute leader cost and link qualities tlv.SetLinkQuality1(0); tlv.SetLinkQuality2(0); @@ -4658,6 +4669,24 @@ uint8_t MleRouter::GetMinDowngradeNeighborRouters(void) return routerCount; } +int8_t MleRouter::GetAssignParentPriority(void) const +{ + return mParentPriority; +} + +otError MleRouter::SetAssignParentPriority(int8_t aParentPriority) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(aParentPriority <= kParentPriorityHigh && + aParentPriority >= kParentPriorityUnspecified, error = OT_ERROR_INVALID_ARGS); + + mParentPriority = aParentPriority; + +exit: + return error; +} + } // namespace Mle } // namespace ot diff --git a/src/core/thread/mle_router_ftd.hpp b/src/core/thread/mle_router_ftd.hpp index e3fbaf834..f667bd3f7 100644 --- a/src/core/thread/mle_router_ftd.hpp +++ b/src/core/thread/mle_router_ftd.hpp @@ -665,6 +665,25 @@ public: otError SetSteeringData(otExtAddress *aExtAddress); #endif // OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB + /** + * This method gets the assigned parent priority. + * + * @returns The assigned parent priority value, -2 means not assigned. + * + */ + int8_t GetAssignParentPriority(void) const; + + /** + * This method sets the parent priority. + * + * @param[in] aParentPriority The parent priority value. + * + * @retval OT_ERROR_NONE Successfully set the parent priority. + * @retval OT_ERROR_INVALID_ARGS If the parent priority value is not among 1, 0, -1 and -2. + * + */ + otError SetAssignParentPriority(int8_t aParentPriority); + private: enum { @@ -789,6 +808,8 @@ private: uint8_t mRouterSelectionJitter; ///< The variable to save the assigned jitter value. uint8_t mRouterSelectionJitterTimeout; ///< The Timeout prior to request/release Router ID. + int8_t mParentPriority; ///< The assigned parent priority value, -2 means not assigned. + #if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB MeshCoP::SteeringDataTlv mSteeringData; #endif // OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB