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