-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
Copy pathNetworkCommissioning.h
450 lines (396 loc) · 19.3 KB
/
NetworkCommissioning.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
/*
*
* Copyright (c) 2021 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* This file defines the CHIP Device Network Provisioning object.
*
*/
#pragma once
#include <credentials/CHIPCert.h>
#include <crypto/CHIPCryptoPAL.h>
#include <lib/core/CHIPCore.h>
#include <lib/core/CHIPSafeCasts.h>
#include <lib/core/Optional.h>
#include <lib/support/ThreadOperationalDataset.h>
#include <lib/support/TypeTraits.h>
#include <lib/support/Variant.h>
#include <platform/CHIPDeviceConfig.h>
#include <platform/internal/DeviceNetworkInfo.h>
#include <app-common/zap-generated/cluster-enums.h>
#include <limits>
#include <utility>
namespace chip {
namespace DeviceLayer {
/**
* We are using a namespace here, for most use cases, this namespace will be used by `using DeviceLayer::NetworkCommissioning`, but
* this still worth a dedicated namespace since:
*
* - The BaseDriver / WirelessDriver is not expected to be implemented directly by users, the only occurrence is in the network
* commissioning cluster.
* - We can safely name the drivers as WiFiDriver / ThreadDriver, it should not be ambiguous for most cases
* - We can safely name the Status enum to Status, and some other structs -- if we are using using, then we should in the context of
* writing something dedicated to network commissioning, then a single word Status should be clear enough.
*/
namespace NetworkCommissioning {
inline constexpr size_t kMaxNetworkIDLen = 32;
// TODO: This is exactly the same as the one in GroupDataProvider, this could be moved to src/lib/support
template <typename T>
class Iterator
{
public:
virtual ~Iterator() = default;
/**
* @retval The number of entries in total that will be iterated.
*/
virtual size_t Count() = 0;
/**
* @param[out] item Value associated with the next element in the iteration.
* @retval true if the next entry is successfully retrieved.
* @retval false if no more entries can be found.
*/
virtual bool Next(T & item) = 0;
/**
* Release the memory allocated by this iterator.
* Must be called before the pointer goes out of scope.
*/
virtual void Release() = 0;
protected:
Iterator() = default;
};
// The following structs follows the generated cluster object structs.
struct Network
{
uint8_t networkID[kMaxNetworkIDLen];
uint8_t networkIDLen = 0;
#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_PDC
Optional<Credentials::CertificateKeyIdStorage> networkIdentifier;
Optional<Credentials::CertificateKeyIdStorage> clientIdentifier;
#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI_PDC
bool connected = false;
};
static_assert(sizeof(Network::networkID) <= std::numeric_limits<decltype(Network::networkIDLen)>::max(),
"Max length of networkID ssid exceeds the limit of networkIDLen field");
struct WiFiScanResponse
{
public:
chip::BitFlags<app::Clusters::NetworkCommissioning::WiFiSecurityBitmap> security;
uint8_t ssid[DeviceLayer::Internal::kMaxWiFiSSIDLength];
uint8_t ssidLen;
uint8_t bssid[6];
uint16_t channel;
app::Clusters::NetworkCommissioning::WiFiBandEnum wiFiBand;
int8_t rssi;
};
static_assert(sizeof(WiFiScanResponse::ssid) <= std::numeric_limits<decltype(WiFiScanResponse::ssidLen)>::max(),
"Max length of WiFi ssid exceeds the limit of ssidLen field");
struct ThreadScanResponse
{
uint16_t panId;
uint64_t extendedPanId;
char networkName[16];
uint8_t networkNameLen;
uint16_t channel;
uint8_t version;
uint64_t extendedAddress;
int8_t rssi;
uint8_t lqi;
};
static_assert(sizeof(ThreadScanResponse::networkName) <= std::numeric_limits<decltype(ThreadScanResponse::networkNameLen)>::max(),
"Max length of WiFi credentials exceeds the limit of credentialsLen field");
using NetworkIterator = Iterator<Network>;
using WiFiScanResponseIterator = Iterator<WiFiScanResponse>;
using ThreadScanResponseIterator = Iterator<ThreadScanResponse>;
using Status = app::Clusters::NetworkCommissioning::NetworkCommissioningStatusEnum;
using WiFiBandEnum = app::Clusters::NetworkCommissioning::WiFiBandEnum;
// For backwards compatibility with pre-rename enum values.
using WiFiBand = WiFiBandEnum;
using WiFiSecurityBitmap = app::Clusters::NetworkCommissioning::WiFiSecurityBitmap;
// For backwards compatibility with pre-rename bitmap values.
using WiFiSecurity = WiFiSecurityBitmap;
using ThreadCapabilities = app::Clusters::NetworkCommissioning::ThreadCapabilitiesBitmap;
// BaseDriver and WirelessDriver are the common interfaces for a network driver, platform drivers should not implement this
// directly, instead, users are expected to implement WiFiDriver, ThreadDriver and EthernetDriver.
namespace Internal {
class BaseDriver
{
public:
class NetworkStatusChangeCallback
{
public:
/**
* @brief Callback for the network driver pushing the event of network status change to the network commissioning cluster.
* The platforms is expected to push the status from operations such as autonomous connection after loss of connectivity or
* during initial establishment.
*
* This function must be called in a thread-safe manner with CHIP stack.
*/
virtual void OnNetworkingStatusChange(Status commissioningError, Optional<ByteSpan> networkId,
Optional<int32_t> connectStatus) = 0;
virtual ~NetworkStatusChangeCallback() = default;
};
/**
* @brief Initializes the driver, this function will be called when initializing the network commissioning cluster.
*/
virtual CHIP_ERROR Init(NetworkStatusChangeCallback * networkStatusChangeCallback) { return CHIP_NO_ERROR; }
/**
* @brief Shuts down the driver, this function will be called when shutting down the network commissioning cluster.
*/
virtual void Shutdown() {}
/**
* @brief Returns maximum number of network configs can be added to the driver.
*/
virtual uint8_t GetMaxNetworks() = 0;
/**
* @brief Returns an iterator for reading the networks, the user will always call NetworkIterator::Release. The iterator should
* be consumed in the same context as calling GetNetworks(). Users must call Release() when the iterator goes out of scope.
*/
virtual NetworkIterator * GetNetworks() = 0;
/**
* @brief Sets the status of the interface, this is an optional feature of a network driver.
*/
virtual CHIP_ERROR SetEnabled(bool enabled) { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; }
/**
* @brief Returns the status of the interface, this is an optional feature of a network driver the driver will be enabled by
* default.
*/
virtual bool GetEnabled() { return true; };
virtual ~BaseDriver() = default;
};
class WirelessDriver : public Internal::BaseDriver
{
public:
class ConnectCallback
{
public:
virtual void OnResult(Status commissioningError, CharSpan debugText, int32_t connectStatus) = 0;
virtual ~ConnectCallback() = default;
};
/**
* @brief Persists the network configurations. This function is expected to be called when CommissioningComplete event is fired.
*/
virtual CHIP_ERROR CommitConfiguration() = 0;
/**
* @brief Reverts the network configurations to the last committed one. This function is expected to be called when failsafe
* timeout reached.
*/
virtual CHIP_ERROR RevertConfiguration() = 0;
virtual uint8_t GetScanNetworkTimeoutSeconds() = 0;
virtual uint8_t GetConnectNetworkTimeoutSeconds() = 0;
/**
* @brief Remove a network from the device. The driver should fill the outDebugText field to pass any human-readable messages to
* the client. The driver should reduce the size of outDebugText to 0 to omit it from the response when no debug text needs to
* be delivered. On success, the driver should set outNetworkIndex to the index of the network just removed. The value of
* network index is discarded on failure.
*
* Note: The capacity of outDebugText passed by network commissioning cluster can be configured via
* CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE.
*/
virtual Status RemoveNetwork(ByteSpan networkId, MutableCharSpan & outDebugText, uint8_t & outNetworkIndex) = 0;
/**
* @brief Reorder the networks on the device. The driver should fill the outDebugText field to pass any human-readable messages
* to the client. The driver should reduce the size of outDebugText to 0 to omit it from the response when no debug text needs
* to be delivered.
*
* Note: The capacity of outDebugText passed by network commissioning cluster can be configured via
* CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE.
*/
virtual Status ReorderNetwork(ByteSpan networkId, uint8_t index, MutableCharSpan & outDebugText) = 0;
/**
* @brief Initializes a network join. callback->OnResult must be called, on both success and error. Callback can be
* called inside ConnectNetwork.
*/
virtual void ConnectNetwork(ByteSpan networkId, ConnectCallback * callback) = 0;
#if CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION
/**
* @brief Disconnect from network, if currently connected.
*/
virtual CHIP_ERROR DisconnectFromNetwork() { return CHIP_ERROR_NOT_IMPLEMENTED; }
#endif
};
} // namespace Internal
class WiFiDriver : public Internal::WirelessDriver
{
public:
class ScanCallback
{
public:
/**
* Indicates the scan is finished, and accepts a iterator of networks discovered.
* - networks can be nullptr when no networks discovered, or error occurred during scanning the networks.
* OnFinished() must be called in a thread-safe manner with CHIP stack. (e.g. using ScheduleWork or ScheduleLambda)
* - Users can assume the networks will always be used (and Release will be called) inside this function call. However, the
* iterator might be not fully consumed (i.e. There are too many networks scanned to fit in the buffer for scan response
* message.)
*/
virtual void OnFinished(Status status, CharSpan debugText, WiFiScanResponseIterator * networks) = 0;
virtual ~ScanCallback() = default;
};
/**
* @brief Adds or updates a WiFi network on the device. The driver should fill the outDebugText field to pass any human-readable
* messages to the client. The driver should reduce the size of outDebugText to 0 to omit it from the response when no debug
* text needs to be delivered. On success, the driver should set outNetworkIndex to the index of the network just added or
* updated. The value of network index is discarded on failure.
*
* Note: The capacity of outDebugText passed by network commissioning cluster can be configured via
* CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE.
*/
virtual Status AddOrUpdateNetwork(ByteSpan ssid, ByteSpan credentials, MutableCharSpan & outDebugText,
uint8_t & outNetworkIndex) = 0;
/**
* @brief Initializes a WiFi network scan. callback->OnFinished must be called, on both success and error. Callback can
* be called inside ScanNetworks.
*
* @param ssid The interested SSID, the scanning SHALL be restricted to the given SSID if the ssid is not empty (i.e.
* ssid.empty() is false).
* @param callback Callback that will be invoked upon finishing the scan
*/
virtual void ScanNetworks(ByteSpan ssid, ScanCallback * callback) = 0;
#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_PDC
virtual bool SupportsPerDeviceCredentials() { return false; };
/**
* @brief Adds or updates a WiFi network with Per-Device Credentials on the device.
*
* @param ssid The SSID of the network to be added / updated.
* @param networkIdentity The Network Identity of the network, in compact-pdc-identity format.
* @param clientIdentityNetworkIndex If present, the index of the existing network configuration of which the Client
* Identity is to be re-used. Otherwise a new Client Identity shall be generated.
* @param outStatus The application-level status code (Status::kSuccess on success).
* @param outDebugText A debug text buffer that may be populated by the driver. The size of the span
* must be reduced to the length of text emitted (or 0, if none).
* @param outClientIdentity On success, the Client Identity that was generated or copied, depending on the
* presence of `clientIdentityNetworkIndex`.
* @param outNextworkIndex On success, the index of the network entry that was added or updated.
*
* @retval CHIP_NO_ERROR and outStatus == kSuccess on success.
* @retval CHIP_NO_ERROR and outStatus != kSuccess for application-level errors. outDebugText should be populated.
* @retval CHIP_ERROR_* on internal errors. None of the output parameters will be examined in this case.
*/
virtual CHIP_ERROR AddOrUpdateNetworkWithPDC(ByteSpan ssid, ByteSpan networkIdentity,
Optional<uint8_t> clientIdentityNetworkIndex, Status & outStatus,
MutableCharSpan & outDebugText, MutableByteSpan & outClientIdentity,
uint8_t & outNetworkIndex)
{
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}
/**
* @brief Retrieves the Network Identity associated with a network.
*
* @param networkIndex The 0-based index of the network.
* @param outNetworkIdentity The output buffer to be populated with the Network
* Identity in compact-pdc-identity TLV format.
*
* @return CHIP_NO_ERROR on success or a CHIP_ERROR on failure.
*/
virtual CHIP_ERROR GetNetworkIdentity(uint8_t networkIndex, MutableByteSpan & outNetworkIdentity)
{
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}
/**
* @brief Retrieves the Network Client Identity associated with a network.
*
* @param networkIndex The 0-based index of the network.
* @param outNetworkIdentity The output buffer to be populated with the Network
* Client Identity in compact-pdc-identity TLV format.
*
* @return CHIP_NO_ERROR on success or a CHIP_ERROR on failure.
*/
virtual CHIP_ERROR GetClientIdentity(uint8_t networkIndex, MutableByteSpan & outClientIdentity)
{
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}
/**
* @brief Signs the specified message with the private key of a Network Client Identity.
*/
virtual CHIP_ERROR SignWithClientIdentity(uint8_t networkIndex, const ByteSpan & message,
Crypto::P256ECDSASignature & outSignature)
{
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI_PDC
/**
* @brief Provide all the frequency bands supported by the Wi-Fi interface.
*
* The default implementation returns the 2.4 GHz band support.
* Note: WiFi platforms should implement this function in their WiFiDriver to provide their complete device capabilities.
*
* The returned bit mask has values of WiFiBandEnum packed into the bits. For example:
*
* - Bit 0 = (WiFiBandEnum::k2g4 == 0) --> (1 << 0) == (1 << WiFiBandEnum::k2g4)
* - Bit 2 = (WiFiBandEnum::k5g == 2) --> (1 << 2) == (1 << WiFiBandEnum::k5g)
* - If both 2.4G and 5G are supported --> ((1 << k2g4) || (1 << k5g)) == (1 || 4) == 5
*
* On error, return 0 (no bands supported). This should never happen... Note that
* certification tests will REQUIRE at least one bit set in the set.
*
* @return a bitmask of supported Wi-Fi bands where each bit is associated with a WiFiBandEnum value.
*/
virtual uint32_t GetSupportedWiFiBandsMask() const
{
// Default to 2.4G support (100% example platform coverage as of Matter 1.3) listed.
return static_cast<uint32_t>(1UL << chip::to_underlying(WiFiBandEnum::k2g4));
}
~WiFiDriver() override = default;
};
class ThreadDriver : public Internal::WirelessDriver
{
public:
class ScanCallback
{
public:
/**
* Indicates the scan is finished, and accepts a iterator of networks discovered.
* - networks can be nullptr when no networks discovered, or error occurred during scanning the networks.
* OnFinished() must be called in a thread-safe manner with CHIP stack. (e.g. using ScheduleWork or ScheduleLambda)
* - Users can assume the networks will always be used (and Release will be called) inside this function call. However, the
* iterator might be not fully consumed (i.e. There are too many networks scanned to fit in the buffer for scan response
* message.)
*/
virtual void OnFinished(Status err, CharSpan debugText, ThreadScanResponseIterator * networks) = 0;
virtual ~ScanCallback() = default;
};
/**
* @brief Adds or updates a Thread network on the device. The driver should fill the outDebugText field to pass any
* human-readable messages to the client. The driver should reduce the size of outDebugText to 0 to omit it from the response
* when no debug text needs to be delivered. On success, the driver should set outNetworkIndex to the index of the network just
* added or updated. The value of the network index is discarded on failure.
*
* Note: The capacity of outDebugText passed by network commissioning cluster can be configured via
* CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE.
*/
virtual Status AddOrUpdateNetwork(ByteSpan operationalDataset, MutableCharSpan & outDebugText, uint8_t & outNetworkIndex) = 0;
/**
* @brief Initializes a Thread network scan. callback->OnFinished must be called, on both success and error. Callback can
* be called inside ScanNetworks.
*/
virtual void ScanNetworks(ScanCallback * callback) = 0;
/**
* @brief Provide all of the Thread features supported by the Thread interface
*/
virtual ThreadCapabilities GetSupportedThreadFeatures() = 0;
/**
* @brief Return the Thread version supported by the Thread interface
*/
virtual uint16_t GetThreadVersion() = 0;
~ThreadDriver() override = default;
};
class EthernetDriver : public Internal::BaseDriver
{
// Ethernet driver does not have any special operations.
};
} // namespace NetworkCommissioning
} // namespace DeviceLayer
} // namespace chip