Skip to content

Commit

Permalink
Add support for commisionable advertisement (#4337)
Browse files Browse the repository at this point in the history
* Add support for commisionable advertisement

* Minor fixes based on review comments

* Use a flag to enable/disable commisionable mode

* Restyled by clang-format

* Revert enable/disable flag for commisionable mode

After discussions with the group, it was decided that we don't need
a compile time option to enable/disable the commisionable mode, but
instead have some kind of a stop advertising command to do this.

* Restyled by clang-format

Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
arunbharadwaj and restyled-commits authored Jan 14, 2021
1 parent 2c820d0 commit be3279a
Show file tree
Hide file tree
Showing 4 changed files with 250 additions and 8 deletions.
51 changes: 43 additions & 8 deletions examples/minimal-mdns/advertiser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,24 @@ enum class AdvertisingMode
{
kCommisioning,
kOperational,
kCommisionable,
};

struct Options
{
bool enableIpV4 = false;
AdvertisingMode advertisingMode = AdvertisingMode::kCommisioning;

// commisioning params
// commisioning/commisionable params
uint8_t shortDiscriminator = 52;
uint16_t longDiscriminator = 840;
Optional<uint16_t> vendorId;
Optional<uint16_t> productId;

// commisionable params
Optional<const char *> pairingInstr;
Optional<uint8_t> pairingHint;

// operational params
uint64_t fabricId = 12345;
uint64_t nodeId = 6789;
Expand All @@ -61,6 +66,8 @@ constexpr uint16_t kOptionCommisioningShordDiscriminator = 's';
constexpr uint16_t kOptionCommisioningLongDiscriminaotr = 'l';
constexpr uint16_t kOptionCommisioningVendorId = 0x100; // v is used by 'version'
constexpr uint16_t kOptionCommisioningProductId = 'p';
constexpr uint16_t kOptionCommisioningPairingInstr = 0x200; // Just use the long format
constexpr uint16_t kOptionCommisioningPairingHint = 0x300;

constexpr uint16_t kOptionOperationalFabricId = 'f';
constexpr uint16_t kOptionOperationalNodeId = 'n';
Expand All @@ -73,14 +80,18 @@ bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier,
gOptions.enableIpV4 = true;
return true;
case kOptionAdvertisingMode:
if ((strcmp(aValue, "operational") == 0) || (strcmp(aValue, "o") == 0))
if (strcmp(aValue, "operational") == 0)
{
gOptions.advertisingMode = AdvertisingMode::kOperational;
}
else if ((strcmp(aValue, "commisioning") == 0) || (strcmp(aValue, "c") == 0))
else if (strcmp(aValue, "commisioning") == 0)
{
gOptions.advertisingMode = AdvertisingMode::kCommisioning;
}
else if (strcmp(aValue, "commisionable") == 0)
{
gOptions.advertisingMode = AdvertisingMode::kCommisionable;
}
else
{
PrintArgError("%s: Invalid advertising mode %s\n", aProgram, aValue);
Expand All @@ -100,6 +111,12 @@ bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier,
case kOptionCommisioningProductId:
gOptions.productId = Optional<uint16_t>::Value(static_cast<uint16_t>(atoi(aValue)));
return true;
case kOptionCommisioningPairingInstr:
gOptions.pairingInstr = Optional<const char *>::Value(static_cast<const char *>(aValue));
return true;
case kOptionCommisioningPairingHint:
gOptions.pairingHint = Optional<uint8_t>::Value(static_cast<uint8_t>(atoi(aValue)));
return true;
case kOptionOperationalFabricId:
gOptions.fabricId = atoll(aValue);
return true;
Expand All @@ -122,6 +139,8 @@ OptionDef cmdLineOptionsDef[] = {
{ "long-discriminator", kArgumentRequired, kOptionCommisioningLongDiscriminaotr },
{ "vendor-id", kArgumentRequired, kOptionCommisioningVendorId },
{ "product-id", kArgumentRequired, kOptionCommisioningProductId },
{ "pairing-instruction", kArgumentRequired, kOptionCommisioningPairingInstr },
{ "pairing-hint", kArgumentRequired, kOptionCommisioningPairingHint },

{ "fabrid-id", kArgumentRequired, kOptionOperationalFabricId },
{ "node-id", kArgumentRequired, kOptionOperationalNodeId },
Expand All @@ -136,18 +155,22 @@ OptionSet cmdLineOptions = { HandleOptions, cmdLineOptionsDef, "PROGRAM OPTIONS"
#endif
" -m <mode>\n"
" --advertising-mode <mode>\n"
" Advertise in this mode (o/operational or c/commisioning).\n"
" Advertise in this mode (operational or commisioning or commisionable).\n"
" --short-discriminator <value>\n"
" -s <value>\n"
" Commisioning short discriminator.\n"
" Commisioning/commisionable short discriminator.\n"
" --long-discriminator <value>\n"
" -l <value>\n"
" Commisioning long discriminator.\n"
" Commisioning/commisionable long discriminator.\n"
" --vendor-id <value>\n"
" Commisioning vendor id.\n"
" Commisioning/commisionable vendor id.\n"
" --product-id <value>\n"
" -p <value>\n"
" Commisioning product id.\n"
" Commisioning/commisionable product id.\n"
" --pairing-instruction <value>\n"
" Commisionable pairing instruction.\n"
" --pairing-hint <value>\n"
" Commisionable pairing hint.\n"
" --fabrid-id <value>\n"
" -f <value>\n"
" Operational fabric id.\n"
Expand Down Expand Up @@ -207,6 +230,18 @@ int main(int argc, char ** args)
.SetFabricId(gOptions.fabricId)
.SetNodeId(gOptions.nodeId));
}
else if (gOptions.advertisingMode == AdvertisingMode::kCommisionable)
{
err = chip::Mdns::ServiceAdvertiser::Instance().Advertise(chip::Mdns::CommisionableAdvertisingParameters()
.EnableIpV4(gOptions.enableIpV4)
.SetPort(CHIP_PORT)
.SetShortDiscriminator(gOptions.shortDiscriminator)
.SetLongDiscrimininator(gOptions.longDiscriminator)
.SetVendorId(gOptions.vendorId)
.SetProductId(gOptions.productId)
.SetPairingInstr(gOptions.pairingInstr)
.SetPairingHint(gOptions.pairingHint));
}
else
{
fprintf(stderr, "FAILED to determine advertising type.\n");
Expand Down
57 changes: 57 additions & 0 deletions src/lib/mdns/Advertiser.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,60 @@ class CommisioningAdvertisingParameters : public BaseAdvertisingParams<Commision
chip::Optional<uint16_t> mProductId;
};

class CommisionableAdvertisingParameters : public BaseAdvertisingParams<CommisionableAdvertisingParameters>
{
public:
CommisionableAdvertisingParameters & SetShortDiscriminator(uint8_t discriminator)
{
mShortDiscriminator = discriminator;
return *this;
}
uint8_t GetShortDiscriminator() const { return mShortDiscriminator; }

CommisionableAdvertisingParameters & SetLongDiscrimininator(uint16_t discriminator)
{
mLongDiscriminator = discriminator;
return *this;
}
uint16_t GetLongDiscriminator() const { return mLongDiscriminator; }

CommisionableAdvertisingParameters & SetVendorId(Optional<uint16_t> vendorId)
{
mVendorId = vendorId;
return *this;
}
Optional<uint16_t> GetVendorId() const { return mVendorId; }

CommisionableAdvertisingParameters & SetProductId(Optional<uint16_t> productId)
{
mProductId = productId;
return *this;
}
Optional<uint16_t> GetProductId() const { return mProductId; }

CommisionableAdvertisingParameters & SetPairingInstr(Optional<const char *> pairingInstr)
{
mPairingInstr = pairingInstr;
return *this;
}
Optional<const char *> GetPairingInstr() const { return mPairingInstr; }

CommisionableAdvertisingParameters & SetPairingHint(Optional<uint8_t> pairingHint)
{
mPairingHint = pairingHint;
return *this;
}
Optional<uint8_t> GetPairingHint() const { return mPairingHint; }

private:
uint8_t mShortDiscriminator = 0;
uint16_t mLongDiscriminator = 0; // 12-bit according to spec
chip::Optional<uint16_t> mVendorId;
chip::Optional<uint16_t> mProductId;
chip::Optional<const char *> mPairingInstr;
chip::Optional<uint8_t> mPairingHint;
};

/// Handles advertising of CHIP nodes
class ServiceAdvertiser
{
Expand All @@ -129,6 +183,9 @@ class ServiceAdvertiser
/// Advertises the CHIP node as a commisioning node
virtual CHIP_ERROR Advertise(const CommisioningAdvertisingParameters & params) = 0;

/// Advertises the CHIP node as a commisionable node
virtual CHIP_ERROR Advertise(const CommisionableAdvertisingParameters & params) = 0;

/// Provides the system-wide implementation of the service advertiser
static ServiceAdvertiser & Instance();
};
Expand Down
144 changes: 144 additions & 0 deletions src/lib/mdns/Advertiser_ImplMinimalMdns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,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 CommisioningAdvertisingParameters & params) override;
CHIP_ERROR Advertise(const CommisionableAdvertisingParameters & params) override;

// ServerDelegate
void OnQuery(const BytesRange & data, const chip::Inet::IPPacketInfo * info) override;
Expand Down Expand Up @@ -266,6 +267,7 @@ class AdvertiserMinMdns : public ServiceAdvertiser,
}

FullQName GetCommisioningTextEntries(const CommisioningAdvertisingParameters & params);
FullQName GetCommisionableTextEntries(const CommisionableAdvertisingParameters & params);

static constexpr size_t kMaxEndPoints = 10;
static constexpr size_t kMaxRecords = 16;
Expand Down Expand Up @@ -559,6 +561,148 @@ FullQName AdvertiserMinMdns::GetCommisioningTextEntries(const CommisioningAdvert
return AllocateQName(txtDiscriminator, txtVidPid);
}

CHIP_ERROR AdvertiserMinMdns::Advertise(const CommisionableAdvertisingParameters & params)
{
Clear();

// TODO: need to detect colisions here
char nameBuffer[64] = "";
size_t len = snprintf(nameBuffer, sizeof(nameBuffer), "chip-%016" PRIX64, GetRandU64());
if (len >= sizeof(nameBuffer))
{
return CHIP_ERROR_NO_MEMORY;
}

FullQName operationalServiceName = AllocateQName("_chipd", "_udp", "local");
FullQName operationalServerName = AllocateQName(nameBuffer, "_chipd", "_udp", "local");
FullQName serverName = AllocateQName(nameBuffer, "local");

if ((operationalServiceName.nameCount == 0) || (operationalServerName.nameCount == 0) || (serverName.nameCount == 0))
{
ChipLogError(Discovery, "Failed to allocate QNames.");
return CHIP_ERROR_NO_MEMORY;
}

if (!AddResponder<PtrResponder>(operationalServiceName, operationalServerName)
.SetReportAdditional(operationalServerName)
.SetReportInServiceListing(true)
.IsValid())
{
ChipLogError(Discovery, "Failed to add service PTR record mDNS responder");
return CHIP_ERROR_NO_MEMORY;
}

if (!AddResponder<SrvResponder>(SrvResourceRecord(operationalServerName, serverName, params.GetPort()))
.SetReportAdditional(serverName)
.IsValid())
{
ChipLogError(Discovery, "Failed to add SRV record mDNS responder");
return CHIP_ERROR_NO_MEMORY;
}
if (!AddResponder<IPv6Responder>(serverName).IsValid())
{
ChipLogError(Discovery, "Failed to add IPv6 mDNS responder");
return CHIP_ERROR_NO_MEMORY;
}

if (params.IsIPv4Enabled())
{
if (!AddResponder<IPv4Responder>(serverName).IsValid())
{
ChipLogError(Discovery, "Failed to add IPv4 mDNS responder");
return CHIP_ERROR_NO_MEMORY;
}
}

{
sprintf(nameBuffer, "S%03d", params.GetShortDiscriminator());
FullQName shortServiceName = AllocateQName(nameBuffer, "_sub", "_chipd", "_udp", "local");
ReturnErrorCodeIf(shortServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY);

if (!AddResponder<PtrResponder>(shortServiceName, operationalServerName)
.SetReportAdditional(operationalServerName)
.SetReportInServiceListing(true)
.IsValid())
{
ChipLogError(Discovery, "Failed to add short discriminator PTR record mDNS responder");
return CHIP_ERROR_NO_MEMORY;
}
}

{
sprintf(nameBuffer, "L%04d", params.GetLongDiscriminator());
FullQName longServiceName = AllocateQName(nameBuffer, "_sub", "_chipd", "_udp", "local");
ReturnErrorCodeIf(longServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY);
if (!AddResponder<PtrResponder>(longServiceName, operationalServerName)
.SetReportAdditional(operationalServerName)
.SetReportInServiceListing(true)
.IsValid())
{
ChipLogError(Discovery, "Failed to add long discriminator PTR record mDNS responder");
return CHIP_ERROR_NO_MEMORY;
}
}

if (params.GetVendorId().HasValue())
{
sprintf(nameBuffer, "V%d", params.GetVendorId().Value());
FullQName vendorServiceName = AllocateQName(nameBuffer, "_sub", "_chipd", "_udp", "local");
ReturnErrorCodeIf(vendorServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY);

if (!AddResponder<PtrResponder>(vendorServiceName, operationalServerName)
.SetReportAdditional(operationalServerName)
.SetReportInServiceListing(true)
.IsValid())
{
ChipLogError(Discovery, "Failed to add vendor discriminator PTR record mDNS responder");
return CHIP_ERROR_NO_MEMORY;
}
}

if (!AddResponder<TxtResponder>(TxtResourceRecord(operationalServerName, GetCommisionableTextEntries(params)))
.SetReportAdditional(serverName)
.IsValid())
{
ChipLogError(Discovery, "Failed to add TXT record mDNS responder");
return CHIP_ERROR_NO_MEMORY;
}

ChipLogProgress(Discovery, "CHIP minimal mDNS configured as 'Commisionable device'.");

return CHIP_NO_ERROR;
}

FullQName AdvertiserMinMdns::GetCommisionableTextEntries(const CommisionableAdvertisingParameters & params)
{
// a discriminator always exists
char txtDiscriminator[32];
sprintf(txtDiscriminator, "D=%d", params.GetLongDiscriminator());

if (!params.GetVendorId().HasValue())
{
return AllocateQName(txtDiscriminator);
}

// Need to also set a vid/pid string
char txtVidPid[64];
if (params.GetProductId().HasValue())
{
sprintf(txtVidPid, "V=%d+%d", params.GetVendorId().Value(), params.GetProductId().Value());
}
else
{
sprintf(txtVidPid, "V=%d", params.GetVendorId().Value());
}

char txtPairingInstrHint[128];
if (params.GetPairingInstr().HasValue() && params.GetPairingHint().HasValue())
{
sprintf(txtPairingInstrHint, "P=%s+%d", params.GetPairingInstr().Value(), params.GetPairingHint().Value());
}

return AllocateQName(txtDiscriminator, txtVidPid, txtPairingInstrHint);
}

AdvertiserMinMdns gAdvertiser;
} // namespace

Expand Down
6 changes: 6 additions & 0 deletions src/lib/mdns/Advertiser_ImplNone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ class NoneAdvertiser : public ServiceAdvertiser
ChipLogError(Discovery, "mDNS advertising not available. Commisioning Advertisement failed.");
return CHIP_ERROR_NOT_IMPLEMENTED;
}

CHIP_ERROR Advertise(const CommisionableAdvertisingParameters & params) override
{
ChipLogError(Discovery, "mDNS advertising not available. Commisionable Advertisement failed.");
return CHIP_ERROR_NOT_IMPLEMENTED;
}
};

NoneAdvertiser gAdvertiser;
Expand Down

0 comments on commit be3279a

Please sign in to comment.