Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2024 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 : #pragma once
19 :
20 : #include <cstdint>
21 : #include <cstring>
22 :
23 : #include <inet/InetInterface.h>
24 : #include <lib/core/CHIPError.h>
25 : #include <lib/core/Optional.h>
26 : #include <lib/core/PeerId.h>
27 : #include <lib/dnssd/Constants.h>
28 : #include <lib/support/BytesToHex.h>
29 : #include <lib/support/logging/CHIPLogging.h>
30 : #include <messaging/ReliableMessageProtocolConfig.h>
31 :
32 : namespace chip {
33 : namespace Dnssd {
34 :
35 : enum class DiscoveryFilterType : uint8_t
36 : {
37 : kNone,
38 : kShortDiscriminator,
39 : kLongDiscriminator,
40 : kVendorId,
41 : kDeviceType,
42 : kCommissioningMode,
43 : kInstanceName,
44 : kCommissioner,
45 : kCompressedFabricId,
46 : };
47 :
48 : struct DiscoveryFilter
49 : {
50 : DiscoveryFilterType type;
51 : uint64_t code = 0;
52 : const char * instanceName = nullptr;
53 0 : DiscoveryFilter() : type(DiscoveryFilterType::kNone), code(0) {}
54 11 : DiscoveryFilter(const DiscoveryFilterType newType) : type(newType) {}
55 46 : DiscoveryFilter(const DiscoveryFilterType newType, uint64_t newCode) : type(newType), code(newCode) {}
56 : DiscoveryFilter(const DiscoveryFilterType newType, const char * newInstanceName) : type(newType), instanceName(newInstanceName)
57 : {}
58 0 : bool operator==(const DiscoveryFilter & other) const
59 : {
60 0 : if (type != other.type)
61 : {
62 0 : return false;
63 : }
64 0 : if (type == DiscoveryFilterType::kInstanceName)
65 : {
66 0 : return (instanceName != nullptr) && (other.instanceName != nullptr) && (strcmp(instanceName, other.instanceName) == 0);
67 : }
68 :
69 0 : return code == other.code;
70 : }
71 : };
72 :
73 : enum class DiscoveryType
74 : {
75 : kUnknown,
76 : kOperational,
77 : kCommissionableNode,
78 : kCommissionerNode
79 : };
80 :
81 : struct CommonResolutionData
82 : {
83 : static constexpr unsigned kMaxIPAddresses = CHIP_DEVICE_CONFIG_MAX_DISCOVERED_IP_ADDRESSES;
84 :
85 : Inet::InterfaceId interfaceId;
86 :
87 : size_t numIPs = 0; // number of valid IP addresses
88 : Inet::IPAddress ipAddress[kMaxIPAddresses];
89 :
90 : uint16_t port = 0;
91 : char hostName[kHostNameMaxLength + 1] = {};
92 : bool supportsTcp = false;
93 : Optional<bool> isICDOperatingAsLIT;
94 : Optional<System::Clock::Milliseconds32> mrpRetryIntervalIdle;
95 : Optional<System::Clock::Milliseconds32> mrpRetryIntervalActive;
96 : Optional<System::Clock::Milliseconds16> mrpRetryActiveThreshold;
97 :
98 528 : CommonResolutionData() { Reset(); }
99 :
100 76 : bool IsValid() const { return !IsHost("") && (numIPs > 0) && (ipAddress[0] != chip::Inet::IPAddress::Any); }
101 :
102 0 : ReliableMessageProtocolConfig GetRemoteMRPConfig() const
103 : {
104 0 : const ReliableMessageProtocolConfig defaultConfig = GetDefaultMRPConfig();
105 0 : return ReliableMessageProtocolConfig(GetMrpRetryIntervalIdle().ValueOr(defaultConfig.mIdleRetransTimeout),
106 0 : GetMrpRetryIntervalActive().ValueOr(defaultConfig.mActiveRetransTimeout),
107 0 : GetMrpRetryActiveThreshold().ValueOr(defaultConfig.mActiveThresholdTime));
108 : }
109 0 : Optional<System::Clock::Milliseconds32> GetMrpRetryIntervalIdle() const { return mrpRetryIntervalIdle; }
110 0 : Optional<System::Clock::Milliseconds32> GetMrpRetryIntervalActive() const { return mrpRetryIntervalActive; }
111 0 : Optional<System::Clock::Milliseconds16> GetMrpRetryActiveThreshold() const { return mrpRetryActiveThreshold; }
112 :
113 : bool IsDeviceTreatedAsSleepy(const ReliableMessageProtocolConfig * defaultMRPConfig) const
114 : {
115 : // If either session interval (Idle - SII, Active - SAI) has a value and that value is greater
116 : // than the value passed to this function, then the peer device will be treated as if it is
117 : // a Sleepy End Device (SED)
118 : return (mrpRetryIntervalIdle.HasValue() && (mrpRetryIntervalIdle.Value() > defaultMRPConfig->mIdleRetransTimeout)) ||
119 : (mrpRetryIntervalActive.HasValue() && (mrpRetryIntervalActive.Value() > defaultMRPConfig->mActiveRetransTimeout));
120 : }
121 :
122 76 : bool IsHost(const char * host) const { return strcmp(host, hostName) == 0; }
123 :
124 152 : void Reset()
125 : {
126 152 : memset(hostName, 0, sizeof(hostName));
127 152 : mrpRetryIntervalIdle = NullOptional;
128 152 : mrpRetryIntervalActive = NullOptional;
129 152 : mrpRetryActiveThreshold = NullOptional;
130 152 : isICDOperatingAsLIT = NullOptional;
131 152 : numIPs = 0;
132 152 : port = 0;
133 152 : supportsTcp = false;
134 152 : interfaceId = Inet::InterfaceId::Null();
135 912 : for (auto & addr : ipAddress)
136 : {
137 760 : addr = chip::Inet::IPAddress::Any;
138 : }
139 152 : }
140 :
141 : void LogDetail() const
142 : {
143 : if (!IsHost(""))
144 : {
145 : ChipLogDetail(Discovery, "\tHostname: %s", hostName);
146 : }
147 : #if CHIP_DETAIL_LOGGING
148 : for (unsigned j = 0; j < numIPs; j++)
149 : {
150 : char buf[Inet::IPAddress::kMaxStringLength];
151 : char * ipAddressOut = ipAddress[j].ToString(buf);
152 : ChipLogDetail(Discovery, "\tIP Address #%d: %s", j + 1, ipAddressOut);
153 : }
154 : #endif // CHIP_DETAIL_LOGGING
155 : if (port > 0)
156 : {
157 : ChipLogDetail(Discovery, "\tPort: %u", port);
158 : }
159 : if (mrpRetryIntervalIdle.HasValue())
160 : {
161 : ChipLogDetail(Discovery, "\tMrp Interval idle: %" PRIu32 " ms", mrpRetryIntervalIdle.Value().count());
162 : }
163 : else
164 : {
165 : ChipLogDetail(Discovery, "\tMrp Interval idle: not present");
166 : }
167 : if (mrpRetryIntervalActive.HasValue())
168 : {
169 : ChipLogDetail(Discovery, "\tMrp Interval active: %" PRIu32 " ms", mrpRetryIntervalActive.Value().count());
170 : }
171 : else
172 : {
173 : ChipLogDetail(Discovery, "\tMrp Interval active: not present");
174 : }
175 : if (mrpRetryActiveThreshold.HasValue())
176 : {
177 : ChipLogDetail(Discovery, "\tMrp Active Threshold: %u ms", mrpRetryActiveThreshold.Value().count());
178 : }
179 : else
180 : {
181 : ChipLogDetail(Discovery, "\tMrp Active Threshold: not present");
182 : }
183 : ChipLogDetail(Discovery, "\tTCP Supported: %d", supportsTcp);
184 : if (isICDOperatingAsLIT.HasValue())
185 : {
186 : ChipLogDetail(Discovery, "\tThe ICD operates in %s", isICDOperatingAsLIT.Value() ? "LIT" : "SIT");
187 : }
188 : else
189 : {
190 : ChipLogDetail(Discovery, "\tICD: not present");
191 : }
192 : }
193 : };
194 :
195 : /// Data that is specific to Operational Discovery of nodes
196 : struct OperationalNodeData
197 : {
198 : PeerId peerId;
199 :
200 : void Reset() { peerId = PeerId(); }
201 : };
202 :
203 : inline constexpr size_t kMaxDeviceNameLen = 32;
204 : inline constexpr size_t kMaxRotatingIdLen = 50;
205 : inline constexpr size_t kMaxPairingInstructionLen = 128;
206 :
207 : /// Data that is specific to commisionable/commissioning node discovery
208 : struct CommissionNodeData
209 : {
210 : size_t rotatingIdLen = 0;
211 : uint32_t deviceType = 0;
212 : uint16_t longDiscriminator = 0;
213 : uint16_t vendorId = 0;
214 : uint16_t productId = 0;
215 : uint16_t pairingHint = 0;
216 : uint8_t commissioningMode = 0;
217 : uint8_t commissionerPasscode = 0;
218 : uint8_t rotatingId[kMaxRotatingIdLen] = {};
219 : char instanceName[Commission::kInstanceNameMaxLength + 1] = {};
220 : char deviceName[kMaxDeviceNameLen + 1] = {};
221 : char pairingInstruction[kMaxPairingInstructionLen + 1] = {};
222 :
223 96 : CommissionNodeData() {}
224 :
225 32 : void Reset()
226 : {
227 : // Let constructor clear things as default
228 32 : this->~CommissionNodeData();
229 32 : new (this) CommissionNodeData();
230 32 : }
231 :
232 : bool IsInstanceName(const char * instance) const { return strcmp(instance, instanceName) == 0; }
233 :
234 : void LogDetail() const
235 : {
236 : if (rotatingIdLen > 0)
237 : {
238 : char rotatingIdString[chip::Dnssd::kMaxRotatingIdLen * 2 + 1] = "";
239 : Encoding::BytesToUppercaseHexString(rotatingId, rotatingIdLen, rotatingIdString, sizeof(rotatingIdString));
240 : ChipLogDetail(Discovery, "\tRotating ID: %s", rotatingIdString);
241 : }
242 : if (strlen(deviceName) != 0)
243 : {
244 : ChipLogDetail(Discovery, "\tDevice Name: %s", deviceName);
245 : }
246 : if (vendorId > 0)
247 : {
248 : ChipLogDetail(Discovery, "\tVendor ID: %u", vendorId);
249 : }
250 : if (productId > 0)
251 : {
252 : ChipLogDetail(Discovery, "\tProduct ID: %u", productId);
253 : }
254 : if (deviceType > 0)
255 : {
256 : ChipLogDetail(Discovery, "\tDevice Type: %" PRIu32, deviceType);
257 : }
258 : if (longDiscriminator > 0)
259 : {
260 : ChipLogDetail(Discovery, "\tLong Discriminator: %u", longDiscriminator);
261 : }
262 : if (strlen(pairingInstruction) != 0)
263 : {
264 : ChipLogDetail(Discovery, "\tPairing Instruction: %s", pairingInstruction);
265 : }
266 : if (pairingHint > 0)
267 : {
268 : ChipLogDetail(Discovery, "\tPairing Hint: %u", pairingHint);
269 : }
270 : if (!IsInstanceName(""))
271 : {
272 : ChipLogDetail(Discovery, "\tInstance Name: %s", instanceName);
273 : }
274 : ChipLogDetail(Discovery, "\tCommissioning Mode: %u", commissioningMode);
275 : if (commissionerPasscode > 0)
276 : {
277 : ChipLogDetail(Discovery, "\tCommissioner Passcode: %u", commissionerPasscode);
278 : }
279 : }
280 : };
281 :
282 : struct ResolvedNodeData
283 : {
284 : CommonResolutionData resolutionData;
285 : OperationalNodeData operationalData;
286 :
287 : void LogNodeIdResolved() const
288 : {
289 : #if CHIP_PROGRESS_LOGGING
290 : // Would be nice to log the interface id, but sorting out how to do so
291 : // across our different InterfaceId implementations is a pain.
292 : ChipLogProgress(Discovery, "Node ID resolved for " ChipLogFormatX64 ":" ChipLogFormatX64,
293 : ChipLogValueX64(operationalData.peerId.GetCompressedFabricId()),
294 : ChipLogValueX64(operationalData.peerId.GetNodeId()));
295 : resolutionData.LogDetail();
296 : #endif // CHIP_PROGRESS_LOGGING
297 : }
298 : };
299 :
300 : struct DiscoveredNodeData
301 : {
302 : CommonResolutionData resolutionData;
303 : CommissionNodeData commissionData;
304 :
305 32 : void Reset()
306 : {
307 32 : resolutionData.Reset();
308 32 : commissionData.Reset();
309 32 : }
310 32 : DiscoveredNodeData() { Reset(); }
311 :
312 : void LogDetail() const
313 : {
314 : ChipLogDetail(Discovery, "Discovered node:");
315 : resolutionData.LogDetail();
316 : commissionData.LogDetail();
317 : }
318 : };
319 :
320 : /// Callbacks for discovering nodes advertising non-operational status:
321 : /// - Commissioners
322 : /// - Nodes in commissioning modes over IP (e.g. ethernet devices, devices already
323 : /// connected to thread/wifi or devices with a commissioning window open)
324 : class CommissioningResolveDelegate
325 : {
326 : public:
327 8 : virtual ~CommissioningResolveDelegate() = default;
328 :
329 : /// Called within the CHIP event loop once a node is discovered.
330 : ///
331 : /// May be called multiple times as more nodes send their answer to a
332 : /// multicast discovery query
333 : virtual void OnNodeDiscovered(const DiscoveredNodeData & nodeData) = 0;
334 : };
335 :
336 : } // namespace Dnssd
337 : } // namespace chip
|