Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2020 Project CHIP Authors 4 : * 5 : * Licensed under the Apache License, Version 2.0 (the "License"); 6 : * you may not use this file except in compliance with the License. 7 : * You may obtain a copy of the License at 8 : * 9 : * http://www.apache.org/licenses/LICENSE-2.0 10 : * 11 : * Unless required by applicable law or agreed to in writing, software 12 : * distributed under the License is distributed on an "AS IS" BASIS, 13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 : * See the License for the specific language governing permissions and 15 : * limitations under the License. 16 : */ 17 : 18 : #pragma once 19 : 20 : #include <algorithm> 21 : #include <cstdint> 22 : 23 : #include <lib/core/CHIPError.h> 24 : #include <lib/core/Optional.h> 25 : #include <lib/core/PeerId.h> 26 : #include <lib/dnssd/TxtFields.h> 27 : #include <lib/support/CHIPMemString.h> 28 : #include <lib/support/SafeString.h> 29 : #include <lib/support/Span.h> 30 : 31 : namespace chip { 32 : namespace Dnssd { 33 : 34 : static constexpr uint16_t kMdnsPort = 5353; 35 : // Need 8 bytes to fit a thread mac. 36 : static constexpr size_t kMaxMacSize = 8; 37 : 38 : enum class CommssionAdvertiseMode : uint8_t 39 : { 40 : kCommissionableNode, 41 : kCommissioner, 42 : }; 43 : 44 : enum class CommissioningMode 45 : { 46 : kDisabled, // Commissioning Mode is disabled, CM=0 in DNS-SD key/value pairs 47 : kEnabledBasic, // Basic Commissioning Mode, CM=1 in DNS-SD key/value pairs 48 : kEnabledEnhanced // Enhanced Commissioning Mode, CM=2 in DNS-SD key/value pairs 49 : }; 50 : 51 : enum class ICDModeAdvertise : uint8_t 52 : { 53 : kNone, // The device does not support the LIT feature-set. No ICD= key is advertised in DNS-SD. 54 : kSIT, // The ICD supports the LIT feature-set, but is currently operating as a SIT. ICD=0 in DNS-SD key/value pairs. 55 : kLIT, // The ICD is currently operating as a LIT. ICD=1 in DNS-SD key/value pairs. 56 : }; 57 : 58 : template <class Derived> 59 : class BaseAdvertisingParams 60 : { 61 : public: 62 : static constexpr uint8_t kCommonTxtMaxNumber = KeyCount(TxtKeyUse::kCommon); 63 : static constexpr size_t kCommonTxtMaxKeySize = MaxKeyLen(TxtKeyUse::kCommon); 64 : static constexpr size_t kCommonTxtMaxValueSize = MaxValueLen(TxtKeyUse::kCommon); 65 : static constexpr size_t kCommonTxtTotalKeySize = TotalKeyLen(TxtKeyUse::kCommon); 66 : static constexpr size_t kCommonTxtTotalValueSize = TotalValueLen(TxtKeyUse::kCommon); 67 : 68 8 : Derived & SetPort(uint16_t port) 69 : { 70 8 : mPort = port; 71 8 : return *reinterpret_cast<Derived *>(this); 72 : } 73 20 : uint16_t GetPort() const { return mPort; } 74 : 75 8 : Derived & SetInterfaceId(Inet::InterfaceId interfaceId) 76 : { 77 8 : mInterfaceId = interfaceId; 78 8 : return *reinterpret_cast<Derived *>(this); 79 : } 80 : 81 : Inet::InterfaceId GetInterfaceId() const { return mInterfaceId; } 82 : 83 8 : Derived & EnableIpV4(bool enable) 84 : { 85 8 : mEnableIPv4 = enable; 86 8 : return *reinterpret_cast<Derived *>(this); 87 : } 88 20 : bool IsIPv4Enabled() const { return mEnableIPv4; } 89 8 : Derived & SetMac(chip::ByteSpan mac) 90 : { 91 8 : mMacLength = std::min(mac.size(), kMaxMacSize); 92 8 : memcpy(mMacStorage, mac.data(), mMacLength); 93 8 : return *reinterpret_cast<Derived *>(this); 94 : } 95 20 : const chip::ByteSpan GetMac() const { return chip::ByteSpan(mMacStorage, mMacLength); } 96 : 97 : // Common Flags 98 8 : Derived & SetLocalMRPConfig(const Optional<ReliableMessageProtocolConfig> & config) 99 : { 100 8 : mLocalMRPConfig = config; 101 8 : return *reinterpret_cast<Derived *>(this); 102 : } 103 20 : const Optional<ReliableMessageProtocolConfig> & GetLocalMRPConfig() const { return mLocalMRPConfig; } 104 : 105 : // NOTE: The SetTcpSupported API is deprecated and not compliant with 1.3. T flag should not be set. 106 : Derived & SetTcpSupported(Optional<bool> tcpSupported) 107 : { 108 : mTcpSupported = tcpSupported; 109 : return *reinterpret_cast<Derived *>(this); 110 : } 111 20 : Optional<bool> GetTcpSupported() const { return mTcpSupported; } 112 : 113 : Derived & SetICDModeToAdvertise(ICDModeAdvertise operatingMode) 114 : { 115 : mICDModeAdvertise = operatingMode; 116 : return *reinterpret_cast<Derived *>(this); 117 : } 118 27 : ICDModeAdvertise GetICDModeToAdvertise() const { return mICDModeAdvertise; } 119 : 120 : private: 121 : uint16_t mPort = CHIP_PORT; 122 : Inet::InterfaceId mInterfaceId = Inet::InterfaceId::Null(); 123 : bool mEnableIPv4 = true; 124 : uint8_t mMacStorage[kMaxMacSize] = {}; 125 : size_t mMacLength = 0; 126 : Optional<ReliableMessageProtocolConfig> mLocalMRPConfig; 127 : Optional<bool> mTcpSupported; 128 : ICDModeAdvertise mICDModeAdvertise = ICDModeAdvertise::kNone; 129 : }; 130 : 131 : /// Defines parameters required for advertising a CHIP node 132 : /// over mDNS as an 'operationally ready' node. 133 : class OperationalAdvertisingParameters : public BaseAdvertisingParams<OperationalAdvertisingParameters> 134 : { 135 : public: 136 : // Operational uses only common keys 137 : static constexpr uint8_t kTxtMaxNumber = kCommonTxtMaxNumber; 138 : static constexpr uint8_t kTxtMaxKeySize = kCommonTxtMaxKeySize; 139 : static constexpr uint8_t kTxtMaxValueSize = kCommonTxtMaxValueSize; 140 : static constexpr size_t kTxtTotalKeySize = kCommonTxtTotalKeySize; 141 : static constexpr size_t kTxtTotalValueSize = kCommonTxtTotalValueSize; 142 : 143 0 : OperationalAdvertisingParameters & SetPeerId(const PeerId & peerId) 144 : { 145 0 : mPeerId = peerId; 146 0 : return *this; 147 : } 148 16 : PeerId GetPeerId() const { return mPeerId; } 149 : 150 : CompressedFabricId GetCompressedFabricId() const { return mPeerId.GetCompressedFabricId(); } 151 : 152 : private: 153 : PeerId mPeerId; 154 : }; 155 : 156 : class CommissionAdvertisingParameters : public BaseAdvertisingParams<CommissionAdvertisingParameters> 157 : { 158 : public: 159 : static constexpr uint8_t kTxtMaxNumber = kCommonTxtMaxNumber + KeyCount(TxtKeyUse::kCommission); 160 : static constexpr uint8_t kTxtMaxKeySize = std::max(kCommonTxtMaxKeySize, MaxKeyLen(TxtKeyUse::kCommission)); 161 : static constexpr uint8_t kTxtMaxValueSize = std::max(kCommonTxtMaxValueSize, MaxValueLen(TxtKeyUse::kCommission)); 162 : static constexpr size_t kTxtTotalKeySize = kCommonTxtTotalKeySize + TotalKeyLen(TxtKeyUse::kCommission); 163 : static constexpr size_t kTxtTotalValueSize = kCommonTxtTotalValueSize + TotalValueLen(TxtKeyUse::kCommission); 164 : 165 8 : CommissionAdvertisingParameters & SetShortDiscriminator(uint8_t discriminator) 166 : { 167 8 : mShortDiscriminator = discriminator; 168 8 : return *this; 169 : } 170 20 : uint8_t GetShortDiscriminator() const { return mShortDiscriminator; } 171 : 172 8 : CommissionAdvertisingParameters & SetLongDiscriminator(uint16_t discriminator) 173 : { 174 8 : mLongDiscriminator = discriminator; 175 8 : return *this; 176 : } 177 32 : uint16_t GetLongDiscriminator() const { return mLongDiscriminator; } 178 : 179 8 : CommissionAdvertisingParameters & SetVendorId(Optional<uint16_t> vendorId) 180 : { 181 8 : mVendorId = vendorId; 182 8 : return *this; 183 : } 184 54 : Optional<uint16_t> GetVendorId() const { return mVendorId; } 185 : 186 8 : CommissionAdvertisingParameters & SetProductId(Optional<uint16_t> productId) 187 : { 188 8 : mProductId = productId; 189 8 : return *this; 190 : } 191 31 : Optional<uint16_t> GetProductId() const { return mProductId; } 192 : 193 8 : CommissionAdvertisingParameters & SetCommissioningMode(CommissioningMode mode) 194 : { 195 8 : mCommissioningMode = mode; 196 8 : return *this; 197 : } 198 32 : CommissioningMode GetCommissioningMode() const { return mCommissioningMode; } 199 : 200 0 : CommissionAdvertisingParameters & SetDeviceType(Optional<uint32_t> deviceType) 201 : { 202 0 : mDeviceType = deviceType; 203 0 : return *this; 204 : } 205 30 : Optional<uint32_t> GetDeviceType() const { return mDeviceType; } 206 : 207 0 : CommissionAdvertisingParameters & SetDeviceName(Optional<const char *> deviceName) 208 : { 209 0 : if (deviceName.HasValue()) 210 : { 211 0 : Platform::CopyString(mDeviceName, sizeof(mDeviceName), deviceName.Value()); 212 0 : mDeviceNameHasValue = true; 213 : } 214 : else 215 : { 216 0 : mDeviceNameHasValue = false; 217 : } 218 0 : return *this; 219 : } 220 15 : Optional<const char *> GetDeviceName() const 221 : { 222 15 : return mDeviceNameHasValue ? Optional<const char *>::Value(mDeviceName) : Optional<const char *>::Missing(); 223 : } 224 : 225 : CommissionAdvertisingParameters & SetRotatingDeviceId(Optional<const char *> rotatingId) 226 : { 227 : if (rotatingId.HasValue()) 228 : { 229 : Platform::CopyString(mRotatingId, sizeof(mRotatingId), rotatingId.Value()); 230 : mRotatingIdHasValue = true; 231 : } 232 : else 233 : { 234 : mRotatingIdHasValue = false; 235 : } 236 : return *this; 237 : } 238 15 : Optional<const char *> GetRotatingDeviceId() const 239 : { 240 15 : return mRotatingIdHasValue ? Optional<const char *>::Value(mRotatingId) : Optional<const char *>::Missing(); 241 : } 242 : 243 8 : CommissionAdvertisingParameters & SetPairingInstruction(Optional<const char *> pairingInstr) 244 : { 245 8 : if (pairingInstr.HasValue()) 246 : { 247 8 : Platform::CopyString(mPairingInstr, sizeof(mPairingInstr), pairingInstr.Value()); 248 8 : mPairingInstrHasValue = true; 249 : } 250 : else 251 : { 252 0 : mPairingInstrHasValue = false; 253 : } 254 8 : return *this; 255 : } 256 23 : Optional<const char *> GetPairingInstruction() const 257 : { 258 23 : return mPairingInstrHasValue ? Optional<const char *>::Value(mPairingInstr) : Optional<const char *>::Missing(); 259 : } 260 : 261 8 : CommissionAdvertisingParameters & SetPairingHint(Optional<uint16_t> pairingHint) 262 : { 263 8 : mPairingHint = pairingHint; 264 8 : return *this; 265 : } 266 23 : Optional<uint16_t> GetPairingHint() const { return mPairingHint; } 267 : 268 8 : CommissionAdvertisingParameters & SetCommissionAdvertiseMode(CommssionAdvertiseMode mode) 269 : { 270 8 : mMode = mode; 271 8 : return *this; 272 : } 273 84 : CommssionAdvertiseMode GetCommissionAdvertiseMode() const { return mMode; } 274 : 275 : CommissionAdvertisingParameters & SetCommissionerPasscodeSupported(Optional<bool> commissionerPasscodeSupported) 276 : { 277 : mCommissionerPasscodeSupported = commissionerPasscodeSupported; 278 : return *this; 279 : } 280 8 : Optional<bool> GetCommissionerPasscodeSupported() const { return mCommissionerPasscodeSupported; } 281 : 282 : private: 283 : uint8_t mShortDiscriminator = 0; 284 : uint16_t mLongDiscriminator = 0; // 12-bit according to spec 285 : CommssionAdvertiseMode mMode = CommssionAdvertiseMode::kCommissionableNode; 286 : CommissioningMode mCommissioningMode = CommissioningMode::kEnabledBasic; 287 : chip::Optional<uint16_t> mVendorId; 288 : chip::Optional<uint16_t> mProductId; 289 : chip::Optional<uint32_t> mDeviceType; 290 : chip::Optional<uint16_t> mPairingHint; 291 : 292 : char mDeviceName[kKeyDeviceNameMaxLength + 1]; 293 : bool mDeviceNameHasValue = false; 294 : 295 : char mRotatingId[kKeyRotatingDeviceIdMaxLength + 1]; 296 : bool mRotatingIdHasValue = false; 297 : 298 : char mPairingInstr[kKeyPairingInstructionMaxLength + 1]; 299 : bool mPairingInstrHasValue = false; 300 : 301 : Optional<bool> mCommissionerPasscodeSupported; 302 : }; 303 : 304 : /** 305 : * Interface for advertising CHIP DNS-SD services. 306 : * 307 : * A user of this interface must first initialize the advertiser using the `Init` method. 308 : * 309 : * Then, whenever advertised services need to be refreshed, the following sequence of events must 310 : * occur: 311 : * 1. Call the `RemoveServices` method. 312 : * 2. Call one of the `Advertise` methods for each service to be added or updated. 313 : * 3. Call the `FinalizeServiceUpdate` method to finalize the update and apply all pending changes. 314 : */ 315 : class ServiceAdvertiser 316 : { 317 : public: 318 2 : virtual ~ServiceAdvertiser() {} 319 : 320 : /** 321 : * Initializes the advertiser. 322 : * 323 : * The method must be called before other methods of this class. 324 : * If the advertiser has already been initialized, the method exits immediately with no error. 325 : */ 326 : virtual CHIP_ERROR Init(chip::Inet::EndPointManager<chip::Inet::UDPEndPoint> * udpEndPointManager) = 0; 327 : 328 : /** 329 : * Returns whether the advertiser has completed the initialization. 330 : * 331 : * Returns true if the advertiser is ready to advertise services. 332 : */ 333 : virtual bool IsInitialized() = 0; 334 : 335 : /** 336 : * Shuts down the advertiser. 337 : */ 338 : virtual void Shutdown() = 0; 339 : 340 : /** 341 : * Removes or marks all services being advertised for removal. 342 : * 343 : * Depending on the implementation, the method may either stop advertising existing services 344 : * immediately, or mark them for removal upon the subsequent `FinalizeServiceUpdate` method call. 345 : */ 346 : virtual CHIP_ERROR RemoveServices() = 0; 347 : 348 : /** 349 : * Advertises the given operational node service. 350 : */ 351 : virtual CHIP_ERROR Advertise(const OperationalAdvertisingParameters & params) = 0; 352 : 353 : /** 354 : * Advertises the given commissionable/commissioner node service. 355 : */ 356 : virtual CHIP_ERROR Advertise(const CommissionAdvertisingParameters & params) = 0; 357 : 358 : /** 359 : * Finalizes updating advertised services. 360 : * 361 : * This method can be used by some implementations to apply changes made with the `RemoveServices` 362 : * and `Advertise` methods in case they could not be applied immediately. 363 : */ 364 : virtual CHIP_ERROR FinalizeServiceUpdate() = 0; 365 : 366 : /** 367 : * Returns the commissionable node service instance name formatted as hex string. 368 : */ 369 : virtual CHIP_ERROR GetCommissionableInstanceName(char * instanceName, size_t maxLength) const = 0; 370 : 371 : /** 372 : * Generates an updated commissionable instance name. This happens 373 : * automatically when Init() is called, but may be needed at other times as 374 : * well. 375 : */ 376 : virtual CHIP_ERROR UpdateCommissionableInstanceName() = 0; 377 : 378 : /// Provides the system-wide implementation of the service advertiser 379 : static ServiceAdvertiser & Instance(); 380 : }; 381 : 382 : } // namespace Dnssd 383 : } // namespace chip