| /* |
| * |
| * Copyright (c) 2020 Project CHIP Authors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @file This file contains the implementation the chip::MessageHeader class. |
| */ |
| |
| #include "MessageHeader.h" |
| |
| #include <assert.h> |
| |
| #include <core/CHIPEncoding.h> |
| #include <core/CHIPError.h> |
| #include <support/CodeUtils.h> |
| |
| /********************************************** |
| * Header format (little endian): |
| * |
| * 16 bit: | VERSION: 4 bit | FLAGS: 4 bit | RESERVED: 8 bit | |
| * 16 bit: | Secure message type | |
| * 32 bit: | MESSAGE_ID | |
| * 32 bit: | Secure Session ID | |
| * 64 bit: | Encryption Initialization Vector (nonce) | |
| * 64 bit: | Message Authentication Tag | |
| * 64 bit: | SOURCE_NODE_ID (iff source node flag is set) | |
| * 64 bit: | DEST_NODE_ID (iff destination node flag is set) | |
| * |
| **********************************************/ |
| |
| namespace chip { |
| namespace { |
| |
| using namespace chip::Encoding; |
| |
| /// size of the fixed portion of the header |
| constexpr size_t kFixedHeaderSizeBytes = 28; |
| |
| /// size of a serialized node id inside a header |
| constexpr size_t kNodeIdSizeBytes = 8; |
| |
| /// Header flag specifying that a destination node id is included in the header. |
| constexpr uint16_t kFlagDestinationNodeIdPresent = 0x0100; |
| /// Header flag specifying that a source node id is included in the header. |
| constexpr uint16_t kFlagSourceNodeIdPresent = 0x0200; |
| |
| /// Mask to extract just the version part from a 16bit header prefix. |
| constexpr uint16_t kVersionMask = 0xF000; |
| /// Shift to convert to/from a masked version 16bit value to a 4bit version. |
| constexpr int kVersionShift = 12; |
| |
| } // namespace |
| |
| size_t MessageHeader::EncodeSizeBytes() const |
| { |
| size_t size = kFixedHeaderSizeBytes; |
| |
| if (mSourceNodeId.HasValue()) |
| { |
| size += kNodeIdSizeBytes; |
| } |
| |
| if (mDestinationNodeId.HasValue()) |
| { |
| size += kNodeIdSizeBytes; |
| } |
| |
| return size; |
| } |
| |
| CHIP_ERROR MessageHeader::Decode(const uint8_t * data, size_t size, size_t * decode_len) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| const uint8_t * p = data; |
| uint16_t header; |
| int version; |
| |
| VerifyOrExit(size >= kFixedHeaderSizeBytes, err = CHIP_ERROR_INVALID_ARGUMENT); |
| |
| header = LittleEndian::Read16(p); |
| version = ((header & kVersionMask) >> kVersionShift); |
| VerifyOrExit(version == kHeaderVersion, err = CHIP_ERROR_VERSION_MISMATCH); |
| |
| mSecureMsgType = LittleEndian::Read16(p); |
| mMessageId = LittleEndian::Read32(p); |
| mSecureSessionID = LittleEndian::Read32(p); |
| mIV = LittleEndian::Read64(p); |
| mTag = LittleEndian::Read64(p); |
| |
| assert(p - data == kFixedHeaderSizeBytes); |
| size -= kFixedHeaderSizeBytes; |
| |
| if (header & kFlagSourceNodeIdPresent) |
| { |
| VerifyOrExit(size >= kNodeIdSizeBytes, err = CHIP_ERROR_INVALID_ARGUMENT); |
| mSourceNodeId.SetValue(LittleEndian::Read64(p)); |
| size -= kNodeIdSizeBytes; |
| } |
| else |
| { |
| mSourceNodeId.ClearValue(); |
| } |
| |
| if (header & kFlagDestinationNodeIdPresent) |
| { |
| VerifyOrExit(size >= kNodeIdSizeBytes, err = CHIP_ERROR_INVALID_ARGUMENT); |
| mDestinationNodeId.SetValue(LittleEndian::Read64(p)); |
| size -= kNodeIdSizeBytes; |
| } |
| else |
| { |
| mDestinationNodeId.ClearValue(); |
| } |
| |
| *decode_len = p - data; |
| |
| exit: |
| |
| return err; |
| } |
| |
| CHIP_ERROR MessageHeader::Encode(uint8_t * data, size_t size, size_t * encode_size) const |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| uint8_t * p = data; |
| uint16_t header = kHeaderVersion << kVersionShift; |
| |
| VerifyOrExit(size >= EncodeSizeBytes(), err = CHIP_ERROR_INVALID_ARGUMENT); |
| |
| if (mSourceNodeId.HasValue()) |
| { |
| header |= kFlagSourceNodeIdPresent; |
| } |
| if (mDestinationNodeId.HasValue()) |
| { |
| header |= kFlagDestinationNodeIdPresent; |
| } |
| |
| LittleEndian::Write16(p, header); |
| LittleEndian::Write16(p, mSecureMsgType); |
| LittleEndian::Write32(p, mMessageId); |
| LittleEndian::Write32(p, mSecureSessionID); |
| LittleEndian::Write64(p, mIV); |
| LittleEndian::Write64(p, mTag); |
| if (mSourceNodeId.HasValue()) |
| { |
| LittleEndian::Write64(p, mSourceNodeId.Value()); |
| } |
| if (mDestinationNodeId.HasValue()) |
| { |
| LittleEndian::Write64(p, mDestinationNodeId.Value()); |
| } |
| |
| // Written data size provided to caller on success |
| *encode_size = p - data; |
| |
| exit: |
| return err; |
| } |
| |
| } // namespace chip |