/* * * Copyright (c) 2020 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include using namespace chip; namespace { enum class AdvertisingMode { kCommissionableNode, kOperational, kOperationalMultiAdmin, kCommissioner, }; struct Options { bool enableIpV4 = false; AdvertisingMode advertisingMode = AdvertisingMode::kCommissionableNode; // commissionable node / commissioner params std::optional vendorId; std::optional productId; std::optional deviceType; std::optional deviceName; // commissionable node params uint8_t shortDiscriminator = 52; uint16_t longDiscriminator = 840; Dnssd::CommissioningMode commissioningMode = Dnssd::CommissioningMode::kDisabled; std::optional rotatingId; std::optional pairingInstr; std::optional pairingHint; // operational params uint64_t fabricId = 12345; uint64_t nodeId = 6789; uint8_t mac[6] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; } gOptions; using namespace chip::ArgParser; constexpr uint16_t kOptionEnableIpV4 = '4'; constexpr uint16_t kOptionAdvertisingMode = 'm'; constexpr uint16_t kOptionCommissioningShortDiscriminator = 's'; constexpr uint16_t kOptionCommissioningLongDiscriminaotr = 'l'; constexpr uint16_t kOptionCommissioningVendorId = 0x100; // v is used by 'version' constexpr uint16_t kOptionCommissioningProductId = 'p'; constexpr uint16_t kOptionCommissioningPairingInstr = 0x200; // Just use the long format constexpr uint16_t kOptionCommissioningPairingHint = 0x300; constexpr uint16_t kOptionCommissioningDeviceType = 0x400; constexpr uint16_t kOptionCommissioningDeviceName = 0x500; constexpr uint16_t kOptionCommissioningMode = 0x600; constexpr uint16_t kOptionCommissioningRotatingId = 0x700; constexpr uint16_t kOptionOperationalFabricId = 'f'; constexpr uint16_t kOptionOperationalNodeId = 'n'; constexpr uint16_t kOptionTraceTo = 't'; // Only used for argument parsing. Tracing setup owned by the main loop. chip::CommandLineApp::TracingSetup * tracing_setup_for_argparse = nullptr; bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue) { uint8_t cm; switch (aIdentifier) { case kOptionEnableIpV4: gOptions.enableIpV4 = true; return true; case kOptionTraceTo: tracing_setup_for_argparse->EnableTracingFor(aValue); return true; case kOptionAdvertisingMode: if (strcmp(aValue, "operational") == 0) { gOptions.advertisingMode = AdvertisingMode::kOperational; } else if (strcmp(aValue, "operational-multi-admin") == 0) { gOptions.advertisingMode = AdvertisingMode::kOperationalMultiAdmin; } else if (strcmp(aValue, "commissionable-node") == 0) { gOptions.advertisingMode = AdvertisingMode::kCommissionableNode; } else if (strcmp(aValue, "commissioner") == 0) { gOptions.advertisingMode = AdvertisingMode::kCommissioner; } else { PrintArgError("%s: Invalid advertising mode %s\n", aProgram, aValue); return false; } return true; case kOptionCommissioningShortDiscriminator: gOptions.shortDiscriminator = static_cast(atoi(aValue)); return true; case kOptionCommissioningLongDiscriminaotr: gOptions.longDiscriminator = static_cast(atoi(aValue)); return true; case kOptionCommissioningVendorId: gOptions.vendorId = std::make_optional(static_cast(atoi(aValue))); return true; case kOptionCommissioningProductId: gOptions.productId = std::make_optional(static_cast(atoi(aValue))); return true; case kOptionCommissioningMode: cm = static_cast(atoi(aValue)); if (cm == 1) { gOptions.commissioningMode = Dnssd::CommissioningMode::kEnabledBasic; } if (cm == 2) { gOptions.commissioningMode = Dnssd::CommissioningMode::kEnabledEnhanced; } return true; case kOptionCommissioningDeviceType: gOptions.deviceType = std::make_optional(static_cast(atoi(aValue))); return true; case kOptionCommissioningDeviceName: gOptions.deviceName = std::make_optional(static_cast(aValue)); return true; case kOptionCommissioningRotatingId: gOptions.rotatingId = std::make_optional(static_cast(aValue)); return true; case kOptionCommissioningPairingInstr: gOptions.pairingInstr = std::make_optional(static_cast(aValue)); return true; case kOptionCommissioningPairingHint: gOptions.pairingHint = std::make_optional(static_cast(atoi(aValue))); return true; case kOptionOperationalFabricId: if (sscanf(aValue, "%" SCNx64, &gOptions.fabricId) != 1) { PrintArgError("%s: Invalid fabric id: %s\n", aProgram, aValue); return false; } return true; case kOptionOperationalNodeId: if (sscanf(aValue, "%" SCNx64, &gOptions.nodeId) != 1) { PrintArgError("%s: Invalid node id: %s\n", aProgram, aValue); return false; } return true; default: PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName); return false; } } OptionDef cmdLineOptionsDef[] = { #if INET_CONFIG_ENABLE_IPV4 { "enable-ip-v4", kNoArgument, kOptionEnableIpV4 }, #endif { "advertising-mode", kArgumentRequired, kOptionAdvertisingMode }, { "short-discriminator", kArgumentRequired, kOptionCommissioningShortDiscriminator }, { "long-discriminator", kArgumentRequired, kOptionCommissioningLongDiscriminaotr }, { "vendor-id", kArgumentRequired, kOptionCommissioningVendorId }, { "product-id", kArgumentRequired, kOptionCommissioningProductId }, { "commissioning-mode", kNoArgument, kOptionCommissioningMode }, { "device-type", kArgumentRequired, kOptionCommissioningDeviceType }, { "device-name", kArgumentRequired, kOptionCommissioningDeviceName }, { "rotating-id", kArgumentRequired, kOptionCommissioningRotatingId }, { "pairing-instruction", kArgumentRequired, kOptionCommissioningPairingInstr }, { "pairing-hint", kArgumentRequired, kOptionCommissioningPairingHint }, { "fabric-id", kArgumentRequired, kOptionOperationalFabricId }, { "node-id", kArgumentRequired, kOptionOperationalNodeId }, { "trace-to", kArgumentRequired, kOptionTraceTo }, {}, }; OptionSet cmdLineOptions = { HandleOptions, cmdLineOptionsDef, "PROGRAM OPTIONS", #if INET_CONFIG_ENABLE_IPV4 " -4\n" " --enable-ip-v4\n" " enable listening on IPv4\n" #endif " -m \n" " --advertising-mode \n" " Advertise in this mode (operational, operational-multi-admin, commissionable-node or commissioner).\n" " --short-discriminator \n" " -s \n" " Commissioning/commissionable short discriminator.\n" " --long-discriminator \n" " -l \n" " Commissioning/commissionable long discriminator.\n" " --vendor-id \n" " Commissioning/commissionable vendor id.\n" " --product-id \n" " -p \n" " Commissioning/commissionable product id.\n" " --commissioning-mode \n" " Commissioning Mode (0=disabled, 1=basic, 2=enhanced).\n" " --device-type \n" " Device type id.\n" " --device-name \n" " Name of device.\n" " --rotating-id \n" " Rotating Id.\n" " --pairing-instruction \n" " Commissionable pairing instruction.\n" " --pairing-hint \n" " Commissionable pairing hint.\n" " --fabric-id \n" " -f \n" " Operational fabric id.\n" " --node-id \n" " -n \n" " Operational node id.\n" " -t \n" " --trace-to \n" " trace to the given destination (supported: " SUPPORTED_COMMAND_LINE_TRACING_TARGETS ").\n" "\n" }; HelpOptions helpOptions("advertiser", "Usage: advertiser [options]", "1.0"); OptionSet * allOptions[] = { &cmdLineOptions, &helpOptions, nullptr }; void StopSignalHandler(int signal) { DeviceLayer::PlatformMgr().StopEventLoopTask(); } } // namespace int main(int argc, char ** args) { if (Platform::MemoryInit() != CHIP_NO_ERROR) { fprintf(stderr, "FAILED to initialize memory\n"); return 1; } if (DeviceLayer::PlatformMgr().InitChipStack() != CHIP_NO_ERROR) { fprintf(stderr, "FAILED to initialize chip stack\n"); return 1; } chip::CommandLineApp::TracingSetup tracing_setup; tracing_setup_for_argparse = &tracing_setup; if (!chip::ArgParser::ParseArgs(args[0], argc, args, allOptions)) { return 1; } tracing_setup_for_argparse = nullptr; if (chip::Dnssd::ServiceAdvertiser::Instance().Init(DeviceLayer::UDPEndPointManager()) != CHIP_NO_ERROR) { fprintf(stderr, "FAILED to start MDNS advertisement\n"); return 1; } CHIP_ERROR err; if (gOptions.advertisingMode == AdvertisingMode::kCommissionableNode) { printf("Advertise Commissionable Node\n"); err = chip::Dnssd::ServiceAdvertiser::Instance().Advertise(chip::Dnssd::CommissionAdvertisingParameters() .EnableIpV4(gOptions.enableIpV4) .SetPort(CHIP_PORT) .SetShortDiscriminator(gOptions.shortDiscriminator) .SetLongDiscriminator(gOptions.longDiscriminator) .SetMac(chip::ByteSpan(gOptions.mac, 6)) .SetVendorId(gOptions.vendorId) .SetProductId(gOptions.productId) .SetCommissioningMode(gOptions.commissioningMode) .SetDeviceType(gOptions.deviceType) .SetDeviceName(gOptions.deviceName) .SetRotatingDeviceId(gOptions.rotatingId) .SetPairingInstruction(gOptions.pairingInstr) .SetPairingHint(gOptions.pairingHint)); } else if (gOptions.advertisingMode == AdvertisingMode::kOperational) { err = chip::Dnssd::ServiceAdvertiser::Instance().Advertise( chip::Dnssd::OperationalAdvertisingParameters() .EnableIpV4(gOptions.enableIpV4) .SetPort(CHIP_PORT) .SetMac(chip::ByteSpan(gOptions.mac, 6)) .SetPeerId(PeerId().SetCompressedFabricId(gOptions.fabricId).SetNodeId(gOptions.nodeId))); } else if (gOptions.advertisingMode == AdvertisingMode::kOperationalMultiAdmin) { err = chip::Dnssd::ServiceAdvertiser::Instance().Advertise( chip::Dnssd::OperationalAdvertisingParameters() .EnableIpV4(gOptions.enableIpV4) .SetPort(CHIP_PORT) .SetMac(chip::ByteSpan(gOptions.mac, 6)) .SetPeerId(PeerId().SetCompressedFabricId(gOptions.fabricId).SetNodeId(gOptions.nodeId))); if (err == CHIP_NO_ERROR) { err = chip::Dnssd::ServiceAdvertiser::Instance().Advertise( chip::Dnssd::OperationalAdvertisingParameters() .EnableIpV4(gOptions.enableIpV4) .SetPort(CHIP_PORT + 1) .SetMac(chip::ByteSpan(gOptions.mac, 6)) .SetPeerId(PeerId().SetCompressedFabricId(gOptions.fabricId + 1).SetNodeId(gOptions.nodeId + 1))); } if (err == CHIP_NO_ERROR) { err = chip::Dnssd::ServiceAdvertiser::Instance().Advertise( chip::Dnssd::OperationalAdvertisingParameters() .EnableIpV4(gOptions.enableIpV4) .SetPort(CHIP_PORT + 2) .SetMac(chip::ByteSpan(gOptions.mac, 6)) .SetPeerId(PeerId().SetCompressedFabricId(gOptions.fabricId + 2).SetNodeId(gOptions.nodeId + 2))); } } else if (gOptions.advertisingMode == AdvertisingMode::kCommissioner) { printf("Advertise Commissioner\n"); err = chip::Dnssd::ServiceAdvertiser::Instance().Advertise( chip::Dnssd::CommissionAdvertisingParameters() .EnableIpV4(gOptions.enableIpV4) .SetPort(CHIP_PORT) .SetMac(chip::ByteSpan(gOptions.mac, 6)) .SetVendorId(gOptions.vendorId) .SetProductId(gOptions.productId) .SetDeviceType(gOptions.deviceType) .SetDeviceName(gOptions.deviceName) .SetCommissionAdvertiseMode(chip::Dnssd::CommssionAdvertiseMode::kCommissioner)); } else { fprintf(stderr, "FAILED to determine advertising type.\n"); return 1; } if (err != CHIP_NO_ERROR) { fprintf(stderr, "FAILED to setup advertisement parameters err=%s\n", chip::ErrorStr(err)); return 1; } signal(SIGTERM, StopSignalHandler); signal(SIGINT, StopSignalHandler); DeviceLayer::PlatformMgr().RunEventLoop(); tracing_setup.StopTracing(); Dnssd::Resolver::Instance().Shutdown(); DeviceLayer::PlatformMgr().Shutdown(); printf("Done...\n"); return 0; }