Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / app / clusters / network-commissioning / network-commissioning.cpp
1 /*
2  *
3  *    Copyright (c) 2021 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
19 #include "network-commissioning.h"
20
21 #include <cstring>
22 #include <type_traits>
23
24 #include <gen/att-storage.h>
25 #include <gen/attribute-id.h>
26 #include <gen/attribute-type.h>
27 #include <gen/callback.h>
28 #include <gen/cluster-id.h>
29 #include <gen/command-id.h>
30 #include <gen/enums.h>
31 #include <util/af.h>
32
33 #include <lib/support/CodeUtils.h>
34 #include <lib/support/SafeInt.h>
35 #include <lib/support/Span.h>
36 #include <lib/support/logging/CHIPLogging.h>
37 #include <platform/CHIPDeviceLayer.h>
38 #include <platform/ConnectivityManager.h>
39
40 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
41 #include <platform/ThreadStackManager.h>
42 #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD
43
44 #include <transport/NetworkProvisioning.h>
45
46 // Include DeviceNetworkProvisioningDelegateImpl for WiFi provisioning.
47 // TODO: Enable wifi network should be done by ConnectivityManager. (Or other platform neutral interfaces)
48 #if defined(CHIP_DEVICE_LAYER_TARGET)
49 #define DEVICENETWORKPROVISIONING_HEADER <platform/CHIP_DEVICE_LAYER_TARGET/DeviceNetworkProvisioningDelegateImpl.h>
50 #include DEVICENETWORKPROVISIONING_HEADER
51 #endif
52
53 using namespace chip;
54 using namespace chip::app;
55 using namespace chip::app::clusters;
56 using namespace chip::app::clusters::NetworkCommissioning;
57
58 namespace chip {
59 namespace app {
60 namespace clusters {
61 namespace NetworkCommissioning {
62
63 constexpr uint8_t kMaxNetworkIDLen       = 32;
64 constexpr uint8_t kMaxThreadDatasetLen   = 254; // As defined in Thread spec.
65 constexpr uint8_t kMaxWiFiSSIDLen        = 32;
66 constexpr uint8_t kMaxWiFiCredentialsLen = 64;
67 constexpr uint8_t kMaxNetworks           = 4;
68
69 // The temporary network id which will be used by thread networks in CHIP before we have the API for getting extpanid from dataset
70 // tlv.
71 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
72 constexpr uint8_t kTemporaryThreadNetworkId[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
73 #endif
74
75 enum class NetworkType : uint8_t
76 {
77     kUndefined = 0,
78     kWiFi      = 1,
79     kThread    = 2,
80     kEthernet  = 3,
81 };
82
83 struct ThreadNetworkInfo
84 {
85     uint8_t mDataset[kMaxThreadDatasetLen];
86     uint8_t mDatasetLen;
87 };
88
89 struct WiFiNetworkInfo
90 {
91     uint8_t mSSID[kMaxWiFiSSIDLen + 1];
92     uint8_t mSSIDLen;
93     uint8_t mCredentials[kMaxWiFiCredentialsLen];
94     uint8_t mCredentialsLen;
95 };
96
97 struct NetworkInfo
98 {
99     uint8_t mNetworkID[kMaxNetworkIDLen];
100     uint8_t mNetworkIDLen;
101     uint8_t mEnabled;
102     NetworkType mNetworkType;
103     union NetworkData
104     {
105         ThreadNetworkInfo mThread;
106         WiFiNetworkInfo mWiFi;
107     } mData;
108 };
109
110 namespace {
111 // The internal network info containing credentials. Need to find some better place to save these info.
112 NetworkInfo sNetworks[kMaxNetworks];
113 } // namespace
114
115 EmberAfNetworkCommissioningError OnAddThreadNetworkCommandCallbackInternal(app::Command *, EndpointId, ByteSpan operationalDataset,
116                                                                            uint64_t breadcrumb, uint32_t timeoutMs)
117 {
118 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
119     EmberAfNetworkCommissioningError err = EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_BOUNDS_EXCEEDED;
120
121     for (size_t i = 0; i < kMaxNetworks; i++)
122     {
123         if (sNetworks[i].mNetworkType == NetworkType::kUndefined)
124         {
125             VerifyOrExit(operationalDataset.size() <= sizeof(ThreadNetworkInfo::mDataset),
126                          err = EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_OUT_OF_RANGE);
127             memcpy(sNetworks[i].mData.mThread.mDataset, operationalDataset.data(), operationalDataset.size());
128
129             using ThreadDatasetLenType = decltype(sNetworks[i].mData.mThread.mDatasetLen);
130             VerifyOrExit(chip::CanCastTo<ThreadDatasetLenType>(operationalDataset.size()),
131                          err = EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_OUT_OF_RANGE);
132             sNetworks[i].mData.mThread.mDatasetLen = static_cast<ThreadDatasetLenType>(operationalDataset.size());
133
134             // A 64bit id for thread networks, currently, we are missing some API for getting the thread network extpanid from the
135             // dataset tlv.
136             static_assert(sizeof(kTemporaryThreadNetworkId) <= sizeof(sNetworks[i].mNetworkID),
137                           "TemporaryThreadNetworkId too long");
138             memcpy(sNetworks[i].mNetworkID, kTemporaryThreadNetworkId, sizeof(kTemporaryThreadNetworkId));
139             sNetworks[i].mNetworkIDLen = sizeof(kTemporaryThreadNetworkId);
140
141             sNetworks[i].mNetworkType = NetworkType::kThread;
142             sNetworks[i].mEnabled     = false;
143
144             err = EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_SUCCESS;
145             break;
146         }
147     }
148
149 exit:
150     // TODO: We should encode response command here.
151
152     ChipLogDetail(Zcl, "AddThreadNetwork: %d", err);
153     return err;
154 #else
155     // The target does not supports ThreadNetwork. We should not add AddThreadNetwork command in that case then the upper layer will
156     // return "Command not found" error.
157     return EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_UNKNOWN_ERROR;
158 #endif
159 }
160
161 EmberAfNetworkCommissioningError OnAddWiFiNetworkCommandCallbackInternal(app::Command *, EndpointId, ByteSpan ssid,
162                                                                          ByteSpan credentials, uint64_t breadcrumb,
163                                                                          uint32_t timeoutMs)
164 {
165     EmberAfNetworkCommissioningError err = EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_BOUNDS_EXCEEDED;
166
167     for (size_t i = 0; i < kMaxNetworks; i++)
168     {
169         if (sNetworks[i].mNetworkType == NetworkType::kUndefined)
170         {
171             VerifyOrExit(ssid.size() <= sizeof(sNetworks[i].mData.mWiFi.mSSID),
172                          err = EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_OUT_OF_RANGE);
173             memcpy(sNetworks[i].mData.mWiFi.mSSID, ssid.data(), ssid.size());
174
175             using WiFiSSIDLenType = decltype(sNetworks[i].mData.mWiFi.mSSIDLen);
176             VerifyOrExit(chip::CanCastTo<WiFiSSIDLenType>(ssid.size()), err = EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_OUT_OF_RANGE);
177             sNetworks[i].mData.mWiFi.mSSIDLen = static_cast<WiFiSSIDLenType>(ssid.size());
178
179             VerifyOrExit(credentials.size() <= sizeof(sNetworks[i].mData.mWiFi.mCredentials),
180                          err = EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_OUT_OF_RANGE);
181             memcpy(sNetworks[i].mData.mWiFi.mCredentials, credentials.data(), credentials.size());
182
183             using WiFiCredentialsLenType = decltype(sNetworks[i].mData.mWiFi.mCredentialsLen);
184             VerifyOrExit(chip::CanCastTo<WiFiCredentialsLenType>(ssid.size()),
185                          err = EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_OUT_OF_RANGE);
186             sNetworks[i].mData.mWiFi.mCredentialsLen = static_cast<WiFiCredentialsLenType>(credentials.size());
187
188             VerifyOrExit(ssid.size() <= sizeof(sNetworks[i].mNetworkID), err = EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_OUT_OF_RANGE);
189             memcpy(sNetworks[i].mNetworkID, sNetworks[i].mData.mWiFi.mSSID, ssid.size());
190
191             using NetworkIDLenType = decltype(sNetworks[i].mNetworkIDLen);
192             VerifyOrExit(chip::CanCastTo<NetworkIDLenType>(ssid.size()), err = EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_OUT_OF_RANGE);
193             sNetworks[i].mNetworkIDLen = static_cast<NetworkIDLenType>(ssid.size());
194
195             sNetworks[i].mNetworkType = NetworkType::kWiFi;
196             sNetworks[i].mEnabled     = false;
197
198             err = EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_SUCCESS;
199             break;
200         }
201     }
202
203     VerifyOrExit(err == EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_SUCCESS, );
204
205     ChipLogDetail(Zcl, "WiFi provisioning data: SSID: %s", ssid);
206 exit:
207     // TODO: We should encode response command here.
208
209     ChipLogDetail(Zcl, "AddWiFiNetwork: %d", err);
210     return err;
211 }
212
213 namespace {
214 CHIP_ERROR DoEnableNetwork(NetworkInfo * network)
215 {
216     switch (network->mNetworkType)
217     {
218     case NetworkType::kThread:
219 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
220         ReturnErrorOnFailure(DeviceLayer::ThreadStackMgr().SetThreadEnabled(false));
221         ReturnErrorOnFailure(
222             DeviceLayer::ThreadStackMgr().SetThreadProvision(network->mData.mThread.mDataset, network->mData.mThread.mDatasetLen));
223         ReturnErrorOnFailure(DeviceLayer::ThreadStackMgr().SetThreadEnabled(true));
224 #else
225         return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
226 #endif
227         break;
228     case NetworkType::kWiFi:
229 #if defined(CHIP_DEVICE_LAYER_TARGET)
230     {
231         // TODO: Currently, DeviceNetworkProvisioningDelegateImpl assumes that ssid and credentials are null terminated strings,
232         // which is not correct, this should be changed once we have better method for commissioning wifi networks.
233         DeviceLayer::DeviceNetworkProvisioningDelegateImpl deviceDelegate;
234         ReturnErrorOnFailure(deviceDelegate.ProvisionWiFi(reinterpret_cast<const char *>(network->mData.mWiFi.mSSID),
235                                                           reinterpret_cast<const char *>(network->mData.mWiFi.mCredentials)));
236         break;
237     }
238 #else
239         return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
240 #endif
241     break;
242     case NetworkType::kEthernet:
243     case NetworkType::kUndefined:
244     default:
245         return CHIP_ERROR_NOT_IMPLEMENTED;
246     }
247     network->mEnabled = true;
248     return CHIP_NO_ERROR;
249 }
250 } // namespace
251
252 EmberAfNetworkCommissioningError OnEnableNetworkCommandCallbackInternal(app::Command *, EndpointId, ByteSpan networkID,
253                                                                         uint64_t breadcrumb, uint32_t timeoutMs)
254 {
255     size_t networkSeq;
256     EmberAfNetworkCommissioningError err = EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_NETWORK_ID_NOT_FOUND;
257
258     for (networkSeq = 0; networkSeq < kMaxNetworks; networkSeq++)
259     {
260         if (sNetworks[networkSeq].mNetworkIDLen == networkID.size() &&
261             sNetworks[networkSeq].mNetworkType != NetworkType::kUndefined &&
262             memcmp(sNetworks[networkSeq].mNetworkID, networkID.data(), networkID.size()) == 0)
263         {
264             // TODO: Currently, we cannot figure out the detailed error from network provisioning on DeviceLayer, we should
265             // implement this in device layer.
266             VerifyOrExit(DoEnableNetwork(&sNetworks[networkSeq]) == CHIP_NO_ERROR,
267                          err = EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_UNKNOWN_ERROR);
268             ExitNow(err = EMBER_ZCL_NETWORK_COMMISSIONING_ERROR_SUCCESS);
269         }
270     }
271     // TODO: We should encode response command here.
272 exit:
273     return err;
274 }
275
276 } // namespace NetworkCommissioning
277 } // namespace clusters
278 } // namespace app
279 } // namespace chip