LCOV - code coverage report
Current view: top level - setup_payload - SetupPayload.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 149 157 94.9 %
Date: 2024-02-15 08:20:41 Functions: 22 22 100.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2020 Project CHIP Authors
       4             :  *
       5             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6             :  *    you may not use this file except in compliance with the License.
       7             :  *    You may obtain a copy of the License at
       8             :  *
       9             :  *        http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  *    Unless required by applicable law or agreed to in writing, software
      12             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  *    See the License for the specific language governing permissions and
      15             :  *    limitations under the License.
      16             :  */
      17             : 
      18             : /**
      19             :  *    @file
      20             :  *      The implementation of the Setup Payload. Currently only needed to
      21             :  *      verify the validity of a Setup Payload
      22             :  */
      23             : 
      24             : #include "SetupPayload.h"
      25             : 
      26             : #include <lib/core/CHIPCore.h>
      27             : #include <lib/core/CHIPVendorIdentifiers.hpp>
      28             : #include <lib/core/TLV.h>
      29             : #include <lib/core/TLVData.h>
      30             : #include <lib/core/TLVUtilities.h>
      31             : #include <lib/support/CodeUtils.h>
      32             : #include <utility>
      33             : 
      34             : namespace chip {
      35             : 
      36             : // Spec 5.1.4.2 CHIPCommon tag numbers are in the range [0x00, 0x7F]
      37          43 : bool SetupPayload::IsCommonTag(uint8_t tag)
      38             : {
      39          43 :     return tag < 0x80;
      40             : }
      41             : 
      42             : // Spec 5.1.4.1 Manufacture-specific tag numbers are in the range [0x80, 0xFF]
      43          24 : bool SetupPayload::IsVendorTag(uint8_t tag)
      44             : {
      45          24 :     return !IsCommonTag(tag);
      46             : }
      47             : 
      48             : // Check the Setup Payload for validity
      49             : //
      50             : // `vendor_id` and `product_id` are allowed all of uint16_t
      51          37 : bool PayloadContents::isValidQRCodePayload() const
      52             : {
      53             :     // 3-bit value specifying the QR code payload version.
      54          37 :     if (version >= 1 << kVersionFieldLengthInBits)
      55             :     {
      56           1 :         return false;
      57             :     }
      58             : 
      59          36 :     if (static_cast<uint8_t>(commissioningFlow) > static_cast<uint8_t>((1 << kCommissioningFlowFieldLengthInBits) - 1))
      60             :     {
      61           1 :         return false;
      62             :     }
      63             : 
      64             :     // Device Commissioning Flow
      65             :     // 0: Standard commissioning flow: such a device, when uncommissioned, always enters commissioning mode upon power-up, subject
      66             :     // to the rules in [ref_Announcement_Commencement]. 1: User-intent commissioning flow: user action required to enter
      67             :     // commissioning mode. 2: Custom commissioning flow: interaction with a vendor-specified means is needed before commissioning.
      68             :     // 3: Reserved
      69          35 :     if (commissioningFlow != CommissioningFlow::kStandard && commissioningFlow != CommissioningFlow::kUserActionRequired &&
      70           2 :         commissioningFlow != CommissioningFlow::kCustom)
      71             :     {
      72           0 :         return false;
      73             :     }
      74             : 
      75          35 :     chip::RendezvousInformationFlags allvalid(RendezvousInformationFlag::kBLE, RendezvousInformationFlag::kOnNetwork,
      76             :                                               RendezvousInformationFlag::kSoftAP);
      77          35 :     if (!rendezvousInformation.HasValue() || !rendezvousInformation.Value().HasOnly(allvalid))
      78             :     {
      79           3 :         return false;
      80             :     }
      81             : 
      82             :     // Discriminator validity is enforced by the SetupDiscriminator class.
      83             : 
      84          32 :     if (setUpPINCode >= 1 << kSetupPINCodeFieldLengthInBits)
      85             :     {
      86           1 :         return false;
      87             :     }
      88             : 
      89          31 :     return CheckPayloadCommonConstraints();
      90             : }
      91             : 
      92          12 : bool PayloadContents::isValidManualCode() const
      93             : {
      94             :     // Discriminator validity is enforced by the SetupDiscriminator class.
      95             : 
      96          12 :     if (setUpPINCode >= 1 << kSetupPINCodeFieldLengthInBits)
      97             :     {
      98           0 :         return false;
      99             :     }
     100             : 
     101          12 :     return CheckPayloadCommonConstraints();
     102             : }
     103             : 
     104          43 : bool PayloadContents::IsValidSetupPIN(uint32_t setupPIN)
     105             : {
     106             :     // SHALL be restricted to the values 0x0000001 to 0x5F5E0FE (00000001 to 99999998 in decimal), excluding the invalid Passcode
     107             :     // values.
     108          43 :     if (setupPIN == kSetupPINCodeUndefinedValue || setupPIN > kSetupPINCodeMaximumValue || setupPIN == 11111111 ||
     109          42 :         setupPIN == 22222222 || setupPIN == 33333333 || setupPIN == 44444444 || setupPIN == 55555555 || setupPIN == 66666666 ||
     110          42 :         setupPIN == 77777777 || setupPIN == 88888888 || setupPIN == 12345678 || setupPIN == 87654321)
     111             :     {
     112           1 :         return false;
     113             :     }
     114             : 
     115          42 :     return true;
     116             : }
     117             : 
     118          43 : bool PayloadContents::CheckPayloadCommonConstraints() const
     119             : {
     120             :     // A version not equal to 0 would be invalid for v1 and would indicate new format (e.g. version 2)
     121          43 :     if (version != 0)
     122             :     {
     123           0 :         return false;
     124             :     }
     125             : 
     126          43 :     if (!IsValidSetupPIN(setUpPINCode))
     127             :     {
     128           1 :         return false;
     129             :     }
     130             : 
     131             :     // VendorID must be unspecified (0) or in valid range expected.
     132          42 :     if (!IsVendorIdValidOperationally(vendorID) && (vendorID != VendorId::Unspecified))
     133             :     {
     134           0 :         return false;
     135             :     }
     136             : 
     137             :     // A value of 0x0000 SHALL NOT be assigned to a product since Product ID = 0x0000 is used for these specific cases:
     138             :     //  * To announce an anonymized Product ID as part of device discovery
     139             :     //  * To indicate an OTA software update file applies to multiple Product IDs equally.
     140             :     //  * To avoid confusion when presenting the Onboarding Payload for ECM with multiple nodes
     141          42 :     if (productID == 0 && vendorID != VendorId::Unspecified)
     142             :     {
     143           0 :         return false;
     144             :     }
     145             : 
     146          42 :     return true;
     147             : }
     148             : 
     149          22 : bool PayloadContents::operator==(PayloadContents & input) const
     150             : {
     151          22 :     return (this->version == input.version && this->vendorID == input.vendorID && this->productID == input.productID &&
     152          44 :             this->commissioningFlow == input.commissioningFlow && this->rendezvousInformation == input.rendezvousInformation &&
     153          66 :             this->discriminator == input.discriminator && this->setUpPINCode == input.setUpPINCode);
     154             : }
     155             : 
     156          11 : CHIP_ERROR SetupPayload::addOptionalVendorData(uint8_t tag, std::string data)
     157             : {
     158          11 :     OptionalQRCodeInfo info;
     159          11 :     info.tag  = tag;
     160          11 :     info.type = optionalQRCodeInfoTypeString;
     161          11 :     info.data = std::move(data);
     162             : 
     163          11 :     return addOptionalVendorData(info);
     164          11 : }
     165             : 
     166           6 : CHIP_ERROR SetupPayload::addOptionalVendorData(uint8_t tag, int32_t data)
     167             : {
     168           6 :     OptionalQRCodeInfo info;
     169           6 :     info.tag   = tag;
     170           6 :     info.type  = optionalQRCodeInfoTypeInt32;
     171           6 :     info.int32 = data;
     172             : 
     173           6 :     return addOptionalVendorData(info);
     174           6 : }
     175             : 
     176          58 : std::vector<OptionalQRCodeInfo> SetupPayload::getAllOptionalVendorData() const
     177             : {
     178          58 :     std::vector<OptionalQRCodeInfo> returnedOptionalInfo;
     179          80 :     for (auto & entry : optionalVendorData)
     180             :     {
     181          22 :         returnedOptionalInfo.push_back(entry.second);
     182             :     }
     183          58 :     return returnedOptionalInfo;
     184             : }
     185             : 
     186           4 : CHIP_ERROR SetupPayload::removeOptionalVendorData(uint8_t tag)
     187             : {
     188           4 :     VerifyOrReturnError(optionalVendorData.find(tag) != optionalVendorData.end(), CHIP_ERROR_KEY_NOT_FOUND);
     189           2 :     optionalVendorData.erase(tag);
     190             : 
     191           2 :     return CHIP_NO_ERROR;
     192             : }
     193             : 
     194           7 : CHIP_ERROR SetupPayload::addSerialNumber(std::string serialNumber)
     195             : {
     196           7 :     OptionalQRCodeInfoExtension info;
     197           7 :     info.tag  = kSerialNumberTag;
     198           7 :     info.type = optionalQRCodeInfoTypeString;
     199           7 :     info.data = std::move(serialNumber);
     200             : 
     201           7 :     return addOptionalExtensionData(info);
     202           7 : }
     203             : 
     204           2 : CHIP_ERROR SetupPayload::addSerialNumber(uint32_t serialNumber)
     205             : {
     206           2 :     OptionalQRCodeInfoExtension info;
     207           2 :     info.tag    = kSerialNumberTag;
     208           2 :     info.type   = optionalQRCodeInfoTypeUInt32;
     209           2 :     info.uint32 = serialNumber;
     210             : 
     211           2 :     return addOptionalExtensionData(info);
     212           2 : }
     213             : 
     214           4 : CHIP_ERROR SetupPayload::getSerialNumber(std::string & outSerialNumber) const
     215             : {
     216           4 :     CHIP_ERROR err = CHIP_NO_ERROR;
     217           4 :     OptionalQRCodeInfoExtension info;
     218           4 :     ReturnErrorOnFailure(getOptionalExtensionData(kSerialNumberTag, info));
     219             : 
     220           2 :     switch (info.type)
     221             :     {
     222           1 :     case (optionalQRCodeInfoTypeString):
     223           1 :         outSerialNumber = info.data;
     224           1 :         break;
     225           1 :     case (optionalQRCodeInfoTypeUInt32):
     226           1 :         outSerialNumber = std::to_string(info.uint32);
     227           1 :         break;
     228           0 :     default:
     229           0 :         err = CHIP_ERROR_INVALID_ARGUMENT;
     230           0 :         break;
     231             :     }
     232             : 
     233           2 :     return err;
     234           4 : }
     235             : 
     236           3 : CHIP_ERROR SetupPayload::removeSerialNumber()
     237             : {
     238           3 :     VerifyOrReturnError(optionalExtensionData.find(kSerialNumberTag) != optionalExtensionData.end(), CHIP_ERROR_KEY_NOT_FOUND);
     239           1 :     optionalExtensionData.erase(kSerialNumberTag);
     240             : 
     241           1 :     return CHIP_NO_ERROR;
     242             : }
     243             : 
     244          21 : CHIP_ERROR SetupPayload::addOptionalVendorData(const OptionalQRCodeInfo & info)
     245             : {
     246          21 :     VerifyOrReturnError(IsVendorTag(info.tag), CHIP_ERROR_INVALID_ARGUMENT);
     247          19 :     optionalVendorData[info.tag] = info;
     248             : 
     249          19 :     return CHIP_NO_ERROR;
     250             : }
     251             : 
     252          12 : CHIP_ERROR SetupPayload::addOptionalExtensionData(const OptionalQRCodeInfoExtension & info)
     253             : {
     254          12 :     VerifyOrReturnError(IsCommonTag(info.tag), CHIP_ERROR_INVALID_ARGUMENT);
     255          12 :     optionalExtensionData[info.tag] = info;
     256             : 
     257          12 :     return CHIP_NO_ERROR;
     258             : }
     259             : 
     260           4 : CHIP_ERROR SetupPayload::getOptionalVendorData(uint8_t tag, OptionalQRCodeInfo & info)
     261             : {
     262           4 :     VerifyOrReturnError(optionalVendorData.find(tag) != optionalVendorData.end(), CHIP_ERROR_KEY_NOT_FOUND);
     263           4 :     info = optionalVendorData[tag];
     264             : 
     265           4 :     return CHIP_NO_ERROR;
     266             : }
     267             : 
     268           7 : CHIP_ERROR SetupPayload::getOptionalExtensionData(uint8_t tag, OptionalQRCodeInfoExtension & info) const
     269             : {
     270           7 :     const auto it = optionalExtensionData.find(tag);
     271           7 :     VerifyOrReturnError(it != optionalExtensionData.end(), CHIP_ERROR_KEY_NOT_FOUND);
     272           5 :     info = it->second;
     273           5 :     return CHIP_NO_ERROR;
     274             : }
     275             : 
     276           3 : optionalQRCodeInfoType SetupPayload::getNumericTypeFor(uint8_t tag)
     277             : {
     278           3 :     optionalQRCodeInfoType elemType = optionalQRCodeInfoTypeUnknown;
     279             : 
     280           3 :     if (IsVendorTag(tag))
     281             :     {
     282           2 :         elemType = optionalQRCodeInfoTypeInt32;
     283             :     }
     284           1 :     else if (tag == kSerialNumberTag)
     285             :     {
     286           1 :         elemType = optionalQRCodeInfoTypeUInt32;
     287             :     }
     288             : 
     289           3 :     return elemType;
     290             : }
     291             : 
     292          51 : std::vector<OptionalQRCodeInfoExtension> SetupPayload::getAllOptionalExtensionData()
     293             : {
     294          51 :     std::vector<OptionalQRCodeInfoExtension> returnedOptionalInfo;
     295          66 :     for (auto & entry : optionalExtensionData)
     296             :     {
     297          15 :         returnedOptionalInfo.push_back(entry.second);
     298             :     }
     299          51 :     return returnedOptionalInfo;
     300             : }
     301             : 
     302          20 : bool SetupPayload::operator==(SetupPayload & input)
     303             : {
     304          20 :     std::vector<OptionalQRCodeInfo> inputOptionalVendorData;
     305          20 :     std::vector<OptionalQRCodeInfoExtension> inputOptionalExtensionData;
     306             : 
     307          20 :     VerifyOrReturnError(PayloadContents::operator==(input), false);
     308             : 
     309          19 :     inputOptionalVendorData = input.getAllOptionalVendorData();
     310          19 :     VerifyOrReturnError(optionalVendorData.size() == inputOptionalVendorData.size(), false);
     311             : 
     312          23 :     for (const OptionalQRCodeInfo & inputInfo : inputOptionalVendorData)
     313             :     {
     314           4 :         OptionalQRCodeInfo info;
     315           4 :         CHIP_ERROR err = getOptionalVendorData(inputInfo.tag, info);
     316           4 :         VerifyOrReturnError(err == CHIP_NO_ERROR, false);
     317           4 :         VerifyOrReturnError(inputInfo.type == info.type, false);
     318           4 :         VerifyOrReturnError(inputInfo.data == info.data, false);
     319           4 :         VerifyOrReturnError(inputInfo.int32 == info.int32, false);
     320           4 :     }
     321             : 
     322          19 :     inputOptionalExtensionData = input.getAllOptionalExtensionData();
     323          19 :     VerifyOrReturnError(optionalExtensionData.size() == inputOptionalExtensionData.size(), false);
     324             : 
     325          22 :     for (const OptionalQRCodeInfoExtension & inputInfo : inputOptionalExtensionData)
     326             :     {
     327           3 :         OptionalQRCodeInfoExtension info;
     328           3 :         CHIP_ERROR err = getOptionalExtensionData(inputInfo.tag, info);
     329           3 :         VerifyOrReturnError(err == CHIP_NO_ERROR, false);
     330           3 :         VerifyOrReturnError(inputInfo.type == info.type, false);
     331           3 :         VerifyOrReturnError(inputInfo.data == info.data, false);
     332           3 :         VerifyOrReturnError(inputInfo.int32 == info.int32, false);
     333           3 :         VerifyOrReturnError(inputInfo.int64 == info.int64, false);
     334           3 :         VerifyOrReturnError(inputInfo.uint32 == info.uint32, false);
     335           3 :         VerifyOrReturnError(inputInfo.uint64 == info.uint64, false);
     336           3 :     }
     337             : 
     338          19 :     return true;
     339          20 : }
     340             : 
     341             : } // namespace chip

Generated by: LCOV version 1.14