From 19f2533aff508efa503ea05b97e1349362df1b87 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Thu, 20 Dec 2018 05:55:26 +0800 Subject: [PATCH] [qos] handle NCP messages based on the priority of the message (#3318) --- include/openthread/ip6.h | 40 ++++++++++++++++++++++++++++++------ src/core/api/ip6_api.cpp | 14 +++++++++++++ src/core/net/ip6.cpp | 40 ++++++++++++++++++++++++++++++++++++ src/core/net/ip6.hpp | 20 +++++++++++++++++- src/core/net/ip6_headers.cpp | 25 ++++++++++++++-------- src/core/net/ip6_headers.hpp | 11 +++++++++- src/ncp/ncp_base_mtd.cpp | 20 ++++++------------ 7 files changed, 140 insertions(+), 30 deletions(-) diff --git a/include/openthread/ip6.h b/include/openthread/ip6.h index 323a6ce10..7d46c9b1f 100644 --- a/include/openthread/ip6.h +++ b/include/openthread/ip6.h @@ -256,7 +256,7 @@ OTAPI const otNetifAddress *OTCALL otIp6GetUnicastAddresses(otInstance *aInstanc * @retval OT_ERROR_ALREADY The multicast address is already subscribed. * @retval OT_ERROR_INVALID_ARGS The IP Address indicated by @p aAddress is invalid address. * @retval OT_ERROR_NO_BUFS The Network Interface is already storing the maximum allowed external multicast - * addresses. + * addresses. * */ otError otIp6SubscribeMulticastAddress(otInstance *aInstance, const otIp6Address *aAddress); @@ -279,6 +279,7 @@ otError otIp6UnsubscribeMulticastAddress(otInstance *aInstance, const otIp6Addre * @param[in] aInstance A pointer to an OpenThread instance. * * @returns A pointer to the first Network Interface Multicast Address. + * */ const otNetifMulticastAddress *otIp6GetMulticastAddresses(otInstance *aInstance); @@ -288,6 +289,7 @@ const otNetifMulticastAddress *otIp6GetMulticastAddresses(otInstance *aInstance) * @param[in] aInstance A pointer to an OpenThread instance. * * @sa otIp6SetMulticastPromiscuousEnabled + * */ bool otIp6IsMulticastPromiscuousEnabled(otInstance *aInstance); @@ -298,6 +300,7 @@ bool otIp6IsMulticastPromiscuousEnabled(otInstance *aInstance); * @param[in] aEnabled TRUE to enable Multicast Promiscuous mode, FALSE otherwise. * * @sa otIp6IsMulticastPromiscuousEnabled + * */ void otIp6SetMulticastPromiscuousEnabled(otInstance *aInstance, bool aEnabled); @@ -308,7 +311,7 @@ void otIp6SetMulticastPromiscuousEnabled(otInstance *aInstance, bool aEnabled); * @param[inout] aAddress A pointer to structure containing IPv6 address for which IID is being created. * @param[inout] aContext A pointer to creator-specific context. * - * @retval OT_ERROR_NONE Created valid IID for given IPv6 address. + * @retval OT_ERROR_NONE Created valid IID for given IPv6 address. * @retval OT_ERROR_IP6_ADDRESS_CREATION_FAILURE Creation of valid IID for given IPv6 address failed. * */ @@ -361,7 +364,7 @@ otError otIp6CreateMacIid(otInstance *aInstance, otNetifAddress *aAddresses, voi * @param[inout] aAddresses A pointer to structure containing IPv6 address for which IID is being created. * @param[inout] aContext A pointer to a otSemanticallyOpaqueIidGeneratorData structure. * - * @retval OT_ERROR_NONE Created valid IID for given IPv6 address. + * @retval OT_ERROR_NONE Created valid IID for given IPv6 address. * @retval OT_ERROR_IP6_ADDRESS_CREATION_FAILURE Could not create valid IID for given IPv6 address. * */ @@ -378,10 +381,33 @@ otError otIp6CreateSemanticallyOpaqueIid(otInstance *aInstance, otNetifAddress * * * @returns A pointer to the message buffer or NULL if no message buffers are available or parameters are invalid. * - * @sa otFreeMessage + * @sa otMessageFree + * */ otMessage *otIp6NewMessage(otInstance *aInstance, const otMessageSettings *aSettings); +/** + * Allocate a new message buffer and write the IPv6 datagram to the message buffer for sending an IPv6 message. + * + * @note If @p aSettings is NULL, the link layer security is enabled and the message priority is obtained from IPv6 + * message itself. + * If @p aSettings is not NULL, the @p aSetting->mPriority is ignored and obtained from IPv6 message itself. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aData A pointer to the IPv6 datagram buffer. + * @param[in] aDataLength The size of the IPv6 datagram buffer pointed by @p aData. + * @param[in] aSettings A pointer to the message settings or NULL to set default settings. + * + * @returns A pointer to the message or NULL if malformed IPv6 header or insufficient message buffers are available. + * + * @sa otMessageFree + * + */ +otMessage *otIp6NewMessageFromBuffer(otInstance * aInstance, + const uint8_t * aData, + uint16_t aDataLength, + const otMessageSettings *aSettings); + /** * This function pointer is called when an IPv6 datagram is received. * @@ -485,8 +511,8 @@ otError otIp6AddUnsecurePort(otInstance *aInstance, uint16_t aPort); * This function removes a port from the allowed unsecure port list. * * @note This function removes @p aPort by overwriting @p aPort with the element after @p aPort in the internal port - * list. Be careful when calling otIp6GetUnsecurePorts() followed by otIp6RemoveUnsecurePort() to remove unsecure - * ports. + * list. Be careful when calling otIp6GetUnsecurePorts() followed by otIp6RemoveUnsecurePort() to remove unsecure + * ports. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aPort The port value. @@ -526,6 +552,7 @@ const uint16_t *otIp6GetUnsecurePorts(otInstance *aInstance, uint8_t *aNumEntrie * * @retval TRUE The two IPv6 addresses are the same. * @retval FALSE The two IPv6 addresses are not the same. + * */ OTAPI bool OTCALL otIp6IsAddressEqual(const otIp6Address *aFirst, const otIp6Address *aSecond); @@ -537,6 +564,7 @@ OTAPI bool OTCALL otIp6IsAddressEqual(const otIp6Address *aFirst, const otIp6Add * * @retval OT_ERROR_NONE Successfully parsed the string. * @retval OT_ERROR_INVALID_ARGS Failed to parse the string. + * */ OTAPI otError OTCALL otIp6AddressFromString(const char *aString, otIp6Address *aAddress); diff --git a/src/core/api/ip6_api.cpp b/src/core/api/ip6_api.cpp index 3d6cee3fe..68fd48c58 100644 --- a/src/core/api/ip6_api.cpp +++ b/src/core/api/ip6_api.cpp @@ -217,6 +217,20 @@ exit: return message; } +otMessage *otIp6NewMessageFromBuffer(otInstance * aInstance, + const uint8_t * aData, + uint16_t aDataLength, + const otMessageSettings *aSettings) +{ + Instance &instance = *static_cast(aInstance); + Message * message; + + VerifyOrExit((message = instance.GetIp6().NewMessage(aData, aDataLength, aSettings)) != NULL); + +exit: + return message; +} + otError otIp6AddUnsecurePort(otInstance *aInstance, uint16_t aPort) { Instance &instance = *static_cast(aInstance); diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index b617dc099..2c8e0f96c 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -73,6 +73,29 @@ Message *Ip6::NewMessage(uint16_t aReserved, const otMessageSettings *aSettings) Message::kTypeIp6, sizeof(Header) + sizeof(HopByHopHeader) + sizeof(OptionMpl) + aReserved, aSettings); } +Message *Ip6::NewMessage(const uint8_t *aData, uint16_t aDataLength, const otMessageSettings *aSettings) +{ + otMessageSettings settings = {true, OT_MESSAGE_PRIORITY_NORMAL}; + Message * message = NULL; + + if (aSettings != NULL) + { + settings = *aSettings; + } + + SuccessOrExit(GetDatagramPriority(aData, aDataLength, *reinterpret_cast(&settings.mPriority))); + VerifyOrExit((message = GetInstance().GetMessagePool().New(Message::kTypeIp6, 0, &settings)) != NULL); + + if (message->Append(aData, aDataLength) != OT_ERROR_NONE) + { + message->Free(); + message = NULL; + } + +exit: + return message; +} + uint8_t Ip6::DscpToPriority(uint8_t aDscp) { uint8_t priority; @@ -127,6 +150,23 @@ uint8_t Ip6::PriorityToDscp(uint8_t aPriority) return dscp; } +otError Ip6::GetDatagramPriority(const uint8_t *aData, uint16_t aDataLen, uint8_t &aPriority) +{ + otError error = OT_ERROR_NONE; + const Header *header; + + VerifyOrExit((aData != NULL) && (aDataLen >= sizeof(Header)), error = OT_ERROR_INVALID_ARGS); + + header = reinterpret_cast(aData); + VerifyOrExit(header->IsValid(), error = OT_ERROR_PARSE); + VerifyOrExit(sizeof(Header) + header->GetPayloadLength() == aDataLen, error = OT_ERROR_PARSE); + + aPriority = DscpToPriority(header->GetDscp()); + +exit: + return error; +} + uint16_t Ip6::UpdateChecksum(uint16_t aChecksum, const Address &aAddress) { return Message::UpdateChecksum(aChecksum, aAddress.mFields.m8, sizeof(aAddress)); diff --git a/src/core/net/ip6.hpp b/src/core/net/ip6.hpp index 9e7b8dd7a..813df0aad 100644 --- a/src/core/net/ip6.hpp +++ b/src/core/net/ip6.hpp @@ -111,7 +111,7 @@ public: * This method allocates a new message buffer from the buffer pool. * * @note If @p aSettings is 'NULL', the link layer security is enabled and the message priority is set to - * OT_MESSAGE_PRIORITY_NORMAL by default. + * OT_MESSAGE_PRIORITY_NORMAL by default. * * @param[in] aReserved The number of header bytes to reserve following the IPv6 header. * @param[in] aSettings A pointer to the message settings or NULL to set default settings. @@ -121,6 +121,22 @@ public: */ Message *NewMessage(uint16_t aReserved, const otMessageSettings *aSettings = NULL); + /** + * This method allocates a new message buffer from the buffer pool and writes the IPv6 datagram to the message. + * + * @note If @p aSettings is NULL, the link layer security is enabled and the message priority is obtained from + * IPv6 message itself. + * If @p aSettings is not NULL, the @p aSetting->mPriority is ignored and obtained from IPv6 message itself. + * + * @param[in] aData A pointer to the IPv6 datagram buffer. + * @param[in] aDataLength The size of the IPV6 datagram buffer pointed by @p aData. + * @param[in] aSettings A pointer to the message settings or NULL to set default settings. + * + * @returns A pointer to the message or NULL if malformed IPv6 header or insufficient message buffers are available. + * + */ + Message *NewMessage(const uint8_t *aData, uint16_t aDataLength, const otMessageSettings *aSettings); + /** * This method converts the message priority level to IPv6 DSCP value. * @@ -411,6 +427,8 @@ private: static void HandleSendQueue(Tasklet &aTasklet); void HandleSendQueue(void); + static otError GetDatagramPriority(const uint8_t *aData, uint16_t aDataLen, uint8_t &aPriority); + otError ProcessReceiveCallback(const Message & aMessage, const MessageInfo &aMessageInfo, uint8_t aIpProto, diff --git a/src/core/net/ip6_headers.cpp b/src/core/net/ip6_headers.cpp index 759047113..8270b4295 100644 --- a/src/core/net/ip6_headers.cpp +++ b/src/core/net/ip6_headers.cpp @@ -40,22 +40,31 @@ namespace Ip6 { otError Header::Init(const Message &aMessage) { - otError error = OT_ERROR_NONE; - uint16_t length; + otError error = OT_ERROR_NONE; // check aMessage length VerifyOrExit(aMessage.Read(0, sizeof(*this), this) == sizeof(*this), error = OT_ERROR_PARSE); - // check Version - VerifyOrExit(IsVersion6(), error = OT_ERROR_PARSE); - - // check Payload Length - length = sizeof(*this) + GetPayloadLength(); - VerifyOrExit(length == aMessage.GetLength() && length <= Ip6::kMaxDatagramLength, error = OT_ERROR_PARSE); + VerifyOrExit(IsValid(), error = OT_ERROR_PARSE); + VerifyOrExit((sizeof(*this) + GetPayloadLength()) == aMessage.GetLength(), error = OT_ERROR_PARSE); exit: return error; } +bool Header::IsValid(void) const +{ + bool ret = true; + + // check Version + VerifyOrExit(IsVersion6(), ret = false); + + // check Payload Length + VerifyOrExit((sizeof(*this) + GetPayloadLength()) <= Ip6::kMaxDatagramLength, ret = false); + +exit: + return ret; +} + } // namespace Ip6 } // namespace ot diff --git a/src/core/net/ip6_headers.hpp b/src/core/net/ip6_headers.hpp index b8443391f..3e923d603 100644 --- a/src/core/net/ip6_headers.hpp +++ b/src/core/net/ip6_headers.hpp @@ -177,6 +177,15 @@ public: */ otError Init(const Message &aMessage); + /** + * This method indicates whether or not the header appears to be well-formed. + * + * @retval TRUE if the header appears to be well-formed. + * @retval FALSE if the header does not appear to be well-formed. + * + */ + bool IsValid(void) const; + /** * This method indicates whether or not the IPv6 Version is set to 6. * @@ -216,7 +225,7 @@ public: * @returns The IPv6 Payload Length value. * */ - uint16_t GetPayloadLength(void) { return HostSwap16(mPayloadLength); } + uint16_t GetPayloadLength(void) const { return HostSwap16(mPayloadLength); } /** * This method sets the IPv6 Payload Length value. diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index 9f5542ff4..34f09a1d1 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -1744,19 +1744,15 @@ template <> otError NcpBase::HandlePropertySet(void) otMessage * message = NULL; otError error = OT_ERROR_NONE; - // STREAM_NET requires layer 2 security. - message = otIp6NewMessage(mInstance, NULL); - VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); - SuccessOrExit(error = mDecoder.ReadDataWithLen(framePtr, frameLen)); SuccessOrExit(error = mDecoder.ReadData(metaPtr, metaLen)); // We ignore metadata for now. // May later include TX power, allow retransmits, etc... - OT_UNUSED_VARIABLE(metaPtr); - OT_UNUSED_VARIABLE(metaLen); - SuccessOrExit(error = otMessageAppend(message, framePtr, frameLen)); + // STREAM_NET requires layer 2 security. + message = otIp6NewMessageFromBuffer(mInstance, framePtr, frameLen, NULL); + VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); error = otIp6Send(mInstance, message); @@ -2588,19 +2584,15 @@ template <> otError NcpBase::HandlePropertySet( otError error = OT_ERROR_NONE; otMessageSettings msgSettings = {false, OT_MESSAGE_PRIORITY_NORMAL}; - // STREAM_NET_INSECURE packets are not secured at layer 2. - message = otIp6NewMessage(mInstance, &msgSettings); - VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); - SuccessOrExit(mDecoder.ReadDataWithLen(framePtr, frameLen)); SuccessOrExit(mDecoder.ReadData(metaPtr, metaLen)); // We ignore metadata for now. // May later include TX power, allow retransmits, etc... - OT_UNUSED_VARIABLE(metaPtr); - OT_UNUSED_VARIABLE(metaLen); - SuccessOrExit(error = otMessageAppend(message, framePtr, frameLen)); + // STREAM_NET_INSECURE packets are not secured at layer 2. + message = otIp6NewMessageFromBuffer(mInstance, framePtr, frameLen, &msgSettings); + VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); // Ensure the insecure message is forwarded using direct transmission. otMessageSetDirectTransmission(message, true);