-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for commisionable advertisement #4337
Changes from 1 commit
31bbe63
cf3d42e
0e36bc2
7fd2c76
377ea28
c90a1c2
3c120cc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,18 +33,21 @@ 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; | ||
Optional<const char *> pairingInstr; | ||
Optional<uint8_t> pairingHint; | ||
|
||
// operational params | ||
uint64_t fabricId = 12345; | ||
|
@@ -61,6 +64,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 = 'I'; | ||
constexpr uint16_t kOptionCommisioningPairingHint = 'H'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. using uppercase seems a bit different than existing flags. I imagine 'H' is to not conflict with 'h'. I would either then update vendorId to use 'V' (and maybe make all others uppercase too) or make the conflicting ones only have a long version like '--pairing-hint'. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think sticking to the long version for conflicting ones is more readable. Will do that. |
||
|
||
constexpr uint16_t kOptionOperationalFabricId = 'f'; | ||
constexpr uint16_t kOptionOperationalNodeId = 'n'; | ||
|
@@ -81,6 +86,10 @@ bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier, | |
{ | ||
gOptions.advertisingMode = AdvertisingMode::kCommisioning; | ||
} | ||
else if ((strcmp(aValue, "commisionable") == 0) || (strcmp(aValue, "d") == 0)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the 'd' is awkward. Please remove 'c' from above instead since 'c' seems ambigous for commisiong/commisionable There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I used 'd' because for commisionable we advertise as _chipd while for commisioning we advertise as _chipc and hence 'c' was used. |
||
{ | ||
gOptions.advertisingMode = AdvertisingMode::kCommisionable; | ||
} | ||
else | ||
{ | ||
PrintArgError("%s: Invalid advertising mode %s\n", aProgram, aValue); | ||
|
@@ -100,6 +109,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; | ||
|
@@ -122,6 +137,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 }, | ||
|
@@ -136,18 +153,24 @@ 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 (o/operational or c/commisioning or d/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" | ||
" -I <value>\n" | ||
" Commisionable pairing instruction.\n" | ||
" --pairing-hint <value>\n" | ||
" -H <value>\n" | ||
" Commisionable pairing hint.\n" | ||
" --fabrid-id <value>\n" | ||
" -f <value>\n" | ||
" Operational fabric id.\n" | ||
|
@@ -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"); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
{ | ||
|
@@ -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; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is there a method to stop this advertisement? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not currently - we assume that 'once a chip device, always a chip device and we advertise'. Having a 'StopAdvertising' seems possible though. |
||
/// Provides the system-wide implementation of the service advertiser | ||
static ServiceAdvertiser & Instance(); | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
|
@@ -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; | ||
|
@@ -559,6 +561,149 @@ 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.GetPairingHint().HasValue()) | ||
{ | ||
// sprintf(txtPairingInstrHint, "P=%d", params.GetPairingHint().Value()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove commented out code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do |
||
sprintf(txtPairingInstrHint, "P=%s+%d", params.GetPairingInstr().Value(), params.GetPairingHint().Value()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to ensure that GetPairingInstr() HasValue. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do |
||
} | ||
|
||
return AllocateQName(txtDiscriminator, txtVidPid, txtPairingInstrHint); | ||
} | ||
|
||
AdvertiserMinMdns gAdvertiser; | ||
} // namespace | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this required for commisionable as well? if not, I think we should add a comment that these 2 are for commisionable only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only required for commisionable. Will add a comment.