diff --git a/examples/all-clusters-app/esp32/main/main.cpp b/examples/all-clusters-app/esp32/main/main.cpp index e4d52a609c8597..051f9f5cba0bf9 100644 --- a/examples/all-clusters-app/esp32/main/main.cpp +++ b/examples/all-clusters-app/esp32/main/main.cpp @@ -338,7 +338,7 @@ class SetupListModel : public ListScreen::Model } else if (i == 2) { - app::Mdns::AdvertiseCommisionable(); + app::Mdns::AdvertiseCommissionableNode(); OpenDefaultPairingWindow(ResetAdmins::kNo, PairingWindowAdvertisement::kMdns); } } diff --git a/examples/lighting-app/linux/BUILD.gn b/examples/lighting-app/linux/BUILD.gn index 31e7c165e94aef..e7348bd8240eee 100644 --- a/examples/lighting-app/linux/BUILD.gn +++ b/examples/lighting-app/linux/BUILD.gn @@ -31,6 +31,7 @@ config("includes") { executable("chip-lighting-app") { sources = [ "LightingManager.cpp", + "include/CHIPProjectAppConfig.h", "include/LightingManager.h", "main.cpp", ] diff --git a/examples/lighting-app/linux/args.gni b/examples/lighting-app/linux/args.gni index 311ddab32d5fe5..22c26955822720 100644 --- a/examples/lighting-app/linux/args.gni +++ b/examples/lighting-app/linux/args.gni @@ -12,6 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. +# CHIPProjectConfig.h + import("//build_overrides/chip.gni") import("${chip_root}/config/standalone/args.gni") + +chip_device_project_config_include = "" +chip_project_config_include = "" +chip_system_project_config_include = "" + +chip_project_config_include_dirs = + [ "${chip_root}/examples/lighting-app/linux/include" ] +chip_project_config_include_dirs += [ "${chip_root}/config/standalone" ] diff --git a/examples/lighting-app/linux/include/CHIPProjectAppConfig.h b/examples/lighting-app/linux/include/CHIPProjectAppConfig.h new file mode 100644 index 00000000000000..bdb071b1f12639 --- /dev/null +++ b/examples/lighting-app/linux/include/CHIPProjectAppConfig.h @@ -0,0 +1,43 @@ +/* + * + * 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. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once + +// include the CHIPProjectConfig from config/standalone +#include + +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY 0 + +#define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 1 + +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_TYPE 1 + +#define CHIP_DEVICE_CONFIG_DEVICE_TYPE 257 // 0x0101 = 257 = Dimmable Bulb + +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_NAME 1 + +#define CHIP_DEVICE_CONFIG_DEVICE_NAME "Test Bulb" diff --git a/examples/minimal-mdns/README.md b/examples/minimal-mdns/README.md index 8949e8ba6e15e8..a1f510d8178c2c 100644 --- a/examples/minimal-mdns/README.md +++ b/examples/minimal-mdns/README.md @@ -62,7 +62,11 @@ Example runs: ``` ```sh -./out/minimal_mdns/mdns-advertiser -4 -m commisioning --vendor-id 123 --product-id 456 +./out/minimal_mdns/mdns-advertiser -4 -m commissionable-node --vendor-id 123 --product-id 456 +``` + +```sh +./out/minimal_mdns/mdns-advertiser -4 -m commissioner --vendor-id 123 --product-id 456 --device-type 35 ``` see diff --git a/examples/minimal-mdns/advertiser.cpp b/examples/minimal-mdns/advertiser.cpp index 4fa67929fced96..bdacbccafe31c5 100644 --- a/examples/minimal-mdns/advertiser.cpp +++ b/examples/minimal-mdns/advertiser.cpp @@ -32,25 +32,30 @@ namespace { enum class AdvertisingMode { - kCommisioning, + kCommissionableNode, kOperational, - kCommisionable, + kCommissioner, }; struct Options { bool enableIpV4 = false; - AdvertisingMode advertisingMode = AdvertisingMode::kCommisioning; + AdvertisingMode advertisingMode = AdvertisingMode::kCommissionableNode; - // commisioning/commisionable params - uint8_t shortDiscriminator = 52; - uint16_t longDiscriminator = 840; + // commissionable node / commissioner params Optional vendorId; Optional productId; - - // commisionable params + Optional deviceType; + Optional deviceName; + + // commisionable node params + uint8_t shortDiscriminator = 52; + uint16_t longDiscriminator = 840; + bool commissioningMode = false; + bool commissioningModeOpenWindow = false; + Optional rotatingId; Optional pairingInstr; - Optional pairingHint; + Optional pairingHint; // operational params uint64_t fabricId = 12345; @@ -70,6 +75,11 @@ constexpr uint16_t kOptionCommisioningVendorId = 0x100; // v is used b constexpr uint16_t kOptionCommisioningProductId = 'p'; constexpr uint16_t kOptionCommisioningPairingInstr = 0x200; // Just use the long format constexpr uint16_t kOptionCommisioningPairingHint = 0x300; +constexpr uint16_t kOptionCommisioningDeviceType = 0x400; +constexpr uint16_t kOptionCommisioningDeviceName = 0x500; +constexpr uint16_t kOptionCommisioningMode = 0x600; +constexpr uint16_t kOptionCommisioningModeOpenWindow = 0x700; +constexpr uint16_t kOptionCommisioningRotatingId = 0x800; constexpr uint16_t kOptionOperationalFabricId = 'f'; constexpr uint16_t kOptionOperationalNodeId = 'n'; @@ -86,13 +96,13 @@ bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier, { gOptions.advertisingMode = AdvertisingMode::kOperational; } - else if (strcmp(aValue, "commisioning") == 0) + else if (strcmp(aValue, "commissionable-node") == 0) { - gOptions.advertisingMode = AdvertisingMode::kCommisioning; + gOptions.advertisingMode = AdvertisingMode::kCommissionableNode; } - else if (strcmp(aValue, "commisionable") == 0) + else if (strcmp(aValue, "commissioner") == 0) { - gOptions.advertisingMode = AdvertisingMode::kCommisionable; + gOptions.advertisingMode = AdvertisingMode::kCommissioner; } else { @@ -113,11 +123,26 @@ bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier, case kOptionCommisioningProductId: gOptions.productId = Optional::Value(static_cast(atoi(aValue))); return true; + case kOptionCommisioningMode: + gOptions.commissioningMode = true; + return true; + case kOptionCommisioningModeOpenWindow: + gOptions.commissioningModeOpenWindow = true; + return true; + case kOptionCommisioningDeviceType: + gOptions.deviceType = Optional::Value(static_cast(atoi(aValue))); + return true; + case kOptionCommisioningDeviceName: + gOptions.deviceName = Optional::Value(static_cast(aValue)); + return true; + case kOptionCommisioningRotatingId: + gOptions.rotatingId = Optional::Value(static_cast(aValue)); + return true; case kOptionCommisioningPairingInstr: gOptions.pairingInstr = Optional::Value(static_cast(aValue)); return true; case kOptionCommisioningPairingHint: - gOptions.pairingHint = Optional::Value(static_cast(atoi(aValue))); + gOptions.pairingHint = Optional::Value(static_cast(atoi(aValue))); return true; case kOptionOperationalFabricId: if (sscanf(aValue, "%" SCNx64, &gOptions.fabricId) != 1) @@ -149,6 +174,11 @@ OptionDef cmdLineOptionsDef[] = { { "long-discriminator", kArgumentRequired, kOptionCommisioningLongDiscriminaotr }, { "vendor-id", kArgumentRequired, kOptionCommisioningVendorId }, { "product-id", kArgumentRequired, kOptionCommisioningProductId }, + { "commissioning-mode-enabled", kNoArgument, kOptionCommisioningMode }, + { "commissioning-mode-open-window", kNoArgument, kOptionCommisioningModeOpenWindow }, + { "device-type", kArgumentRequired, kOptionCommisioningDeviceType }, + { "device-name", kArgumentRequired, kOptionCommisioningDeviceName }, + { "rotating-id", kArgumentRequired, kOptionCommisioningRotatingId }, { "pairing-instruction", kArgumentRequired, kOptionCommisioningPairingInstr }, { "pairing-hint", kArgumentRequired, kOptionCommisioningPairingHint }, @@ -165,7 +195,7 @@ OptionSet cmdLineOptions = { HandleOptions, cmdLineOptionsDef, "PROGRAM OPTIONS" #endif " -m \n" " --advertising-mode \n" - " Advertise in this mode (operational or commisioning or commisionable).\n" + " Advertise in this mode (operational or commissionable-node or commissioner).\n" " --short-discriminator \n" " -s \n" " Commisioning/commisionable short discriminator.\n" @@ -177,6 +207,16 @@ OptionSet cmdLineOptions = { HandleOptions, cmdLineOptionsDef, "PROGRAM OPTIONS" " --product-id \n" " -p \n" " Commisioning/commisionable product id.\n" + " --commissioning-mode-enabled\n" + " Commissioning Mode Enabled.\n" + " --commissioning-mode-open-window\n" + " Commissioning Mode as a result of Open Commissioning Window.\n" + " --device-type \n" + " Device type id.\n" + " --device-name \n" + " Name of device.\n" + " --rotating-id \n" + " Rotating Id.\n" " --pairing-instruction \n" " Commisionable pairing instruction.\n" " --pairing-hint \n" @@ -222,16 +262,24 @@ int main(int argc, char ** args) CHIP_ERROR err; - if (gOptions.advertisingMode == AdvertisingMode::kCommisioning) + if (gOptions.advertisingMode == AdvertisingMode::kCommissionableNode) { - err = chip::Mdns::ServiceAdvertiser::Instance().Advertise(chip::Mdns::CommissionAdvertisingParameters() - .EnableIpV4(gOptions.enableIpV4) - .SetPort(CHIP_PORT) - .SetShortDiscriminator(gOptions.shortDiscriminator) - .SetLongDiscrimininator(gOptions.longDiscriminator) - .SetMac(chip::ByteSpan(gOptions.mac, 6)) - .SetVendorId(gOptions.vendorId) - .SetProductId(gOptions.productId)); + printf("Advertise Commissionable Node\n"); + err = chip::Mdns::ServiceAdvertiser::Instance().Advertise( + chip::Mdns::CommissionAdvertisingParameters() + .EnableIpV4(gOptions.enableIpV4) + .SetPort(CHIP_PORT) + .SetShortDiscriminator(gOptions.shortDiscriminator) + .SetLongDiscrimininator(gOptions.longDiscriminator) + .SetMac(chip::ByteSpan(gOptions.mac, 6)) + .SetVendorId(gOptions.vendorId) + .SetProductId(gOptions.productId) + .SetCommissioningMode(gOptions.commissioningMode, gOptions.commissioningModeOpenWindow) + .SetDeviceType(gOptions.deviceType) + .SetDeviceName(gOptions.deviceName) + .SetRotatingId(gOptions.rotatingId) + .SetPairingInstr(gOptions.pairingInstr) + .SetPairingHint(gOptions.pairingHint)); } else if (gOptions.advertisingMode == AdvertisingMode::kOperational) { @@ -242,19 +290,19 @@ int main(int argc, char ** args) .SetMac(chip::ByteSpan(gOptions.mac, 6)) .SetPeerId(PeerId().SetFabricId(gOptions.fabricId).SetNodeId(gOptions.nodeId))); } - else if (gOptions.advertisingMode == AdvertisingMode::kCommisionable) + else if (gOptions.advertisingMode == AdvertisingMode::kCommissioner) { + printf("Advertise Commissioner\n"); err = chip::Mdns::ServiceAdvertiser::Instance().Advertise( chip::Mdns::CommissionAdvertisingParameters() .EnableIpV4(gOptions.enableIpV4) .SetPort(CHIP_PORT) - .SetShortDiscriminator(gOptions.shortDiscriminator) - .SetLongDiscrimininator(gOptions.longDiscriminator) + .SetMac(chip::ByteSpan(gOptions.mac, 6)) .SetVendorId(gOptions.vendorId) .SetProductId(gOptions.productId) - .SetPairingInstr(gOptions.pairingInstr) - .SetPairingHint(gOptions.pairingHint) - .SetCommissionAdvertiseMode(chip::Mdns::CommssionAdvertiseMode::kCommissionable)); + .SetDeviceType(gOptions.deviceType) + .SetDeviceName(gOptions.deviceName) + .SetCommissionAdvertiseMode(chip::Mdns::CommssionAdvertiseMode::kCommissioner)); } else { @@ -264,7 +312,7 @@ int main(int argc, char ** args) if (err != CHIP_NO_ERROR) { - fprintf(stderr, "FAILED to setup advertisement parameters\n"); + fprintf(stderr, "FAILED to setup advertisement parameters err=%s\n", chip::ErrorStr(err)); return 1; } diff --git a/examples/tv-app/linux/BUILD.gn b/examples/tv-app/linux/BUILD.gn index 259651bf8cb744..0a1b7cc7ed11a6 100644 --- a/examples/tv-app/linux/BUILD.gn +++ b/examples/tv-app/linux/BUILD.gn @@ -21,6 +21,7 @@ assert(chip_build_tools) executable("chip-tv-app") { sources = [ + "${chip_root}/examples/tv-app/tv-common/include/CHIPProjectAppConfig.h", "include/account-login/AccountLoginManager.cpp", "include/account-login/AccountLoginManager.h", "include/application-basic/ApplicationBasicManager.cpp", diff --git a/examples/tv-app/linux/args.gni b/examples/tv-app/linux/args.gni index 311ddab32d5fe5..98a1f6a5c5e5cb 100644 --- a/examples/tv-app/linux/args.gni +++ b/examples/tv-app/linux/args.gni @@ -15,3 +15,11 @@ import("//build_overrides/chip.gni") import("${chip_root}/config/standalone/args.gni") + +chip_device_project_config_include = "" +chip_project_config_include = "" +chip_system_project_config_include = "" + +chip_project_config_include_dirs = + [ "${chip_root}/examples/tv-app/tv-common/include" ] +chip_project_config_include_dirs += [ "${chip_root}/config/standalone" ] diff --git a/examples/tv-app/tv-common/include/CHIPProjectAppConfig.h b/examples/tv-app/tv-common/include/CHIPProjectAppConfig.h new file mode 100644 index 00000000000000..4eb90951c175f8 --- /dev/null +++ b/examples/tv-app/tv-common/include/CHIPProjectAppConfig.h @@ -0,0 +1,43 @@ +/* + * + * 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. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once + +// include the CHIPProjectConfig from config/standalone +#include + +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY 1 + +#define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 1 + +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_TYPE 1 + +#define CHIP_DEVICE_CONFIG_DEVICE_TYPE 35 // 0x0023 = 35 = Video Player + +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_NAME 1 + +#define CHIP_DEVICE_CONFIG_DEVICE_NAME "Test TV" diff --git a/src/app/server/Mdns.cpp b/src/app/server/Mdns.cpp index 846b74f26a5c98..5af680afaf9726 100644 --- a/src/app/server/Mdns.cpp +++ b/src/app/server/Mdns.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -114,10 +115,33 @@ CHIP_ERROR AdvertiseOperational() return mdnsAdvertiser.Advertise(advertiseParameters); } -/// Set MDNS commisioning advertisement -CHIP_ERROR AdvertiseCommisionable() +/// Set MDNS commissioner advertisement +CHIP_ERROR AdvertiseCommisioner() +{ + return Advertise(false); +} + +/// Set MDNS commissionable node advertisement +CHIP_ERROR AdvertiseCommissionableNode() +{ + return Advertise(true); +} + +/// commissionableNode +// CHIP_ERROR Advertise(chip::Mdns::CommssionAdvertiseMode mode) +CHIP_ERROR Advertise(bool commissionableNode) { auto advertiseParameters = chip::Mdns::CommissionAdvertisingParameters().SetPort(CHIP_PORT).EnableIpV4(true); + advertiseParameters.SetCommissionAdvertiseMode(commissionableNode ? chip::Mdns::CommssionAdvertiseMode::kCommissionableNode + : chip::Mdns::CommssionAdvertiseMode::kCommissioner); + + // TODO: device can re-enter commissioning mode after being fully provisioned + // (additionalPairing == true) + bool notYetCommissioned = !DeviceLayer::ConfigurationMgr().IsFullyProvisioned(); + bool additionalPairing = false; + advertiseParameters.SetCommissioningMode(notYetCommissioned, additionalPairing); + + char pairingInst[chip::Mdns::kKeyPairingInstructionMaxLength + 1]; uint8_t mac[8]; advertiseParameters.SetMac(FillMAC(mac)); @@ -148,6 +172,66 @@ CHIP_ERROR AdvertiseCommisionable() } advertiseParameters.SetShortDiscriminator(static_cast(value & 0xFF)).SetLongDiscrimininator(value); + if (DeviceLayer::ConfigurationMgr().IsCommissionableDeviceTypeEnabled() && + DeviceLayer::ConfigurationMgr().GetDeviceType(value) == CHIP_NO_ERROR) + { + advertiseParameters.SetDeviceType(chip::Optional::Value(value)); + } + + char deviceName[chip::Mdns::kKeyDeviceNameMaxLength + 1]; + if (DeviceLayer::ConfigurationMgr().IsCommissionableDeviceNameEnabled() && + DeviceLayer::ConfigurationMgr().GetDeviceName(deviceName, sizeof(deviceName)) == CHIP_NO_ERROR) + { + advertiseParameters.SetDeviceName(chip::Optional::Value(deviceName)); + } + +#if CHIP_ENABLE_ROTATING_DEVICE_ID + char rotatingDeviceIdHexBuffer[RotatingDeviceId::kHexMaxLength]; + ReturnErrorOnFailure(GenerateRotatingDeviceId(rotatingDeviceIdHexBuffer, ArraySize(rotatingDeviceIdHexBuffer))); + advertiseParameters.SetRotatingId(chip::Optional::Value(rotatingDeviceIdHexBuffer)); +#endif + + if (notYetCommissioned) + { + if (DeviceLayer::ConfigurationMgr().GetInitialPairingHint(value) != CHIP_NO_ERROR) + { + ChipLogProgress(Discovery, "DNS-SD Pairing Hint not set"); + } + else + { + advertiseParameters.SetPairingHint(chip::Optional::Value(value)); + } + + if (DeviceLayer::ConfigurationMgr().GetInitialPairingInstruction(pairingInst, sizeof(pairingInst)) != CHIP_NO_ERROR) + { + ChipLogProgress(Discovery, "DNS-SD Pairing Instruction not set"); + } + else + { + advertiseParameters.SetPairingInstr(chip::Optional::Value(pairingInst)); + } + } + else + { + if (DeviceLayer::ConfigurationMgr().GetSecondaryPairingHint(value) != CHIP_NO_ERROR) + { + ChipLogProgress(Discovery, "DNS-SD Pairing Hint not set"); + } + else + { + advertiseParameters.SetPairingHint(chip::Optional::Value(value)); + } + + if (DeviceLayer::ConfigurationMgr().GetSecondaryPairingInstruction(pairingInst, sizeof(pairingInst)) != CHIP_NO_ERROR) + { + ChipLogProgress(Discovery, "DNS-SD Pairing Instruction not set"); + } + else + { + advertiseParameters.SetPairingInstr(chip::Optional::Value(pairingInst)); + } + } + auto & mdnsAdvertiser = chip::Mdns::ServiceAdvertiser::Instance(); ChipLogProgress(Discovery, "Advertise commission parameter vendorID=%u productID=%u discriminator=%04u/%02u", @@ -167,23 +251,50 @@ void StartServer() if (DeviceLayer::ConfigurationMgr().IsFullyProvisioned()) { err = app::Mdns::AdvertiseOperational(); +#if CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY + err = app::Mdns::AdvertiseCommissionableNode(); +#endif } else { // TODO: Thread devices are not able to advertise using mDNS before being provisioned, // so configuraton should be added to enable commissioning advertising based on supported // Rendezvous methods. -#if !CHIP_DEVICE_CONFIG_ENABLE_THREAD - err = app::Mdns::AdvertiseCommisionable(); +#if (!CHIP_DEVICE_CONFIG_ENABLE_THREAD || CHIP_DEVICE_CONFIG_ENABLE_UNPROVISIONED_MDNS) + err = app::Mdns::AdvertiseCommissionableNode(); #endif } +#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY + err = app::Mdns::AdvertiseCommisioner(); +#endif + if (err != CHIP_NO_ERROR) { ChipLogError(Discovery, "Failed to start mDNS server: %s", chip::ErrorStr(err)); } } +#if CHIP_ENABLE_ROTATING_DEVICE_ID +CHIP_ERROR GenerateRotatingDeviceId(char rotatingDeviceIdHexBuffer[], size_t rotatingDeviceIdHexBufferSize) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + char serialNumber[chip::DeviceLayer::ConfigurationManager::kMaxSerialNumberLength + 1]; + size_t serialNumberSize = 0; + uint16_t lifetimeCounter = 0; + size_t rotatingDeviceIdValueOutputSize = 0; + + SuccessOrExit(error = + chip::DeviceLayer::ConfigurationMgr().GetSerialNumber(serialNumber, sizeof(serialNumber), serialNumberSize)); + SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetLifetimeCounter(lifetimeCounter)); + SuccessOrExit(error = AdditionalDataPayloadGenerator().generateRotatingDeviceId( + lifetimeCounter, serialNumber, serialNumberSize, rotatingDeviceIdHexBuffer, rotatingDeviceIdHexBufferSize, + rotatingDeviceIdValueOutputSize)); +exit: + return error; +} +#endif + } // namespace Mdns } // namespace app } // namespace chip diff --git a/src/app/server/Mdns.h b/src/app/server/Mdns.h index 8f63ee8b3f0eb1..7c13968fe8de50 100644 --- a/src/app/server/Mdns.h +++ b/src/app/server/Mdns.h @@ -18,6 +18,7 @@ #pragma once #include +#include namespace chip { namespace app { @@ -26,12 +27,21 @@ namespace Mdns { /// Start operational advertising CHIP_ERROR AdvertiseOperational(); -/// Start commisionable node advertising -CHIP_ERROR AdvertiseCommisionable(); +/// Set MDNS commissioner advertisement +CHIP_ERROR AdvertiseCommissioner(); + +/// Set MDNS commissionable node advertisement +CHIP_ERROR AdvertiseCommissionableNode(); + +/// Set MDNS advertisement +// CHIP_ERROR Advertise(chip::Mdns::CommssionAdvertiseMode mode); +CHIP_ERROR Advertise(bool commissionableNode); /// (Re-)starts the minmdns server void StartServer(); +CHIP_ERROR GenerateRotatingDeviceId(char rotatingDeviceIdHexBuffer[], size_t rotatingDeviceIdHexBufferSize); + } // namespace Mdns } // namespace app } // namespace chip diff --git a/src/include/platform/CHIPDeviceConfig.h b/src/include/platform/CHIPDeviceConfig.h index 6f7c6929adba3f..a1864d694ff893 100644 --- a/src/include/platform/CHIPDeviceConfig.h +++ b/src/include/platform/CHIPDeviceConfig.h @@ -619,6 +619,19 @@ #define CHIP_DEVICE_CONFIG_ENABLE_MDNS 0 #endif +/** + * CHIP_DEVICE_CONFIG_ENABLE_UNPROVISIONED_MDNS + * + * Enable MDNS commissionable node advertising when not yet provisioned. + * + * This should be 1 for WiFi SoftAP devices, ethernet devices, and (probably) bridge devices + * + * This should be 0 for Thread/BLE devices and WiFi/BLE devices + */ +#ifndef CHIP_DEVICE_CONFIG_ENABLE_UNPROVISIONED_MDNS +#define CHIP_DEVICE_CONFIG_ENABLE_UNPROVISIONED_MDNS 0 +#endif + /** * CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT * @@ -1053,3 +1066,125 @@ #ifndef CHIP_DEVICE_CONFIG_FIRMWARE_BUILD_TIME #define CHIP_DEVICE_CONFIG_FIRMWARE_BUILD_TIME __TIME__ #endif + +// -------------------- Device DNS-SD Advertising Configuration -------------------- + +/** + * CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY + * + * Enable or disable whether this device advertises as a commissioner. + * + * For Video Players, this value will be 1 + */ +#ifndef CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY 0 +#endif + +/** + * CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY + * + * Enable or disable whether this device advertises when not in commissioning mode. + * + */ +#ifndef CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY +#define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 0 +#endif + +/** + * CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_TYPE + * + * Enable or disable including device type in commissionable node discovery. + * + * For Video Players, this value will often be 1 + */ +#ifndef CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_TYPE +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_TYPE 0 +#endif + +/** + * CHIP_DEVICE_CONFIG_DEVICE_TYPE + * + * Type of device using the CHIP Device Type Identifier. + * + * Examples: + * 0xFFFF = 65535 = Invalid Device Type + * 0x0051 = 81 = Smart Plug + * 0x0022 = 34 = Speaker + * 0x0023 = 35 = Video Player + * + */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_TYPE +#define CHIP_DEVICE_CONFIG_DEVICE_TYPE 65535 // 65535 = Invalid Device Type +#endif + +/** + * CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_NAME + * + * Enable or disable including device name in commissionable node discovery. + * + * For Video Players, this value will often be 1 + */ +#ifndef CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_NAME +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_NAME 0 +#endif + +/** + * CHIP_DEVICE_CONFIG_DEVICE_NAME + * + * Name of device. + */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_NAME +#define CHIP_DEVICE_CONFIG_DEVICE_NAME "Test Kitchen" +#endif + +/** + * CHIP_DEVICE_CONFIG_PAIRING_INITIAL_HINT + * + * Pairing Hint, bitmap value of methods to put device into pairing mode + * when it has not yet been commissioned. + * + * Bits: + * 0 - Power Cycle + * 5 - See Device Manual + */ +#ifndef CHIP_DEVICE_CONFIG_PAIRING_INITIAL_HINT +#define CHIP_DEVICE_CONFIG_PAIRING_INITIAL_HINT \ + (1 << CHIP_COMMISSIONING_HINT_INDEX_POWER_CYCLE | 1 << CHIP_COMMISSIONING_HINT_INDEX_SEE_MANUAL) +#endif + +/** + * CHIP_DEVICE_CONFIG_PAIRING_INITIAL_INSTRUCTION + * + * Pairing Instruction, when device has not yet been commissioned + * + * Meaning is depedent upon pairing hint value. + */ +#ifndef CHIP_DEVICE_CONFIG_PAIRING_INITIAL_INSTRUCTION +#define CHIP_DEVICE_CONFIG_PAIRING_INITIAL_INSTRUCTION "" +#endif + +/** + * CHIP_DEVICE_CONFIG_PAIRING_SECONDARY_HINT + * + * Pairing Hint, bitmap value of methods to put device into pairing mode + * when it has already been commissioned. + * + * Bits: + * 2 - Visit Administrator UX (always true for secondary) + * 5 - See Device Manual + */ +#ifndef CHIP_DEVICE_CONFIG_PAIRING_SECONDARY_HINT +#define CHIP_DEVICE_CONFIG_PAIRING_SECONDARY_HINT \ + (1 << CHIP_COMMISSIONING_HINT_INDEX_SEE_ADMINISTRATOR_UX | 1 << CHIP_COMMISSIONING_HINT_INDEX_SEE_MANUAL) +#endif + +/** + * CHIP_DEVICE_CONFIG_PAIRING_SECONDARY_INSTRUCTION + * + * Pairing Instruction, when device has not yet been commissioned + * + * Meaning is depedent upon pairing hint value. + */ +#ifndef CHIP_DEVICE_CONFIG_PAIRING_SECONDARY_INSTRUCTION +#define CHIP_DEVICE_CONFIG_PAIRING_SECONDARY_INSTRUCTION "" +#endif diff --git a/src/include/platform/ConfigurationManager.h b/src/include/platform/ConfigurationManager.h index 3aceb5c8f2d3b0..bc6854f3727cc7 100644 --- a/src/include/platform/ConfigurationManager.h +++ b/src/include/platform/ConfigurationManager.h @@ -147,6 +147,15 @@ class ConfigurationManager void LogDeviceConfig(); + bool IsCommissionableDeviceTypeEnabled(); + CHIP_ERROR GetDeviceType(uint16_t & deviceType); + bool IsCommissionableDeviceNameEnabled(); + CHIP_ERROR GetDeviceName(char * buf, size_t bufSize); + CHIP_ERROR GetInitialPairingHint(uint16_t & pairingHint); + CHIP_ERROR GetInitialPairingInstruction(char * buf, size_t bufSize); + CHIP_ERROR GetSecondaryPairingHint(uint16_t & pairingHint); + CHIP_ERROR GetSecondaryPairingInstruction(char * buf, size_t bufSize); + private: // ===== Members for internal use by the following friends. @@ -628,5 +637,69 @@ inline void ConfigurationManager::LogDeviceConfig() static_cast(this)->_LogDeviceConfig(); } +/** + * True if device type in DNS-SD advertisement is enabled + */ +inline bool ConfigurationManager::IsCommissionableDeviceTypeEnabled() +{ + return static_cast(this)->_IsCommissionableDeviceNameEnabled(); +} + +/** + * Device type id. + */ +inline CHIP_ERROR ConfigurationManager::GetDeviceType(uint16_t & deviceType) +{ + return static_cast(this)->_GetDeviceType(deviceType); +} + +/** + * True if device name in DNS-SD advertisement is enabled + */ +inline bool ConfigurationManager::IsCommissionableDeviceNameEnabled() +{ + return static_cast(this)->_IsCommissionableDeviceNameEnabled(); +} + +/** + * Name of the device. + */ +inline CHIP_ERROR ConfigurationManager::GetDeviceName(char * buf, size_t bufSize) +{ + return static_cast(this)->_GetDeviceName(buf, bufSize); +} + +/** + * Initial pairing hint. + */ +inline CHIP_ERROR ConfigurationManager::GetInitialPairingHint(uint16_t & pairingHint) +{ + return static_cast(this)->_GetInitialPairingHint(pairingHint); +} + +/** + * Secondary pairing hint. + */ +inline CHIP_ERROR ConfigurationManager::GetSecondaryPairingHint(uint16_t & pairingHint) +{ + return static_cast(this)->_GetSecondaryPairingHint(pairingHint); +} + +/** + * Initial pairing instruction. + */ +inline CHIP_ERROR ConfigurationManager::GetInitialPairingInstruction(char * buf, size_t bufSize) +{ + return static_cast(this)->_GetInitialPairingInstruction(buf, bufSize); +} + +/** + * Secondary pairing instruction. + */ +inline CHIP_ERROR ConfigurationManager::GetSecondaryPairingInstruction(char * buf, size_t bufSize) +{ + return static_cast(this)->_GetSecondaryPairingInstruction(buf, bufSize); +} + } // namespace DeviceLayer } // namespace chip diff --git a/src/include/platform/internal/GenericConfigurationManagerImpl.cpp b/src/include/platform/internal/GenericConfigurationManagerImpl.cpp index 7d862abe76f800..d9ef27da607894 100644 --- a/src/include/platform/internal/GenericConfigurationManagerImpl.cpp +++ b/src/include/platform/internal/GenericConfigurationManagerImpl.cpp @@ -197,7 +197,6 @@ template CHIP_ERROR GenericConfigurationManagerImpl::_GetSerialNumber(char * buf, size_t bufSize, size_t & serialNumLen) { CHIP_ERROR err; - err = Impl()->ReadConfigValueStr(ImplClass::kConfigKey_SerialNum, buf, bufSize, serialNumLen); #ifdef CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER if (CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER[0] != 0 && err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) @@ -926,6 +925,42 @@ bool GenericConfigurationManagerImpl::_IsFullyProvisioned() #endif // CHIP_BYPASS_RENDEZVOUS } +template +bool GenericConfigurationManagerImpl::_IsCommissionableDeviceTypeEnabled() +{ + return CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_TYPE == 1; +} + +template +bool GenericConfigurationManagerImpl::_IsCommissionableDeviceNameEnabled() +{ + return CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_NAME == 1; +} + +template +CHIP_ERROR GenericConfigurationManagerImpl::_GetDeviceName(char * buf, size_t bufSize) +{ + ReturnErrorCodeIf(bufSize < sizeof(CHIP_DEVICE_CONFIG_DEVICE_NAME), CHIP_ERROR_BUFFER_TOO_SMALL); + strcpy(buf, CHIP_DEVICE_CONFIG_DEVICE_NAME); + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR GenericConfigurationManagerImpl::_GetInitialPairingInstruction(char * buf, size_t bufSize) +{ + ReturnErrorCodeIf(bufSize < sizeof(CHIP_DEVICE_CONFIG_PAIRING_INITIAL_INSTRUCTION), CHIP_ERROR_BUFFER_TOO_SMALL); + strcpy(buf, CHIP_DEVICE_CONFIG_PAIRING_INITIAL_INSTRUCTION); + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR GenericConfigurationManagerImpl::_GetSecondaryPairingInstruction(char * buf, size_t bufSize) +{ + ReturnErrorCodeIf(bufSize < sizeof(CHIP_DEVICE_CONFIG_PAIRING_SECONDARY_INSTRUCTION), CHIP_ERROR_BUFFER_TOO_SMALL); + strcpy(buf, CHIP_DEVICE_CONFIG_PAIRING_SECONDARY_INSTRUCTION); + return CHIP_NO_ERROR; +} + template CHIP_ERROR GenericConfigurationManagerImpl::_ComputeProvisioningHash(uint8_t * hashBuf, size_t hashBufSize) { @@ -1164,6 +1199,15 @@ void GenericConfigurationManagerImpl::_LogDeviceConfig() ChipLogProgress(DeviceLayer, " Pairing Code: %s", (FabricState.PairingCode != NULL) ? FabricState.PairingCode : "(none)"); #endif // CHIP_CONFIG_ENABLE_FABRIC_STATE + + { + uint16_t deviceType; + if (Impl()->_GetDeviceType(deviceType) != CHIP_NO_ERROR) + { + deviceType = 0; + } + ChipLogProgress(DeviceLayer, " Device Type: %" PRIu16 " (0x%" PRIX16 ")", deviceType, deviceType); + } } // Fully instantiate the generic implementation class in whatever compilation unit includes this file. diff --git a/src/include/platform/internal/GenericConfigurationManagerImpl.h b/src/include/platform/internal/GenericConfigurationManagerImpl.h index bfee1c1c00cfa7..8fb3a7e0a93a25 100644 --- a/src/include/platform/internal/GenericConfigurationManagerImpl.h +++ b/src/include/platform/internal/GenericConfigurationManagerImpl.h @@ -115,6 +115,14 @@ class GenericConfigurationManagerImpl CHIP_ERROR _GetQRCodeString(char * buf, size_t bufSize); CHIP_ERROR _GetWiFiAPSSID(char * buf, size_t bufSize); CHIP_ERROR _GetBLEDeviceIdentificationInfo(Ble::ChipBLEDeviceIdentificationInfo & deviceIdInfo); + bool _IsCommissionableDeviceTypeEnabled(); + CHIP_ERROR _GetDeviceType(uint16_t & deviceType); + bool _IsCommissionableDeviceNameEnabled(); + CHIP_ERROR _GetDeviceName(char * buf, size_t bufSize); + CHIP_ERROR _GetInitialPairingHint(uint16_t & pairingHint); + CHIP_ERROR _GetInitialPairingInstruction(char * buf, size_t bufSize); + CHIP_ERROR _GetSecondaryPairingHint(uint16_t & pairingHint); + CHIP_ERROR _GetSecondaryPairingInstruction(char * buf, size_t bufSize); CHIP_ERROR _GetRegulatoryLocation(uint32_t & location); CHIP_ERROR _StoreRegulatoryLocation(uint32_t location); CHIP_ERROR _GetCountryCode(char * buf, size_t bufSize, size_t & codeLen); @@ -184,6 +192,27 @@ inline CHIP_ERROR GenericConfigurationManagerImpl::_GetFirmwareRevisi return CHIP_NO_ERROR; } +template +inline CHIP_ERROR GenericConfigurationManagerImpl::_GetDeviceType(uint16_t & deviceType) +{ + deviceType = static_cast(CHIP_DEVICE_CONFIG_DEVICE_TYPE); + return CHIP_NO_ERROR; +} + +template +inline CHIP_ERROR GenericConfigurationManagerImpl::_GetInitialPairingHint(uint16_t & pairingHint) +{ + pairingHint = static_cast(CHIP_DEVICE_CONFIG_PAIRING_INITIAL_HINT); + return CHIP_NO_ERROR; +} + +template +inline CHIP_ERROR GenericConfigurationManagerImpl::_GetSecondaryPairingHint(uint16_t & pairingHint) +{ + pairingHint = static_cast(CHIP_DEVICE_CONFIG_PAIRING_SECONDARY_HINT); + return CHIP_NO_ERROR; +} + } // namespace Internal } // namespace DeviceLayer } // namespace chip diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index e7aed2a92ea25f..149a066a4d3b05 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -2371,3 +2371,25 @@ #ifdef CHIP_NON_PRODUCTION_MARKER extern const char CHIP_NON_PRODUCTION_MARKER[]; #endif + +/** + * @def CHIP_COMMISSIONING_HINT_TABLE + * + * @brief Defines the set of "pairing hint" values that can be set in + * the PH key in commissionable node discovery response. + */ +#ifndef CHIP_COMMISSIONING_HINT_TABLE +#define CHIP_COMMISSIONING_HINT_TABLE +#define CHIP_COMMISSIONING_HINT_INDEX_POWER_CYCLE 0 +#define CHIP_COMMISSIONING_HINT_INDEX_MANUFACTURER_URL 1 +#define CHIP_COMMISSIONING_HINT_INDEX_SEE_ADMINISTRATOR_UX 2 +#define CHIP_COMMISSIONING_HINT_INDEX_SEE_SETTINGS_MENU 3 +#define CHIP_COMMISSIONING_HINT_INDEX_CUSTOM_INSTRUCTION 4 +#define CHIP_COMMISSIONING_HINT_INDEX_SEE_MANUAL 5 +#define CHIP_COMMISSIONING_HINT_INDEX_PRESS_RESET 6 +#define CHIP_COMMISSIONING_HINT_INDEX_PRESS_RESET_WITH_POWER 7 +#define CHIP_COMMISSIONING_HINT_INDEX_PRESS_RESET_SECONDS 8 +#define CHIP_COMMISSIONING_HINT_INDEX_PRESS_RESET_UNTIL_BLINK 9 +#define CHIP_COMMISSIONING_HINT_INDEX_PRESS_RESET_SECONDS_WITH_POWER 10 +#define CHIP_COMMISSIONING_HINT_INDEX_PRESS_RESET_UNTIL_BLINK_WITH_POWER 11 +#endif diff --git a/src/lib/mdns/Advertiser.h b/src/lib/mdns/Advertiser.h index 1afa64557dd9c2..59ccddb828f992 100644 --- a/src/lib/mdns/Advertiser.h +++ b/src/lib/mdns/Advertiser.h @@ -33,10 +33,27 @@ static constexpr uint16_t kMdnsPort = 5353; // Need 8 bytes to fit a thread mac. static constexpr size_t kMaxMacSize = 8; +static constexpr size_t kKeyDiscriminatorMaxLength = 5; +static constexpr size_t kKeyVendorProductMaxLength = 11; +static constexpr size_t kKeyAdditionalPairingMaxLength = 1; +static constexpr size_t kKeyCommissioningModeMaxLength = 1; +static constexpr size_t kKeyDeviceTypeMaxLength = 5; +static constexpr size_t kKeyDeviceNameMaxLength = 32; +static constexpr size_t kKeyRotatingIdMaxLength = 100; +static constexpr size_t kKeyPairingInstructionMaxLength = 128; +static constexpr size_t kKeyPairingHintMaxLength = 10; + +static constexpr size_t kSubTypeShortDiscriminatorMaxLength = 3; +static constexpr size_t kSubTypeLongDiscriminatorMaxLength = 4; +static constexpr size_t kSubTypeVendorMaxLength = 5; +static constexpr size_t kSubTypeDeviceTypeMaxLength = 5; +static constexpr size_t kSubTypeCommissioningModeMaxLength = 1; +static constexpr size_t kSubTypeAdditionalPairingMaxLength = 1; + enum class CommssionAdvertiseMode : uint8_t { - kCommissioning, - kCommissionable, + kCommissionableNode, + kCommissioner, }; template @@ -142,19 +159,61 @@ class CommissionAdvertisingParameters : public BaseAdvertisingParams GetProductId() const { return mProductId; } + CommissionAdvertisingParameters & SetCommissioningMode(bool modeEnabled, bool openWindow) + { + mCommissioningModeEnabled = modeEnabled; + mOpenWindowCommissioningMode = openWindow; + return *this; + } + bool GetCommissioningMode() const { return mCommissioningModeEnabled; } + bool GetOpenWindowCommissioningMode() const { return mOpenWindowCommissioningMode; } + + CommissionAdvertisingParameters & SetDeviceType(Optional deviceType) + { + mDeviceType = deviceType; + return *this; + } + Optional GetDeviceType() const { return mDeviceType; } + + CommissionAdvertisingParameters & SetDeviceName(Optional deviceName) + { + if (deviceName.HasValue()) + { + strncpy(sDeviceName, deviceName.Value(), min(strlen(deviceName.Value()) + 1, sizeof(sDeviceName))); + mDeviceName = Optional::Value(static_cast(sDeviceName)); + } + return *this; + } + Optional GetDeviceName() const { return mDeviceName; } + + CommissionAdvertisingParameters & SetRotatingId(Optional rotatingId) + { + if (rotatingId.HasValue()) + { + strncpy(sRotatingId, rotatingId.Value(), min(strlen(rotatingId.Value()) + 1, sizeof(sRotatingId))); + mRotatingId = Optional::Value(static_cast(sRotatingId)); + } + return *this; + } + Optional GetRotatingId() const { return mRotatingId; } + CommissionAdvertisingParameters & SetPairingInstr(Optional pairingInstr) { - mPairingInstr = pairingInstr; + if (pairingInstr.HasValue()) + { + strncpy(sPairingInstr, pairingInstr.Value(), min(strlen(pairingInstr.Value()) + 1, sizeof(sPairingInstr))); + mPairingInstr = Optional::Value(static_cast(sPairingInstr)); + } return *this; } Optional GetPairingInstr() const { return mPairingInstr; } - CommissionAdvertisingParameters & SetPairingHint(Optional pairingHint) + CommissionAdvertisingParameters & SetPairingHint(Optional pairingHint) { mPairingHint = pairingHint; return *this; } - Optional GetPairingHint() const { return mPairingHint; } + Optional GetPairingHint() const { return mPairingHint; } CommissionAdvertisingParameters & SetCommissionAdvertiseMode(CommssionAdvertiseMode mode) { @@ -164,13 +223,24 @@ class CommissionAdvertisingParameters : public BaseAdvertisingParams mVendorId; chip::Optional mProductId; + chip::Optional mDeviceType; + chip::Optional mPairingHint; + + char sDeviceName[kKeyDeviceNameMaxLength + 1]; + chip::Optional mDeviceName; + + char sRotatingId[kKeyRotatingIdMaxLength + 1]; + chip::Optional mRotatingId; + + char sPairingInstr[kKeyPairingInstructionMaxLength + 1]; chip::Optional mPairingInstr; - chip::Optional mPairingHint; }; /// Handles advertising of CHIP nodes @@ -186,9 +256,12 @@ class ServiceAdvertiser /// Advertises the CHIP node as an operational node virtual CHIP_ERROR Advertise(const OperationalAdvertisingParameters & params) = 0; - /// Advertises the CHIP node as a commisioning/commissionable node + /// Advertises the CHIP node as a commissioner/commissionable node virtual CHIP_ERROR Advertise(const CommissionAdvertisingParameters & params) = 0; + /// Stops the advertiser. + virtual CHIP_ERROR StopPublishDevice() = 0; + /// Provides the system-wide implementation of the service advertiser static ServiceAdvertiser & Instance(); }; diff --git a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp index be93b051e1ae51..a365de8b62125d 100644 --- a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp +++ b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp @@ -37,6 +37,7 @@ // Enable detailed mDNS logging for received queries #undef DETAIL_LOGGING +// #define DETAIL_LOGGING namespace chip { namespace Mdns { @@ -119,6 +120,7 @@ class AdvertiserMinMdns : public ServiceAdvertiser, CHIP_ERROR Start(chip::Inet::InetLayer * inetLayer, uint16_t port) override; CHIP_ERROR Advertise(const OperationalAdvertisingParameters & params) override; CHIP_ERROR Advertise(const CommissionAdvertisingParameters & params) override; + CHIP_ERROR StopPublishDevice() override; // MdnsPacketDelegate void OnMdnsPacketData(const BytesRange & data, const chip::Inet::IPPacketInfo * info) override; @@ -200,9 +202,9 @@ class AdvertiserMinMdns : public ServiceAdvertiser, FullQName GetCommisioningTextEntries(const CommissionAdvertisingParameters & params); - static constexpr size_t kMaxRecords = 16; - static constexpr size_t kMaxAllocatedResponders = 16; - static constexpr size_t kMaxAllocatedQNameData = 8; + static constexpr size_t kMaxRecords = 32; + static constexpr size_t kMaxAllocatedResponders = 64; + static constexpr size_t kMaxAllocatedQNameData = 32; QueryResponder mQueryResponder; ResponseSender mResponseSender; @@ -264,6 +266,13 @@ CHIP_ERROR AdvertiserMinMdns::Start(chip::Inet::InetLayer * inetLayer, uint16_t return CHIP_NO_ERROR; } +/// Stops the advertiser. +CHIP_ERROR AdvertiserMinMdns::StopPublishDevice() +{ + Clear(); + return CHIP_NO_ERROR; +} + void AdvertiserMinMdns::Clear() { // Init clears all responders, so that data can be freed @@ -291,8 +300,6 @@ void AdvertiserMinMdns::Clear() CHIP_ERROR AdvertiserMinMdns::Advertise(const OperationalAdvertisingParameters & params) { - Clear(); - char nameBuffer[64] = ""; /// need to set server name @@ -356,8 +363,6 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const OperationalAdvertisingParameters & CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters & params) { - Clear(); - // TODO: need to detect colisions here char nameBuffer[64] = ""; size_t len = snprintf(nameBuffer, sizeof(nameBuffer), "%016" PRIX64, GetRandU64()); @@ -365,7 +370,8 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters & { return CHIP_ERROR_NO_MEMORY; } - const char * serviceType = params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissioning ? "_chipc" : "_chipd"; + const char * serviceType = + params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode ? "_chipc" : "_chipd"; FullQName operationalServiceName = AllocateQName(serviceType, "_udp", "local"); FullQName operationalServerName = AllocateQName(nameBuffer, serviceType, "_udp", "local"); @@ -410,48 +416,97 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters & } } + if (params.GetVendorId().HasValue()) { - sprintf(nameBuffer, "_S%03d", params.GetShortDiscriminator()); - FullQName shortServiceName = AllocateQName(nameBuffer, "_sub", serviceType, "_udp", "local"); - ReturnErrorCodeIf(shortServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY); + sprintf(nameBuffer, "_V%d", params.GetVendorId().Value()); + FullQName vendorServiceName = AllocateQName(nameBuffer, "_sub", serviceType, "_udp", "local"); + ReturnErrorCodeIf(vendorServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY); - if (!AddResponder(shortServiceName, operationalServerName) + if (!AddResponder(vendorServiceName, operationalServerName) .SetReportAdditional(operationalServerName) .SetReportInServiceListing(true) .IsValid()) { - ChipLogError(Discovery, "Failed to add short discriminator PTR record mDNS responder"); + ChipLogError(Discovery, "Failed to add vendor PTR record mDNS responder"); return CHIP_ERROR_NO_MEMORY; } } + if (params.GetDeviceType().HasValue()) { - sprintf(nameBuffer, "_L%04d", params.GetLongDiscriminator()); - FullQName longServiceName = AllocateQName(nameBuffer, "_sub", serviceType, "_udp", "local"); - ReturnErrorCodeIf(longServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY); - if (!AddResponder(longServiceName, operationalServerName) + sprintf(nameBuffer, "_T%d", params.GetDeviceType().Value()); + FullQName vendorServiceName = AllocateQName(nameBuffer, "_sub", serviceType, "_udp", "local"); + ReturnErrorCodeIf(vendorServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY); + + if (!AddResponder(vendorServiceName, operationalServerName) .SetReportAdditional(operationalServerName) .SetReportInServiceListing(true) .IsValid()) { - ChipLogError(Discovery, "Failed to add long discriminator PTR record mDNS responder"); + ChipLogError(Discovery, "Failed to add device type PTR record mDNS responder"); return CHIP_ERROR_NO_MEMORY; } } - if (params.GetVendorId().HasValue()) + // the following sub types only apply to commissionable node advertisements + if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode) { - sprintf(nameBuffer, "_V%d", params.GetVendorId().Value()); - FullQName vendorServiceName = AllocateQName(nameBuffer, "_sub", serviceType, "_udp", "local"); - ReturnErrorCodeIf(vendorServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY); + { + sprintf(nameBuffer, "_S%03d", params.GetShortDiscriminator()); + FullQName shortServiceName = AllocateQName(nameBuffer, "_sub", serviceType, "_udp", "local"); + ReturnErrorCodeIf(shortServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY); + + if (!AddResponder(shortServiceName, operationalServerName) + .SetReportAdditional(operationalServerName) + .SetReportInServiceListing(true) + .IsValid()) + { + ChipLogError(Discovery, "Failed to add short discriminator PTR record mDNS responder"); + return CHIP_ERROR_NO_MEMORY; + } + } - if (!AddResponder(vendorServiceName, operationalServerName) - .SetReportAdditional(operationalServerName) - .SetReportInServiceListing(true) - .IsValid()) { - ChipLogError(Discovery, "Failed to add vendor discriminator PTR record mDNS responder"); - return CHIP_ERROR_NO_MEMORY; + sprintf(nameBuffer, "_L%04d", params.GetLongDiscriminator()); + FullQName longServiceName = AllocateQName(nameBuffer, "_sub", serviceType, "_udp", "local"); + ReturnErrorCodeIf(longServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY); + if (!AddResponder(longServiceName, operationalServerName) + .SetReportAdditional(operationalServerName) + .SetReportInServiceListing(true) + .IsValid()) + { + ChipLogError(Discovery, "Failed to add long discriminator PTR record mDNS responder"); + return CHIP_ERROR_NO_MEMORY; + } + } + + { + sprintf(nameBuffer, "_C%d", params.GetCommissioningMode() ? 1 : 0); + FullQName longServiceName = AllocateQName(nameBuffer, "_sub", serviceType, "_udp", "local"); + ReturnErrorCodeIf(longServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY); + if (!AddResponder(longServiceName, operationalServerName) + .SetReportAdditional(operationalServerName) + .SetReportInServiceListing(true) + .IsValid()) + { + ChipLogError(Discovery, "Failed to add commissioning mode PTR record mDNS responder"); + return CHIP_ERROR_NO_MEMORY; + } + } + + if (params.GetCommissioningMode() && params.GetOpenWindowCommissioningMode()) + { + sprintf(nameBuffer, "_A1"); + FullQName longServiceName = AllocateQName(nameBuffer, "_sub", serviceType, "_udp", "local"); + ReturnErrorCodeIf(longServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY); + if (!AddResponder(longServiceName, operationalServerName) + .SetReportAdditional(operationalServerName) + .SetReportInServiceListing(true) + .IsValid()) + { + ChipLogError(Discovery, "Failed to add open window commissioning mode PTR record mDNS responder"); + return CHIP_ERROR_NO_MEMORY; + } } } @@ -463,42 +518,111 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters & return CHIP_ERROR_NO_MEMORY; } - ChipLogProgress(Discovery, "CHIP minimal mDNS configured as 'Commisioning device'."); + if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode) + { + ChipLogProgress(Discovery, "CHIP minimal mDNS configured as 'Commissionable node device'."); + } + else + { + ChipLogProgress(Discovery, "CHIP minimal mDNS configured as 'Commissioner device'."); + } return CHIP_NO_ERROR; } FullQName AdvertiserMinMdns::GetCommisioningTextEntries(const CommissionAdvertisingParameters & params) { - // a discriminator always exists - char txtDiscriminator[32]; - sprintf(txtDiscriminator, "D=%d", params.GetLongDiscriminator()); + char txtVidPid[chip::Mdns::kKeyVendorProductMaxLength + 4]; + if (params.GetProductId().HasValue()) + { + sprintf(txtVidPid, "VP=%d+%d", params.GetVendorId().Value(), params.GetProductId().Value()); + } + else + { + sprintf(txtVidPid, "VP=%d", params.GetVendorId().Value()); + } - if (!params.GetVendorId().HasValue()) + char txtDeviceType[chip::Mdns::kKeyDeviceTypeMaxLength + 4]; + if (params.GetDeviceType().HasValue()) { - return AllocateQName(txtDiscriminator); + sprintf(txtDeviceType, "DT=%d", params.GetDeviceType().Value()); + } + else + { + txtDeviceType[0] = '\0'; } - // Need to also set a vid/pid string - char txtVidPid[64]; - if (params.GetProductId().HasValue()) + char txtDeviceName[chip::Mdns::kKeyDeviceNameMaxLength + 4]; + if (params.GetDeviceName().HasValue()) { - sprintf(txtVidPid, "VP=%d+%d", params.GetVendorId().Value(), params.GetProductId().Value()); + sprintf(txtDeviceName, "DN=%s", params.GetDeviceName().Value()); } else { - sprintf(txtVidPid, "VP=%d", params.GetVendorId().Value()); + txtDeviceName[0] = '\0'; } - char txtPairingInstrHint[128]; - if (params.GetPairingInstr().HasValue() && params.GetPairingHint().HasValue()) + // the following sub types only apply to commissionable node advertisements + if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode) { - sprintf(txtPairingInstrHint, "P=%s+%d", params.GetPairingInstr().Value(), params.GetPairingHint().Value()); - return AllocateQName(txtDiscriminator, txtVidPid, txtPairingInstrHint); + // a discriminator always exists + char txtDiscriminator[chip::Mdns::kKeyDiscriminatorMaxLength + 3]; + sprintf(txtDiscriminator, "D=%d", params.GetLongDiscriminator()); + + if (!params.GetVendorId().HasValue()) + { + return AllocateQName(txtDiscriminator); + } + + char txtCommissioningMode[chip::Mdns::kKeyCommissioningModeMaxLength + 4]; + sprintf(txtCommissioningMode, "CM=%d", params.GetCommissioningMode() ? 1 : 0); + + char txtOpenWindowCommissioningMode[chip::Mdns::kKeyAdditionalPairingMaxLength + 4]; + if (params.GetCommissioningMode() && params.GetOpenWindowCommissioningMode()) + { + sprintf(txtOpenWindowCommissioningMode, "AP=1"); + } + else + { + txtOpenWindowCommissioningMode[0] = '\0'; + } + + char txtRotatingDeviceId[chip::Mdns::kKeyRotatingIdMaxLength + 4]; + if (params.GetRotatingId().HasValue()) + { + sprintf(txtRotatingDeviceId, "RI=%s", params.GetRotatingId().Value()); + } + else + { + txtRotatingDeviceId[0] = '\0'; + } + + char txtPairingHint[chip::Mdns::kKeyPairingInstructionMaxLength + 4]; + if (params.GetPairingHint().HasValue()) + { + sprintf(txtPairingHint, "PH=%d", params.GetPairingHint().Value()); + } + else + { + txtPairingHint[0] = '\0'; + } + + char txtPairingInstr[chip::Mdns::kKeyPairingInstructionMaxLength + 4]; + if (params.GetPairingInstr().HasValue()) + { + sprintf(txtPairingInstr, "PI=%s", params.GetPairingInstr().Value()); + } + else + { + txtPairingInstr[0] = '\0'; + } + + return AllocateQName(txtDiscriminator, txtVidPid, txtCommissioningMode, txtOpenWindowCommissioningMode, txtDeviceType, + txtDeviceName, txtRotatingDeviceId, txtPairingHint, txtPairingInstr); } else { - return AllocateQName(txtDiscriminator, txtVidPid); + return AllocateQName(txtVidPid, txtDeviceType, txtDeviceName); } } diff --git a/src/lib/mdns/Advertiser_ImplNone.cpp b/src/lib/mdns/Advertiser_ImplNone.cpp index 1ea1edd7583d18..889388abdb0d3a 100644 --- a/src/lib/mdns/Advertiser_ImplNone.cpp +++ b/src/lib/mdns/Advertiser_ImplNone.cpp @@ -43,6 +43,13 @@ class NoneAdvertiser : public ServiceAdvertiser ChipLogError(Discovery, "mDNS advertising not available. Commisioning Advertisement failed."); return CHIP_ERROR_NOT_IMPLEMENTED; } + + /// Stops the advertiser. + CHIP_ERROR StopPublishDevice() override + { + ChipLogError(Discovery, "mDNS advertising not available. mDNS stop not available."); + return CHIP_ERROR_NOT_IMPLEMENTED; + } }; NoneAdvertiser gAdvertiser; diff --git a/src/lib/mdns/Discovery_ImplPlatform.cpp b/src/lib/mdns/Discovery_ImplPlatform.cpp index 7b09e1ea9ec345..ed9e84ba78b63f 100644 --- a/src/lib/mdns/Discovery_ImplPlatform.cpp +++ b/src/lib/mdns/Discovery_ImplPlatform.cpp @@ -87,9 +87,13 @@ void DiscoveryImplPlatform::HandleMdnsError(void * context, CHIP_ERROR error) { publisher->Advertise(publisher->mOperationalAdvertisingParams); } - if (publisher->mIsCommissionalPublishing) + if (publisher->mIsCommissionableNodePublishing) { - publisher->Advertise(publisher->mCommissioningdvertisingParams); + publisher->Advertise(publisher->mCommissionableNodeAdvertisingParams); + } + if (publisher->mIsCommissionerPublishing) + { + publisher->Advertise(publisher->mCommissionerAdvertisingParams); } } else @@ -98,24 +102,6 @@ void DiscoveryImplPlatform::HandleMdnsError(void * context, CHIP_ERROR error) } } -#if CHIP_ENABLE_ROTATING_DEVICE_ID -CHIP_ERROR DiscoveryImplPlatform::GenerateRotatingDeviceId(char rotatingDeviceIdHexBuffer[], size_t & rotatingDeviceIdHexBufferSize) -{ - CHIP_ERROR error = CHIP_NO_ERROR; - char serialNumber[chip::DeviceLayer::ConfigurationManager::kMaxSerialNumberLength + 1]; - size_t serialNumberSize = 0; - uint16_t lifetimeCounter = 0; - SuccessOrExit(error = - chip::DeviceLayer::ConfigurationMgr().GetSerialNumber(serialNumber, sizeof(serialNumber), serialNumberSize)); - SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetLifetimeCounter(lifetimeCounter)); - SuccessOrExit(error = AdditionalDataPayloadGenerator().generateRotatingDeviceId( - lifetimeCounter, serialNumber, serialNumberSize, rotatingDeviceIdHexBuffer, rotatingDeviceIdHexBufferSize, - rotatingDeviceIdHexBufferSize)); -exit: - return error; -} -#endif - CHIP_ERROR DiscoveryImplPlatform::SetupHostname(chip::ByteSpan macOrEui64) { char nameBuffer[17]; @@ -138,20 +124,29 @@ CHIP_ERROR DiscoveryImplPlatform::Advertise(const CommissionAdvertisingParameter { CHIP_ERROR error = CHIP_NO_ERROR; MdnsService service; - char discriminatorBuf[6]; - char vendorProductBuf[12]; - char pairingInstrBuf[128]; - TextEntry textEntries[CommissionAdvertisingParameters::kNumAdvertisingTxtEntries]; + // add newline to lengths for TXT entries + char discriminatorBuf[kKeyDiscriminatorMaxLength + 1]; + char vendorProductBuf[kKeyVendorProductMaxLength + 1]; + char commissioningModeBuf[kKeyCommissioningModeMaxLength + 1]; + char additionalPairingBuf[kKeyAdditionalPairingMaxLength + 1]; + char deviceTypeBuf[kKeyDeviceTypeMaxLength + 1]; + char deviceNameBuf[kKeyDeviceNameMaxLength + 1]; + char rotatingIdBuf[kKeyRotatingIdMaxLength + 1]; + char pairingHintBuf[kKeyPairingHintMaxLength + 1]; + char pairingInstrBuf[kKeyPairingInstructionMaxLength + 1]; + // size of textEntries array should be count of Bufs above + TextEntry textEntries[9]; size_t textEntrySize = 0; - char shortDiscriminatorSubtype[6]; - char longDiscriminatorSubtype[8]; - char vendorSubType[8]; - const char * subTypes[3]; + // add underscore, character and newline to lengths for sub types (ex. _S) + char shortDiscriminatorSubtype[kSubTypeShortDiscriminatorMaxLength + 3]; + char longDiscriminatorSubtype[kSubTypeLongDiscriminatorMaxLength + 4]; + char vendorSubType[kSubTypeVendorMaxLength + 3]; + char commissioningModeSubType[kSubTypeCommissioningModeMaxLength + 3]; + char openWindowSubType[kSubTypeAdditionalPairingMaxLength + 3]; + char deviceTypeSubType[kSubTypeDeviceTypeMaxLength + 3]; + // size of subTypes array should be count of SubTypes above + const char * subTypes[6]; size_t subTypeSize = 0; -#if CHIP_ENABLE_ROTATING_DEVICE_ID - char rotatingDeviceIdHexBuffer[RotatingDeviceId::kHexMaxLength]; - size_t rotatingDeviceIdHexBufferSize = 0; -#endif if (!mMdnsInitialized) { @@ -162,7 +157,7 @@ CHIP_ERROR DiscoveryImplPlatform::Advertise(const CommissionAdvertisingParameter snprintf(service.mName, sizeof(service.mName), "%08" PRIX32 "%08" PRIX32, static_cast(mCommissionInstanceName >> 32), static_cast(mCommissionInstanceName)); - if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissioning) + if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode) { strncpy(service.mType, "_chipc", sizeof(service.mType)); } @@ -172,9 +167,6 @@ CHIP_ERROR DiscoveryImplPlatform::Advertise(const CommissionAdvertisingParameter } service.mProtocol = MdnsServiceProtocol::kMdnsProtocolUdp; - snprintf(discriminatorBuf, sizeof(discriminatorBuf), "%04u", params.GetLongDiscriminator()); - textEntries[textEntrySize++] = { "D", reinterpret_cast(discriminatorBuf), - strnlen(discriminatorBuf, sizeof(discriminatorBuf)) }; if (params.GetVendorId().HasValue()) { if (params.GetProductId().HasValue()) @@ -189,38 +181,83 @@ CHIP_ERROR DiscoveryImplPlatform::Advertise(const CommissionAdvertisingParameter textEntries[textEntrySize++] = { "VP", reinterpret_cast(vendorProductBuf), strnlen(vendorProductBuf, sizeof(vendorProductBuf)) }; } -#if CHIP_ENABLE_ROTATING_DEVICE_ID - if (textEntrySize < ArraySize(textEntries)) - { - ReturnErrorOnFailure(GenerateRotatingDeviceId(rotatingDeviceIdHexBuffer, rotatingDeviceIdHexBufferSize)); - // Rotating Device ID - textEntries[textEntrySize++] = { "RI", Uint8::from_const_char(rotatingDeviceIdHexBuffer), rotatingDeviceIdHexBufferSize }; - } - else + if (params.GetDeviceType().HasValue()) { - return CHIP_ERROR_INVALID_LIST_LENGTH; + snprintf(deviceTypeBuf, sizeof(deviceTypeBuf), "%u", params.GetDeviceType().Value()); + textEntries[textEntrySize++] = { "DT", reinterpret_cast(deviceTypeBuf), + strnlen(deviceTypeBuf, sizeof(deviceTypeBuf)) }; } -#endif - if (params.GetPairingHint().HasValue() && params.GetPairingInstr().HasValue()) + + if (params.GetDeviceName().HasValue()) { - snprintf(pairingInstrBuf, sizeof(pairingInstrBuf), "%s+%u", params.GetPairingInstr().Value(), - params.GetPairingHint().Value()); - textEntries[textEntrySize++] = { "P", reinterpret_cast(pairingInstrBuf), - strnlen(pairingInstrBuf, sizeof(pairingInstrBuf)) }; + snprintf(deviceNameBuf, sizeof(deviceNameBuf), "%s", params.GetDeviceName().Value()); + textEntries[textEntrySize++] = { "DN", reinterpret_cast(deviceNameBuf), + strnlen(deviceNameBuf, sizeof(deviceNameBuf)) }; } - // TODO: Add missing "CM" / "DT" / "DN" keys + split "P" into "PH"/"PI" to be spec-compliant + // Following fields are for nodes and not for commissioners + if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode) + { + snprintf(discriminatorBuf, sizeof(discriminatorBuf), "%04u", params.GetLongDiscriminator()); + textEntries[textEntrySize++] = { "D", reinterpret_cast(discriminatorBuf), + strnlen(discriminatorBuf, sizeof(discriminatorBuf)) }; + + snprintf(commissioningModeBuf, sizeof(commissioningModeBuf), "%u", params.GetCommissioningMode() ? 1 : 0); + textEntries[textEntrySize++] = { "CM", reinterpret_cast(commissioningModeBuf), + strnlen(commissioningModeBuf, sizeof(commissioningModeBuf)) }; + + if (params.GetCommissioningMode() && params.GetOpenWindowCommissioningMode()) + { + snprintf(additionalPairingBuf, sizeof(additionalPairingBuf), "1"); + textEntries[textEntrySize++] = { "AP", reinterpret_cast(additionalPairingBuf), + strnlen(additionalPairingBuf, sizeof(additionalPairingBuf)) }; + } + + if (params.GetRotatingId().HasValue()) + { + snprintf(rotatingIdBuf, sizeof(rotatingIdBuf), "%s", params.GetRotatingId().Value()); + textEntries[textEntrySize++] = { "RI", reinterpret_cast(rotatingIdBuf), + strnlen(rotatingIdBuf, sizeof(rotatingIdBuf)) }; + } + + if (params.GetPairingHint().HasValue()) + { + snprintf(pairingHintBuf, sizeof(pairingHintBuf), "%u", params.GetPairingHint().Value()); + textEntries[textEntrySize++] = { "PH", reinterpret_cast(pairingHintBuf), + strnlen(pairingHintBuf, sizeof(pairingHintBuf)) }; + } + + if (params.GetPairingInstr().HasValue()) + { + snprintf(pairingInstrBuf, sizeof(pairingInstrBuf), "%s", params.GetPairingInstr().Value()); + textEntries[textEntrySize++] = { "PI", reinterpret_cast(pairingInstrBuf), + strnlen(pairingInstrBuf, sizeof(pairingInstrBuf)) }; + } + + snprintf(shortDiscriminatorSubtype, sizeof(shortDiscriminatorSubtype), "_S%03u", params.GetShortDiscriminator()); + subTypes[subTypeSize++] = shortDiscriminatorSubtype; + snprintf(longDiscriminatorSubtype, sizeof(longDiscriminatorSubtype), "_L%04u", params.GetLongDiscriminator()); + subTypes[subTypeSize++] = longDiscriminatorSubtype; + snprintf(commissioningModeSubType, sizeof(commissioningModeSubType), "_C%u", params.GetCommissioningMode() ? 1 : 0); + subTypes[subTypeSize++] = commissioningModeSubType; + if (params.GetCommissioningMode() && params.GetOpenWindowCommissioningMode()) + { + snprintf(openWindowSubType, sizeof(openWindowSubType), "_A1"); + subTypes[subTypeSize++] = openWindowSubType; + } + } - snprintf(shortDiscriminatorSubtype, sizeof(shortDiscriminatorSubtype), "_S%03u", params.GetShortDiscriminator()); - subTypes[subTypeSize++] = shortDiscriminatorSubtype; - snprintf(longDiscriminatorSubtype, sizeof(longDiscriminatorSubtype), "_L%04u", params.GetLongDiscriminator()); - subTypes[subTypeSize++] = longDiscriminatorSubtype; if (params.GetVendorId().HasValue()) { snprintf(vendorSubType, sizeof(vendorSubType), "_V%u", params.GetVendorId().Value()); subTypes[subTypeSize++] = vendorSubType; } + if (params.GetDeviceType().HasValue()) + { + snprintf(deviceTypeSubType, sizeof(deviceTypeSubType), "_T%u", params.GetDeviceType().Value()); + subTypes[subTypeSize++] = deviceTypeSubType; + } service.mTextEntries = textEntries; service.mTextEntrySize = textEntrySize; @@ -231,9 +268,43 @@ CHIP_ERROR DiscoveryImplPlatform::Advertise(const CommissionAdvertisingParameter service.mAddressType = Inet::kIPAddressType_Any; error = ChipMdnsPublishService(&service); + if (error == CHIP_NO_ERROR) + { + if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode) + { + mCommissionableNodeAdvertisingParams = params; + mIsCommissionableNodePublishing = true; + } + else + { + mCommissionerAdvertisingParams = params; + mIsCommissionerPublishing = true; + } + } + +#ifdef DETAIL_LOGGING + PrintEntries(&service); +#endif return error; } +#ifdef DETAIL_LOGGING +void DiscoveryImplPlatform::PrintEntries(const MdnsService * service) +{ + printf("printEntries port=%d, mTextEntrySize=%d, mSubTypeSize=%d\n", (int) (service->mPort), (int) (service->mTextEntrySize), + (int) (service->mSubTypeSize)); + for (int i = 0; i < (int) service->mTextEntrySize; i++) + { + printf(" entry [%d] : %s %s\n", i, service->mTextEntries[i].mKey, (char *) (service->mTextEntries[i].mData)); + } + + for (int i = 0; i < (int) service->mSubTypeSize; i++) + { + printf(" type [%d] : %s\n", i, service->mSubTypes[i]); + } +} +#endif + CHIP_ERROR DiscoveryImplPlatform::Advertise(const OperationalAdvertisingParameters & params) { MdnsService service; @@ -310,14 +381,25 @@ CHIP_ERROR DiscoveryImplPlatform::Advertise(const OperationalAdvertisingParamete service.mAddressType = Inet::kIPAddressType_Any; error = ChipMdnsPublishService(&service); + if (error == CHIP_NO_ERROR) + { + mIsOperationalPublishing = true; + } + return error; } CHIP_ERROR DiscoveryImplPlatform::StopPublishDevice() { - mIsOperationalPublishing = false; - mIsCommissionalPublishing = false; - return ChipMdnsStopPublish(); + CHIP_ERROR error = ChipMdnsStopPublish(); + + if (error == CHIP_NO_ERROR) + { + mIsOperationalPublishing = false; + mIsCommissionableNodePublishing = false; + mIsCommissionerPublishing = false; + } + return error; } CHIP_ERROR DiscoveryImplPlatform::SetResolverDelegate(ResolverDelegate * delegate) diff --git a/src/lib/mdns/Discovery_ImplPlatform.h b/src/lib/mdns/Discovery_ImplPlatform.h index a076671c21f689..fdacc76ca45710 100644 --- a/src/lib/mdns/Discovery_ImplPlatform.h +++ b/src/lib/mdns/Discovery_ImplPlatform.h @@ -24,6 +24,10 @@ #include #include +// Enable detailed mDNS logging for publish +#undef DETAIL_LOGGING +// #define DETAIL_LOGGING + namespace chip { namespace Mdns { @@ -38,11 +42,11 @@ class DiscoveryImplPlatform : public ServiceAdvertiser, public Resolver /// Advertises the CHIP node as an operational node CHIP_ERROR Advertise(const OperationalAdvertisingParameters & params) override; - /// Advertises the CHIP node as a commisioning/commissionable node + /// Advertises the CHIP node as a commissioner/commissionable node CHIP_ERROR Advertise(const CommissionAdvertisingParameters & params) override; /// This function stops publishing the device on mDNS. - CHIP_ERROR StopPublishDevice(); + CHIP_ERROR StopPublishDevice() override; /// Registers a resolver delegate if none has been registered before CHIP_ERROR SetResolverDelegate(ResolverDelegate * delegate) override; @@ -66,12 +70,17 @@ class DiscoveryImplPlatform : public ServiceAdvertiser, public Resolver static void HandleMdnsError(void * context, CHIP_ERROR initError); static CHIP_ERROR GenerateRotatingDeviceId(char rotatingDeviceIdHexBuffer[], size_t & rotatingDeviceIdHexBufferSize); CHIP_ERROR SetupHostname(chip::ByteSpan macOrEui64); +#ifdef DETAIL_LOGGING + static void PrintEntries(const MdnsService * service); +#endif OperationalAdvertisingParameters mOperationalAdvertisingParams; - bool mIsOperationalPublishing = false; + CommissionAdvertisingParameters mCommissionableNodeAdvertisingParams; + CommissionAdvertisingParameters mCommissionerAdvertisingParams; + bool mIsOperationalPublishing = false; + bool mIsCommissionableNodePublishing = false; + bool mIsCommissionerPublishing = false; uint64_t mCommissionInstanceName; - CommissionAdvertisingParameters mCommissioningdvertisingParams; - bool mIsCommissionalPublishing = false; bool mMdnsInitialized = false; ResolverDelegate * mResolverDelegate = nullptr; diff --git a/src/platform/Darwin/CHIPDevicePlatformConfig.h b/src/platform/Darwin/CHIPDevicePlatformConfig.h index 142bc09cfa6550..95228d41057ef3 100644 --- a/src/platform/Darwin/CHIPDevicePlatformConfig.h +++ b/src/platform/Darwin/CHIPDevicePlatformConfig.h @@ -41,6 +41,8 @@ #define CHIP_DEVICE_CONFIG_PERSISTED_STORAGE_INFO_EIDC_KEY 4 #define CHIP_DEVICE_CONFIG_PERSISTED_STORAGE_DEBUG_EIDC_KEY 5 +#define CHIP_DEVICE_CONFIG_ENABLE_UNPROVISIONED_MDNS 1 + // ========== Platform-specific Configuration ========= // These are configuration options that are unique to Darwin platforms. diff --git a/src/platform/Darwin/MdnsImpl.cpp b/src/platform/Darwin/MdnsImpl.cpp index 111d0956e7f2f4..e0bf76f1894427 100644 --- a/src/platform/Darwin/MdnsImpl.cpp +++ b/src/platform/Darwin/MdnsImpl.cpp @@ -55,6 +55,19 @@ std::string GetFullType(const char * type, MdnsServiceProtocol protocol) return typeBuilder.str(); } +std::string GetFullTypeWithSubTypes(const char * type, MdnsServiceProtocol protocol, const char * subTypes[], size_t subTypeSize) +{ + std::ostringstream typeBuilder; + typeBuilder << type; + typeBuilder << (protocol == MdnsServiceProtocol::kMdnsProtocolUdp ? kProtocolUdp : kProtocolTcp); + for (int i = 0; i < (int) subTypeSize; i++) + { + typeBuilder << ","; + typeBuilder << subTypes[i]; + } + return typeBuilder.str(); +} + } // namespace namespace chip { @@ -143,7 +156,7 @@ CHIP_ERROR MdnsContexts::Removes(ContextType type) return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND; } -CHIP_ERROR MdnsContexts::Get(ContextType type, GenericContext * context) +CHIP_ERROR MdnsContexts::Get(ContextType type, GenericContext ** context) { bool found = false; std::vector::iterator iter; @@ -152,8 +165,26 @@ CHIP_ERROR MdnsContexts::Get(ContextType type, GenericContext * context) { if ((*iter)->type == type) { - context = *iter; - found = true; + *context = *iter; + found = true; + break; + } + } + + return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND; +} + +CHIP_ERROR MdnsContexts::GetRegisterType(const char * type, GenericContext ** context) +{ + bool found = false; + std::vector::iterator iter; + + for (iter = mContexts.begin(); iter != mContexts.end(); iter++) + { + if ((*iter)->type == ContextType::Register && ((RegisterContext *) (*iter))->matches(type)) + { + *context = *iter; + found = true; break; } } @@ -277,12 +308,12 @@ CHIP_ERROR Register(uint32_t interfaceId, const char * type, const char * name, { DNSServiceErrorType err; DNSServiceRef sdRef; - RegisterContext * sdCtx = nullptr; + GenericContext * sdCtx = nullptr; uint16_t recordLen = TXTRecordGetLength(recordRef); const void * recordBytesPtr = TXTRecordGetBytesPtr(recordRef); - if (CHIP_NO_ERROR == MdnsContexts::GetInstance().Get(ContextType::Register, sdCtx)) + if (CHIP_NO_ERROR == MdnsContexts::GetInstance().GetRegisterType(type, &sdCtx)) { err = DNSServiceUpdateRecord(sdCtx->serviceRef, NULL, 0 /* flags */, recordLen, recordBytesPtr, 0 /* ttl */); TXTRecordDeallocate(recordRef); @@ -290,7 +321,7 @@ CHIP_ERROR Register(uint32_t interfaceId, const char * type, const char * name, return CHIP_NO_ERROR; } - sdCtx = chip::Platform::New(nullptr); + sdCtx = chip::Platform::New(type, nullptr); err = DNSServiceRegister(&sdRef, 0 /* flags */, interfaceId, name, type, kLocalDomain, NULL, port, recordLen, recordBytesPtr, OnRegister, sdCtx); TXTRecordDeallocate(recordRef); @@ -471,7 +502,7 @@ CHIP_ERROR ChipMdnsPublishService(const MdnsService * service) VerifyOrReturnError(service != nullptr, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(IsSupportedProtocol(service->mProtocol), CHIP_ERROR_INVALID_ARGUMENT); - std::string regtype = GetFullType(service->mType, service->mProtocol); + std::string regtype = GetFullTypeWithSubTypes(service->mType, service->mProtocol, service->mSubTypes, service->mSubTypeSize); uint32_t interfaceId = GetInterfaceId(service->mInterface); TXTRecordRef record; @@ -483,8 +514,8 @@ CHIP_ERROR ChipMdnsPublishService(const MdnsService * service) CHIP_ERROR ChipMdnsStopPublish() { - RegisterContext * sdCtx = nullptr; - if (CHIP_ERROR_KEY_NOT_FOUND == MdnsContexts::GetInstance().Get(ContextType::Register, sdCtx)) + GenericContext * sdCtx = nullptr; + if (CHIP_ERROR_KEY_NOT_FOUND == MdnsContexts::GetInstance().Get(ContextType::Register, &sdCtx)) { return CHIP_NO_ERROR; } diff --git a/src/platform/Darwin/MdnsImpl.h b/src/platform/Darwin/MdnsImpl.h index 934e38327f1e2e..29a83b85eadb49 100644 --- a/src/platform/Darwin/MdnsImpl.h +++ b/src/platform/Darwin/MdnsImpl.h @@ -42,11 +42,15 @@ struct GenericContext struct RegisterContext : public GenericContext { - RegisterContext(void * cbContext) + char mType[kMdnsTypeMaxSize + 1]; + RegisterContext(const char * sType, void * cbContext) { - type = ContextType::Register; + type = ContextType::Register; + strncpy(mType, sType, sizeof(mType)); context = cbContext; } + + bool matches(const char * sType) { return (strcmp(mType, sType) == 0); } }; struct BrowseContext : public GenericContext @@ -109,7 +113,8 @@ class MdnsContexts CHIP_ERROR Add(GenericContext * context, DNSServiceRef sdRef); CHIP_ERROR Remove(GenericContext * context); CHIP_ERROR Removes(ContextType type); - CHIP_ERROR Get(ContextType type, GenericContext * context); + CHIP_ERROR Get(ContextType type, GenericContext ** context); + CHIP_ERROR GetRegisterType(const char * type, GenericContext ** context); void SetHostname(const char * name) { mHostname = name; } const char * GetHostname() { return mHostname.c_str(); } diff --git a/src/platform/Linux/CHIPDevicePlatformConfig.h b/src/platform/Linux/CHIPDevicePlatformConfig.h index d948cac9a0fac7..a2c98a393d2c92 100644 --- a/src/platform/Linux/CHIPDevicePlatformConfig.h +++ b/src/platform/Linux/CHIPDevicePlatformConfig.h @@ -43,6 +43,8 @@ #define CHIP_DEVICE_CONFIG_PERSISTED_STORAGE_INFO_EIDC_KEY 4 #define CHIP_DEVICE_CONFIG_PERSISTED_STORAGE_DEBUG_EIDC_KEY 5 +#define CHIP_DEVICE_CONFIG_ENABLE_UNPROVISIONED_MDNS 1 + // ========== Platform-specific Configuration ========= // These are configuration options that are unique to Linux platforms.