/* * * Copyright (c) 2020 Project CHIP Authors * All rights reserved. * * 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. */ #include #include #include #include #include "Options.h" #include #include #include #include #include #include #include #include #include #include #if ENABLE_TRACING #include // nogncheck #endif #if CHIP_WITH_NLFAULTINJECTION #include #include #include #endif using namespace chip; using namespace chip::ArgParser; using namespace chip::Platform; #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS using namespace chip::Access; #endif namespace { LinuxDeviceOptions gDeviceOptions; // Follow the code style of command line arguments in case we need to add more options in the future. enum { kDeviceOption_BleDevice = 0x1000, kDeviceOption_WiFi, kDeviceOption_Thread, kDeviceOption_Version, kDeviceOption_VendorID, kDeviceOption_ProductID, kDeviceOption_CustomFlow, kDeviceOption_Capabilities, kDeviceOption_Discriminator, kDeviceOption_Passcode, #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE || CHIP_DEVICE_ENABLE_PORT_PARAMS kDeviceOption_SecuredDevicePort, kDeviceOption_UnsecuredCommissionerPort, #endif #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE kDeviceOption_SecuredCommissionerPort, kCommissionerOption_FabricID, #endif kDeviceOption_Command, kDeviceOption_PICS, kDeviceOption_KVS, kDeviceOption_InterfaceId, kDeviceOption_Spake2pVerifierBase64, kDeviceOption_Spake2pSaltBase64, kDeviceOption_Spake2pIterations, kDeviceOption_TraceFile, kDeviceOption_TraceLog, kDeviceOption_TraceDecode, #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS kDeviceOption_CommissioningArlEntries, kDeviceOption_ArlEntries, #endif kOptionCSRResponseCSRIncorrectType, kOptionCSRResponseCSRNonceIncorrectType, kOptionCSRResponseCSRNonceTooLong, kOptionCSRResponseCSRNonceInvalid, kOptionCSRResponseNOCSRElementsTooLong, kOptionCSRResponseAttestationSignatureIncorrectType, kOptionCSRResponseAttestationSignatureInvalid, kOptionCSRResponseCSRExistingKeyPair, kDeviceOption_TestEventTriggerEnableKey, kTraceTo, kOptionSimulateNoInternalTime, #if defined(PW_RPC_ENABLED) kOptionRpcServerPort, #endif #if CONFIG_BUILD_FOR_HOST_UNIT_TEST kDeviceOption_SubscriptionCapacity, #endif kDeviceOption_WiFiSupports5g, #if CONFIG_BUILD_FOR_HOST_UNIT_TEST kDeviceOption_SubscriptionResumptionRetryIntervalSec, #endif #if CHIP_WITH_NLFAULTINJECTION kDeviceOption_FaultInjection, #endif #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF kDeviceOption_WiFi_PAF, #endif }; constexpr unsigned kAppUsageLength = 64; OptionDef sDeviceOptionDefs[] = { #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE { "ble-device", kArgumentRequired, kDeviceOption_BleDevice }, #endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE #if CHIP_DEVICE_CONFIG_ENABLE_WIFI { "wifi", kNoArgument, kDeviceOption_WiFi }, { "wifi-supports-5g", kNoArgument, kDeviceOption_WiFiSupports5g }, #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF { "wifipaf", kArgumentRequired, kDeviceOption_WiFi_PAF }, #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF #endif // CHIP_DEVICE_CONFIG_ENABLE_WPA #if CHIP_ENABLE_OPENTHREAD { "thread", kNoArgument, kDeviceOption_Thread }, #endif // CHIP_ENABLE_OPENTHREAD { "version", kArgumentRequired, kDeviceOption_Version }, { "vendor-id", kArgumentRequired, kDeviceOption_VendorID }, { "product-id", kArgumentRequired, kDeviceOption_ProductID }, { "custom-flow", kArgumentRequired, kDeviceOption_CustomFlow }, { "capabilities", kArgumentRequired, kDeviceOption_Capabilities }, { "discriminator", kArgumentRequired, kDeviceOption_Discriminator }, { "passcode", kArgumentRequired, kDeviceOption_Passcode }, { "spake2p-verifier-base64", kArgumentRequired, kDeviceOption_Spake2pVerifierBase64 }, { "spake2p-salt-base64", kArgumentRequired, kDeviceOption_Spake2pSaltBase64 }, { "spake2p-iterations", kArgumentRequired, kDeviceOption_Spake2pIterations }, #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE || CHIP_DEVICE_ENABLE_PORT_PARAMS { "secured-device-port", kArgumentRequired, kDeviceOption_SecuredDevicePort }, { "unsecured-commissioner-port", kArgumentRequired, kDeviceOption_UnsecuredCommissionerPort }, #endif #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE { "secured-commissioner-port", kArgumentRequired, kDeviceOption_SecuredCommissionerPort }, { "commissioner-fabric-id", kArgumentRequired, kCommissionerOption_FabricID }, #endif { "command", kArgumentRequired, kDeviceOption_Command }, { "PICS", kArgumentRequired, kDeviceOption_PICS }, { "KVS", kArgumentRequired, kDeviceOption_KVS }, { "interface-id", kArgumentRequired, kDeviceOption_InterfaceId }, #if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED { "trace_file", kArgumentRequired, kDeviceOption_TraceFile }, { "trace_log", kArgumentRequired, kDeviceOption_TraceLog }, { "trace_decode", kArgumentRequired, kDeviceOption_TraceDecode }, #endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS { "commissioning-arl-entries", kArgumentRequired, kDeviceOption_CommissioningArlEntries }, { "arl-entries", kArgumentRequired, kDeviceOption_ArlEntries }, #endif // CHIP_CONFIG_USE_ACCESS_RESTRICTIONS { "cert_error_csr_incorrect_type", kNoArgument, kOptionCSRResponseCSRIncorrectType }, { "cert_error_csr_existing_keypair", kNoArgument, kOptionCSRResponseCSRExistingKeyPair }, { "cert_error_csr_nonce_incorrect_type", kNoArgument, kOptionCSRResponseCSRNonceIncorrectType }, { "cert_error_csr_nonce_too_long", kNoArgument, kOptionCSRResponseCSRNonceTooLong }, { "cert_error_csr_nonce_invalid", kNoArgument, kOptionCSRResponseCSRNonceInvalid }, { "cert_error_nocsrelements_too_long", kNoArgument, kOptionCSRResponseNOCSRElementsTooLong }, { "cert_error_attestation_signature_incorrect_type", kNoArgument, kOptionCSRResponseAttestationSignatureIncorrectType }, { "cert_error_attestation_signature_invalid", kNoArgument, kOptionCSRResponseAttestationSignatureInvalid }, { "enable-key", kArgumentRequired, kDeviceOption_TestEventTriggerEnableKey }, #if ENABLE_TRACING { "trace-to", kArgumentRequired, kTraceTo }, #endif { "simulate-no-internal-time", kNoArgument, kOptionSimulateNoInternalTime }, #if defined(PW_RPC_ENABLED) { "rpc-server-port", kArgumentRequired, kOptionRpcServerPort }, #endif #if CONFIG_BUILD_FOR_HOST_UNIT_TEST { "subscription-capacity", kArgumentRequired, kDeviceOption_SubscriptionCapacity }, { "subscription-resumption-retry-interval", kArgumentRequired, kDeviceOption_SubscriptionResumptionRetryIntervalSec }, #endif #if CHIP_WITH_NLFAULTINJECTION { "faults", kArgumentRequired, kDeviceOption_FaultInjection }, #endif {} }; const char * sDeviceOptionHelp = #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE " --ble-device \n" " The device number for CHIPoBLE, without 'hci' prefix, can be found by hciconfig.\n" #endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE #if CHIP_DEVICE_CONFIG_ENABLE_WPA "\n" " --wifi\n" " Enable Wi-Fi management via wpa_supplicant.\n" #endif // CHIP_DEVICE_CONFIG_ENABLE_WPA #if CHIP_DEVICE_CONFIG_ENABLE_WIFI "\n" " --wifi-supports-5g\n" " Indicate that local Wi-Fi hardware should report 5GHz support.\n" #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF "\n" " --wifipaf freq_list=,... \n" " Enable Wi-Fi PAF via wpa_supplicant.\n" " Give an empty string if not setting freq_list: \"\"\n" #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFIPAFs #if CHIP_ENABLE_OPENTHREAD "\n" " --thread\n" " Enable Thread management via ot-agent.\n" #endif // CHIP_ENABLE_OPENTHREAD "\n" " --version \n" " The version indication provides versioning of the setup payload.\n" "\n" " --vendor-id \n" " The Vendor ID is assigned by the Connectivity Standards Alliance.\n" "\n" " --product-id \n" " The Product ID is specified by vendor.\n" "\n" " --custom-flow \n" " A 2-bit unsigned enumeration specifying manufacturer-specific custom flow options.\n" "\n" " --capabilities \n" " Discovery Capabilities Bitmask which contains information about Device’s available technologies for device discovery.\n" "\n" " --discriminator \n" " A 12-bit unsigned integer match the value which a device advertises during commissioning.\n" "\n" " --passcode \n" " A 27-bit unsigned integer, which serves as proof of possession during commissioning. \n" " If not provided to compute a verifier, the --spake2p-verifier-base64 must be provided. \n" "\n" " --spake2p-verifier-base64 \n" " A raw concatenation of 'W0' and 'L' (67 bytes) as base64 to override the verifier\n" " auto-computed from the passcode, if provided.\n" "\n" " --spake2p-salt-base64 \n" " 16-32 bytes of salt to use for the PASE verifier, as base64. If omitted, will be generated\n" " randomly. If a --spake2p-verifier-base64 is passed, it must match against the salt otherwise\n" " failure will arise.\n" "\n" " --spake2p-iterations \n" " Number of PBKDF iterations to use. If omitted, will be 1000. If a --spake2p-verifier-base64 is\n" " passed, the iteration counts must match that used to generate the verifier otherwise failure will\n" " arise.\n" "\n" #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE || CHIP_DEVICE_ENABLE_PORT_PARAMS " --secured-device-port \n" " A 16-bit unsigned integer specifying the listen port to use for secure device messages (default is 5540).\n" "\n" " --unsecured-commissioner-port \n" " A 16-bit unsigned integer specifying the port to use for unsecured commissioner messages (default is 5550).\n" "\n" #endif #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE " --secured-commissioner-port \n" " A 16-bit unsigned integer specifying the listen port to use for secure commissioner messages (default is 5552). Only " "valid when app is both device and commissioner\n" "\n" " --commissioner-fabric-id \n" " The fabric ID to be used when this device is a commissioner (default in code is 1).\n" "\n" #endif " --command \n" " A name for a command to execute during startup.\n" "\n" " --PICS \n" " A file containing PICS items.\n" "\n" " --KVS \n" " A file to store Key Value Store items.\n" "\n" " --interface-id \n" " A interface id to advertise on.\n" #if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED "\n" " --trace_file \n" " Output trace data to the provided file.\n" " --trace_log <1/0>\n" " A value of 1 enables traces to go to the log, 0 disables this (default 0).\n" " --trace_decode <1/0>\n" " A value of 1 enables traces decoding, 0 disables this (default 0).\n" #endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS " --commissioning-arl-entries \n" " Enable ACL cluster access restrictions used during commissioning with the provided JSON. Example:\n" " \"[{\\\"endpoint\\\": 1,\\\"cluster\\\": 1105,\\\"restrictions\\\": [{\\\"type\\\": 0,\\\"id\\\": 0}]}]\"\n" " --arl-entries \n" " Enable ACL cluster access restrictions applied to fabric index 1 with the provided JSON. Example:\n" " \"[{\\\"endpoint\\\": 1,\\\"cluster\\\": 1105,\\\"restrictions\\\": [{\\\"type\\\": 0,\\\"id\\\": 0}]}]\"\n" #endif // CHIP_CONFIG_USE_ACCESS_RESTRICTIONS " --cert_error_csr_incorrect_type\n" " Configure the CSRResponse to be built with an invalid CSR type.\n" " --cert_error_csr_existing_keypair\n" " Configure the CSRResponse to be built with a CSR where the keypair already exists.\n" " --cert_error_csr_nonce_incorrect_type\n" " Configure the CSRResponse to be built with an invalid CSRNonce type.\n" " --cert_error_csr_nonce_too_long\n" " Configure the CSRResponse to be built with a CSRNonce that is longer than expected.\n" " --cert_error_csr_nonce_invalid\n" " Configure the CSRResponse to be built with a CSRNonce that does not match the CSRNonce from the CSRRequest.\n" " --cert_error_nocsrelements_too_long\n" " Configure the CSRResponse to contains an NOCSRElements larger than the allowed RESP_MAX.\n" " --cert_error_attestation_signature_incorrect_type\n" " Configure the CSRResponse to be build with an invalid AttestationSignature type.\n" " --cert_error_attestation_signature_invalid\n" " Configure the CSRResponse to be build with an AttestationSignature that does not match what is expected.\n" " --enable-key \n" " A 16-byte, hex-encoded key, used to validate TestEventTrigger command of Generial Diagnostics cluster\n" #if ENABLE_TRACING " --trace-to \n" " Trace destinations, comma separated (" SUPPORTED_COMMAND_LINE_TRACING_TARGETS ")\n" #endif " --simulate-no-internal-time\n" " Time cluster does not use internal platform time\n" #if defined(PW_RPC_ENABLED) " --rpc-server-port\n" " Start RPC server on specified port\n" #endif #if CONFIG_BUILD_FOR_HOST_UNIT_TEST " --subscription-capacity\n" " Max number of subscriptions the device will allow\n" " --subscription-resumption-retry-interval\n" " subscription timeout resumption retry interval in seconds\n" #endif #if CHIP_WITH_NLFAULTINJECTION " --faults \n" " Inject specified fault(s) at runtime.\n" #endif "\n"; #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS bool ParseAccessRestrictionEntriesFromJson(const char * jsonString, std::vector & entries) { Json::Value root; Json::Reader reader; VerifyOrReturnValue(reader.parse(jsonString, root), false); for (Json::Value::const_iterator eIt = root.begin(); eIt != root.end(); eIt++) { AccessRestrictionProvider::Entry entry; entry.endpointNumber = static_cast((*eIt)["endpoint"].asUInt()); entry.clusterId = static_cast((*eIt)["cluster"].asUInt()); Json::Value restrictions = (*eIt)["restrictions"]; for (Json::Value::const_iterator rIt = restrictions.begin(); rIt != restrictions.end(); rIt++) { AccessRestrictionProvider::Restriction restriction; restriction.restrictionType = static_cast((*rIt)["type"].asUInt()); if ((*rIt).isMember("id")) { restriction.id.SetValue((*rIt)["id"].asUInt()); } entry.restrictions.push_back(restriction); } entries.push_back(entry); } return true; } #endif // CHIP_CONFIG_USE_ACCESS_RESTRICTIONS bool Base64ArgToVector(const char * arg, size_t maxSize, std::vector & outVector) { size_t maxBase64Size = BASE64_ENCODED_LEN(maxSize); outVector.resize(maxSize); size_t argLen = strlen(arg); VerifyOrReturnValue(argLen <= maxBase64Size, false); VerifyOrReturnValue(chip::CanCastTo(argLen), false); size_t decodedLen = chip::Base64Decode32(arg, static_cast(argLen), reinterpret_cast(outVector.data())); VerifyOrReturnValue(decodedLen != 0, false); outVector.resize(decodedLen); return true; } bool HandleOption(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue) { bool retval = true; switch (aIdentifier) { case kDeviceOption_BleDevice: if (!ParseInt(aValue, LinuxDeviceOptions::GetInstance().mBleDevice)) { PrintArgError("%s: invalid value specified for ble device number: %s\n", aProgram, aValue); retval = false; } break; case kDeviceOption_WiFi: LinuxDeviceOptions::GetInstance().mWiFi = true; break; case kDeviceOption_WiFiSupports5g: LinuxDeviceOptions::GetInstance().wifiSupports5g = true; break; case kDeviceOption_Thread: LinuxDeviceOptions::GetInstance().mThread = true; break; case kDeviceOption_Version: LinuxDeviceOptions::GetInstance().payload.version = static_cast(strtoul(aValue, nullptr, 0)); break; case kDeviceOption_VendorID: LinuxDeviceOptions::GetInstance().payload.vendorID = static_cast(strtoul(aValue, nullptr, 0)); break; case kDeviceOption_ProductID: LinuxDeviceOptions::GetInstance().payload.productID = static_cast(strtoul(aValue, nullptr, 0)); break; case kDeviceOption_CustomFlow: LinuxDeviceOptions::GetInstance().payload.commissioningFlow = static_cast(strtoul(aValue, nullptr, 0)); break; case kDeviceOption_Capabilities: LinuxDeviceOptions::GetInstance().payload.rendezvousInformation.Emplace().SetRaw( static_cast(strtoul(aValue, nullptr, 0))); break; case kDeviceOption_Discriminator: { uint16_t value = static_cast(strtoul(aValue, nullptr, 0)); if (value >= 4096) { PrintArgError("%s: invalid value specified for discriminator: %s\n", aProgram, aValue); retval = false; } else { LinuxDeviceOptions::GetInstance().discriminator.SetValue(value); } break; } case kDeviceOption_Passcode: LinuxDeviceOptions::GetInstance().payload.setUpPINCode = static_cast(strtoul(aValue, nullptr, 0)); break; case kDeviceOption_Spake2pSaltBase64: { constexpr size_t kMaxSize = chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length; std::vector saltVector; bool success = Base64ArgToVector(aValue, kMaxSize, saltVector); if (!success) { PrintArgError("%s: ERROR: Base64 format for argument %s was invalid\n", aProgram, aName); retval = false; break; } if ((saltVector.size() < chip::Crypto::kSpake2p_Min_PBKDF_Salt_Length) || (saltVector.size() > chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length)) { PrintArgError("%s: ERROR: argument %s not in range [%u, %u]\n", aProgram, aName, chip::Crypto::kSpake2p_Min_PBKDF_Salt_Length, chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length); retval = false; break; } LinuxDeviceOptions::GetInstance().spake2pSalt.SetValue(std::move(saltVector)); break; } case kDeviceOption_Spake2pVerifierBase64: { constexpr size_t kMaxSize = chip::Crypto::kSpake2p_VerifierSerialized_Length; std::vector serializedVerifier; bool success = Base64ArgToVector(aValue, kMaxSize, serializedVerifier); if (!success) { PrintArgError("%s: ERROR: Base64 format for argument %s was invalid\n", aProgram, aName); retval = false; break; } if (serializedVerifier.size() != chip::Crypto::kSpake2p_VerifierSerialized_Length) { PrintArgError("%s: ERROR: argument %s should contain base64 for a %u bytes octet string \n", aProgram, aName, chip::Crypto::kSpake2p_VerifierSerialized_Length); retval = false; break; } LinuxDeviceOptions::GetInstance().spake2pVerifier.SetValue(std::move(serializedVerifier)); break; } case kDeviceOption_Spake2pIterations: { errno = 0; uint32_t iterCount = static_cast(strtoul(aValue, nullptr, 0)); if (errno == ERANGE) { PrintArgError("%s: ERROR: argument %s was not parsable as an integer\n", aProgram, aName); retval = false; break; } if ((iterCount < chip::Crypto::kSpake2p_Min_PBKDF_Iterations) || (iterCount > chip::Crypto::kSpake2p_Max_PBKDF_Iterations)) { PrintArgError("%s: ERROR: argument %s not in range [%u, %u]\n", aProgram, aName, chip::Crypto::kSpake2p_Min_PBKDF_Iterations, chip::Crypto::kSpake2p_Max_PBKDF_Iterations); retval = false; break; } LinuxDeviceOptions::GetInstance().spake2pIterations = iterCount; break; } #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE || CHIP_DEVICE_ENABLE_PORT_PARAMS case kDeviceOption_SecuredDevicePort: LinuxDeviceOptions::GetInstance().securedDevicePort = static_cast(atoi(aValue)); break; case kDeviceOption_UnsecuredCommissionerPort: LinuxDeviceOptions::GetInstance().unsecuredCommissionerPort = static_cast(atoi(aValue)); break; #endif #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE case kDeviceOption_SecuredCommissionerPort: LinuxDeviceOptions::GetInstance().securedCommissionerPort = static_cast(atoi(aValue)); break; case kCommissionerOption_FabricID: LinuxDeviceOptions::GetInstance().commissionerFabricId = static_cast(strtoull(aValue, nullptr, 0)); break; #endif case kDeviceOption_Command: LinuxDeviceOptions::GetInstance().command = aValue; break; case kDeviceOption_PICS: LinuxDeviceOptions::GetInstance().PICS = aValue; break; case kDeviceOption_KVS: LinuxDeviceOptions::GetInstance().KVS = aValue; break; case kDeviceOption_InterfaceId: LinuxDeviceOptions::GetInstance().interfaceId = Inet::InterfaceId(static_cast(atoi(aValue))); break; #if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED case kDeviceOption_TraceFile: LinuxDeviceOptions::GetInstance().traceStreamFilename.SetValue(std::string{ aValue }); break; case kDeviceOption_TraceLog: if (atoi(aValue) != 0) { LinuxDeviceOptions::GetInstance().traceStreamToLogEnabled = true; } break; case kDeviceOption_TraceDecode: if (atoi(aValue) != 0) { LinuxDeviceOptions::GetInstance().traceStreamDecodeEnabled = true; } break; #endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS // TODO(#35189): change to use a path to JSON files instead case kDeviceOption_CommissioningArlEntries: { std::vector entries; retval = ParseAccessRestrictionEntriesFromJson(aValue, entries); if (retval) { LinuxDeviceOptions::GetInstance().commissioningArlEntries.SetValue(std::move(entries)); } } break; case kDeviceOption_ArlEntries: { std::vector entries; retval = ParseAccessRestrictionEntriesFromJson(aValue, entries); if (retval) { LinuxDeviceOptions::GetInstance().arlEntries.SetValue(std::move(entries)); } } break; #endif // CHIP_CONFIG_USE_ACCESS_RESTRICTIONS case kOptionCSRResponseCSRIncorrectType: LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrIncorrectType = true; break; case kOptionCSRResponseCSRExistingKeyPair: LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrExistingKeyPair = true; break; case kOptionCSRResponseCSRNonceIncorrectType: LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrNonceIncorrectType = true; break; case kOptionCSRResponseCSRNonceTooLong: LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrNonceTooLong = true; break; case kOptionCSRResponseCSRNonceInvalid: LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrNonceInvalid = true; break; case kOptionCSRResponseNOCSRElementsTooLong: LinuxDeviceOptions::GetInstance().mCSRResponseOptions.nocsrElementsTooLong = true; break; case kOptionCSRResponseAttestationSignatureIncorrectType: LinuxDeviceOptions::GetInstance().mCSRResponseOptions.attestationSignatureIncorrectType = true; break; case kOptionCSRResponseAttestationSignatureInvalid: LinuxDeviceOptions::GetInstance().mCSRResponseOptions.attestationSignatureInvalid = true; break; case kDeviceOption_TestEventTriggerEnableKey: { constexpr size_t kEnableKeyLength = sizeof(LinuxDeviceOptions::GetInstance().testEventTriggerEnableKey); if (Encoding::HexToBytes(aValue, strlen(aValue), LinuxDeviceOptions::GetInstance().testEventTriggerEnableKey, kEnableKeyLength) != kEnableKeyLength) { PrintArgError("%s: ERROR: invalid value specified for %s\n", aProgram, aName); retval = false; } break; } #if ENABLE_TRACING case kTraceTo: LinuxDeviceOptions::GetInstance().traceTo.push_back(aValue); break; #endif case kOptionSimulateNoInternalTime: LinuxDeviceOptions::GetInstance().mSimulateNoInternalTime = true; break; #if defined(PW_RPC_ENABLED) case kOptionRpcServerPort: LinuxDeviceOptions::GetInstance().rpcServerPort = static_cast(atoi(aValue)); break; #endif #if CONFIG_BUILD_FOR_HOST_UNIT_TEST case kDeviceOption_SubscriptionCapacity: LinuxDeviceOptions::GetInstance().subscriptionCapacity = static_cast(atoi(aValue)); break; case kDeviceOption_SubscriptionResumptionRetryIntervalSec: LinuxDeviceOptions::GetInstance().subscriptionResumptionRetryIntervalSec = static_cast(atoi(aValue)); break; #endif #if CHIP_WITH_NLFAULTINJECTION case kDeviceOption_FaultInjection: { constexpr nl::FaultInjection::GetManagerFn faultManagerFns[] = { FaultInjection::GetManager, Inet::FaultInjection::GetManager, System::FaultInjection::GetManager }; Platform::ScopedMemoryString mutableArg(aValue, strlen(aValue)); // ParseFaultInjectionStr may mutate if (!nl::FaultInjection::ParseFaultInjectionStr(mutableArg.Get(), faultManagerFns, ArraySize(faultManagerFns))) { PrintArgError("%s: Invalid fault injection specification\n", aProgram); retval = false; } break; } #endif #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF case kDeviceOption_WiFi_PAF: { LinuxDeviceOptions::GetInstance().mWiFiPAF = true; LinuxDeviceOptions::GetInstance().mWiFiPAFExtCmds = aValue; break; } #endif default: PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName); retval = false; break; } return (retval); } OptionSet sDeviceOptions = { HandleOption, sDeviceOptionDefs, "GENERAL OPTIONS", sDeviceOptionHelp }; OptionSet * sLinuxDeviceOptionSets[] = { &sDeviceOptions, nullptr, nullptr, nullptr }; } // namespace CHIP_ERROR ParseArguments(int argc, char * const argv[], OptionSet * customOptions) { // Index 0 is for the general Linux options uint8_t optionSetIndex = 1; if (customOptions != nullptr) { // If there are custom options, include it during arg parsing sLinuxDeviceOptionSets[optionSetIndex++] = customOptions; } char usage[kAppUsageLength]; snprintf(usage, kAppUsageLength, "Usage: %s [options]", argv[0]); HelpOptions helpOptions(argv[0], usage, "1.0"); sLinuxDeviceOptionSets[optionSetIndex] = &helpOptions; if (!ParseArgs(argv[0], argc, argv, sLinuxDeviceOptionSets)) { return CHIP_ERROR_INVALID_ARGUMENT; } return CHIP_NO_ERROR; } LinuxDeviceOptions & LinuxDeviceOptions::GetInstance() { if (gDeviceOptions.dacProvider == nullptr) { gDeviceOptions.dacProvider = chip::Credentials::Examples::GetExampleDACProvider(); } return gDeviceOptions; }