3 * Copyright (c) 2020-2021 Project CHIP Authors
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <core/CHIPEncoding.h>
19 #include <core/CHIPSafeCasts.h>
20 #include <platform/internal/DeviceNetworkInfo.h>
21 #include <protocols/Protocols.h>
22 #include <support/CodeUtils.h>
23 #include <support/ErrorStr.h>
24 #include <support/SafeInt.h>
25 #include <transport/NetworkProvisioning.h>
26 #include <transport/SecureSessionMgr.h>
28 #if CONFIG_DEVICE_LAYER
29 #include <platform/CHIPDeviceLayer.h>
30 #if defined(CHIP_DEVICE_LAYER_TARGET)
31 #define DEVICENETWORKPROVISIONING_HEADER <platform/CHIP_DEVICE_LAYER_TARGET/DeviceNetworkProvisioningDelegateImpl.h>
32 #include DEVICENETWORKPROVISIONING_HEADER
38 constexpr char kAPInterfaceNamePrefix[] = "ap";
39 constexpr char kLoobackInterfaceNamePrefix[] = "lo";
41 void NetworkProvisioning::Init(NetworkProvisioningDelegate * delegate)
44 #if CONFIG_DEVICE_LAYER
45 #if defined(CHIP_DEVICE_LAYER_TARGET)
46 DeviceLayer::PlatformMgr().AddEventHandler(ConnectivityHandler, reinterpret_cast<intptr_t>(this));
51 NetworkProvisioning::~NetworkProvisioning()
53 #if CONFIG_DEVICE_LAYER
54 #if defined(CHIP_DEVICE_LAYER_TARGET)
55 DeviceLayer::PlatformMgr().RemoveEventHandler(ConnectivityHandler, reinterpret_cast<intptr_t>(this));
60 CHIP_ERROR NetworkProvisioning::HandleNetworkProvisioningMessage(uint8_t msgType, const System::PacketBufferHandle & msgBuf)
62 CHIP_ERROR err = CHIP_NO_ERROR;
66 case NetworkProvisioning::MsgTypes::kWiFiAssociationRequest: {
67 char SSID[chip::DeviceLayer::Internal::kMaxWiFiSSIDLength];
68 char passwd[chip::DeviceLayer::Internal::kMaxWiFiKeyLength];
69 Encoding::LittleEndian::BufferWriter bbufSSID(Uint8::from_char(SSID), chip::DeviceLayer::Internal::kMaxWiFiSSIDLength);
70 Encoding::LittleEndian::BufferWriter bbufPW(Uint8::from_char(passwd), chip::DeviceLayer::Internal::kMaxWiFiKeyLength);
72 const uint8_t * buffer = msgBuf->Start();
73 size_t len = msgBuf->DataLength();
76 ChipLogProgress(NetworkProvisioning, "Received kWiFiAssociationRequest.\n");
78 err = DecodeString(&buffer[offset], len - offset, bbufSSID, offset);
79 // TODO: Check for the error once network provisioning is moved to delegate calls
81 err = DecodeString(&buffer[offset], len - offset, bbufPW, offset);
82 // TODO: Check for the error once network provisioning is moved to delegate calls
84 #if CONFIG_DEVICE_LAYER
85 #if defined(CHIP_DEVICE_LAYER_TARGET)
86 DeviceLayer::DeviceNetworkProvisioningDelegateImpl deviceDelegate;
87 err = deviceDelegate.ProvisionWiFi(SSID, passwd);
90 if (DeviceLayer::ConnectivityMgr().IsWiFiStationConnected())
92 err = SendCurrentIPv4Address();
99 case NetworkProvisioning::MsgTypes::kThreadAssociationRequest:
100 ChipLogProgress(NetworkProvisioning, "Received kThreadAssociationRequest");
101 err = DecodeThreadAssociationRequest(msgBuf);
104 case NetworkProvisioning::MsgTypes::kIPAddressAssigned: {
105 ChipLogProgress(NetworkProvisioning, "Received kIPAddressAssigned");
106 if (!Inet::IPAddress::FromString(Uint8::to_const_char(msgBuf->Start()), msgBuf->DataLength(), mDeviceAddress))
108 ExitNow(err = CHIP_ERROR_INVALID_ADDRESS);
114 ExitNow(err = CHIP_ERROR_INVALID_MESSAGE_TYPE);
119 if (mDelegate != nullptr)
121 if (err != CHIP_NO_ERROR)
123 ChipLogError(NetworkProvisioning, "Failed in HandleNetworkProvisioningMessage. error %s\n", ErrorStr(err));
124 mDelegate->OnNetworkProvisioningError(err);
128 // Network provisioning handshake requires only one message exchange in either direction.
129 // If the current message handling did not result in an error, network provisioning is
131 mDelegate->OnNetworkProvisioningComplete();
137 size_t NetworkProvisioning::EncodedStringSize(const char * str)
139 return strlen(str) + sizeof(uint16_t);
142 CHIP_ERROR NetworkProvisioning::EncodeString(const char * str, Encoding::LittleEndian::BufferWriter & bbuf)
144 CHIP_ERROR err = CHIP_NO_ERROR;
145 size_t length = strlen(str);
146 uint16_t u16len = static_cast<uint16_t>(length);
147 VerifyOrExit(CanCastTo<uint16_t>(length), err = CHIP_ERROR_INVALID_ARGUMENT);
156 CHIP_ERROR NetworkProvisioning::DecodeString(const uint8_t * input, size_t input_len, Encoding::LittleEndian::BufferWriter & bbuf,
159 CHIP_ERROR err = CHIP_NO_ERROR;
162 VerifyOrExit(input_len >= sizeof(uint16_t), err = CHIP_ERROR_BUFFER_TOO_SMALL);
163 length = chip::Encoding::LittleEndian::Get16(input);
164 consumed = sizeof(uint16_t);
166 VerifyOrExit(input_len - consumed >= length, err = CHIP_ERROR_BUFFER_TOO_SMALL);
167 bbuf.Put(&input[consumed], length);
169 consumed += bbuf.Needed();
170 bbuf.Put(static_cast<uint8_t>('\0'));
172 VerifyOrExit(bbuf.Fit(), err = CHIP_ERROR_BUFFER_TOO_SMALL);
178 CHIP_ERROR NetworkProvisioning::SendIPAddress(const Inet::IPAddress & addr)
181 CHIP_ERROR err = CHIP_NO_ERROR;
182 System::PacketBufferHandle buffer = System::PacketBufferHandle::New(Inet::kMaxIPAddressStringLength);
183 VerifyOrExit(!buffer.IsNull(), err = CHIP_ERROR_NO_MEMORY);
184 addrStr = addr.ToString(Uint8::to_char(buffer->Start()), buffer->AvailableDataLength());
185 buffer->SetDataLength(static_cast<uint16_t>(strlen(addrStr) + 1));
187 ChipLogProgress(NetworkProvisioning, "Sending IP Address. Delegate %p\n", mDelegate);
188 VerifyOrExit(mDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
189 VerifyOrExit(addrStr != nullptr, err = CHIP_ERROR_INVALID_ADDRESS);
191 err = mDelegate->SendSecureMessage(Protocols::NetworkProvisioning::Id, NetworkProvisioning::MsgTypes::kIPAddressAssigned,
196 if (CHIP_NO_ERROR != err)
197 ChipLogError(NetworkProvisioning, "Failed in sending IP address. error %s\n", ErrorStr(err));
201 CHIP_ERROR NetworkProvisioning::SendCurrentIPv4Address()
203 for (chip::Inet::InterfaceAddressIterator it; it.HasCurrent(); it.Next())
205 char ifName[chip::Inet::InterfaceIterator::kMaxIfNameLength];
206 if (it.IsUp() && CHIP_NO_ERROR == it.GetInterfaceName(ifName, sizeof(ifName)) &&
207 memcmp(ifName, kAPInterfaceNamePrefix, sizeof(kAPInterfaceNamePrefix) - 1) &&
208 memcmp(ifName, kLoobackInterfaceNamePrefix, sizeof(kLoobackInterfaceNamePrefix) - 1))
210 chip::Inet::IPAddress addr = it.GetAddress();
213 return SendIPAddress(addr);
218 return CHIP_NO_ERROR;
221 CHIP_ERROR NetworkProvisioning::SendNetworkCredentials(const char * ssid, const char * passwd)
223 CHIP_ERROR err = CHIP_NO_ERROR;
224 const size_t bufferSize = EncodedStringSize(ssid) + EncodedStringSize(passwd);
225 VerifyOrExit(CanCastTo<uint16_t>(bufferSize), err = CHIP_ERROR_INVALID_ARGUMENT);
227 Encoding::LittleEndian::PacketBufferWriter bbuf(MessagePacketBuffer::New(bufferSize), bufferSize);
229 ChipLogProgress(NetworkProvisioning, "Sending Network Creds. Delegate %p\n", mDelegate);
230 VerifyOrExit(mDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
231 VerifyOrExit(!bbuf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
232 SuccessOrExit(EncodeString(ssid, bbuf));
233 SuccessOrExit(EncodeString(passwd, bbuf));
234 VerifyOrExit(bbuf.Fit(), err = CHIP_ERROR_BUFFER_TOO_SMALL);
236 err = mDelegate->SendSecureMessage(Protocols::NetworkProvisioning::Id,
237 NetworkProvisioning::MsgTypes::kWiFiAssociationRequest, bbuf.Finalize());
242 if (CHIP_NO_ERROR != err)
243 ChipLogError(NetworkProvisioning, "Failed in sending Network Creds. error %s\n", ErrorStr(err));
247 CHIP_ERROR NetworkProvisioning::SendThreadCredentials(const DeviceLayer::Internal::DeviceNetworkInfo & threadData)
249 CHIP_ERROR err = CHIP_NO_ERROR;
250 /* clang-format off */
251 constexpr uint16_t credentialSize =
252 sizeof(threadData.ThreadNetworkName) +
253 sizeof(threadData.ThreadExtendedPANId) +
254 sizeof(threadData.ThreadMeshPrefix) +
255 sizeof(threadData.ThreadMasterKey) +
256 sizeof(threadData.ThreadPSKc) +
257 sizeof (uint16_t) + // threadData.ThereadPANId
258 4; // threadData.ThreadChannel, threadData.FieldPresent.ThreadExtendedPANId,
259 // threadData.FieldPresent.ThreadMeshPrefix, threadData.FieldPresent.ThreadPSKc
260 /* clang-format on */
261 Encoding::LittleEndian::PacketBufferWriter bbuf(MessagePacketBuffer::New(credentialSize), credentialSize);
263 ChipLogProgress(NetworkProvisioning, "Sending Thread Credentials");
264 VerifyOrExit(mDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
265 VerifyOrExit(!bbuf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
267 bbuf.Put(threadData.ThreadNetworkName, sizeof(threadData.ThreadNetworkName));
268 bbuf.Put(threadData.ThreadExtendedPANId, sizeof(threadData.ThreadExtendedPANId));
269 bbuf.Put(threadData.ThreadMeshPrefix, sizeof(threadData.ThreadMeshPrefix));
270 bbuf.Put(threadData.ThreadMasterKey, sizeof(threadData.ThreadMasterKey));
271 bbuf.Put(threadData.ThreadPSKc, sizeof(threadData.ThreadPSKc));
272 bbuf.Put16(threadData.ThreadPANId);
273 bbuf.Put(threadData.ThreadChannel);
274 bbuf.Put(static_cast<uint8_t>(threadData.FieldPresent.ThreadExtendedPANId));
275 bbuf.Put(static_cast<uint8_t>(threadData.FieldPresent.ThreadMeshPrefix));
276 bbuf.Put(static_cast<uint8_t>(threadData.FieldPresent.ThreadPSKc));
278 VerifyOrExit(bbuf.Fit(), err = CHIP_ERROR_BUFFER_TOO_SMALL);
279 err = mDelegate->SendSecureMessage(Protocols::NetworkProvisioning::Id, NetworkProvisioning::MsgTypes::kThreadAssociationRequest,
283 if (CHIP_NO_ERROR != err)
284 ChipLogError(NetworkProvisioning, "Failed to send Thread Credentials: %s", ErrorStr(err));
288 #ifdef CHIP_ENABLE_OPENTHREAD
289 CHIP_ERROR NetworkProvisioning::DecodeThreadAssociationRequest(const System::PacketBufferHandle & msgBuf)
291 CHIP_ERROR err = CHIP_NO_ERROR;
292 DeviceLayer::Internal::DeviceNetworkInfo networkInfo = {};
293 uint8_t * data = msgBuf->Start();
294 size_t dataLen = msgBuf->DataLength();
296 VerifyOrExit(dataLen >= sizeof(networkInfo.ThreadNetworkName),
297 ChipLogProgress(NetworkProvisioning, "Invalid network provision message"));
298 memcpy(networkInfo.ThreadNetworkName, data, sizeof(networkInfo.ThreadNetworkName));
299 data += sizeof(networkInfo.ThreadNetworkName);
300 dataLen -= sizeof(networkInfo.ThreadNetworkName);
302 VerifyOrExit(dataLen >= sizeof(networkInfo.ThreadExtendedPANId),
303 ChipLogProgress(NetworkProvisioning, "Invalid network provision message"));
304 memcpy(networkInfo.ThreadExtendedPANId, data, sizeof(networkInfo.ThreadExtendedPANId));
305 data += sizeof(networkInfo.ThreadExtendedPANId);
306 dataLen -= sizeof(networkInfo.ThreadExtendedPANId);
308 VerifyOrExit(dataLen >= sizeof(networkInfo.ThreadMeshPrefix),
309 ChipLogProgress(NetworkProvisioning, "Invalid network provision message"));
310 memcpy(networkInfo.ThreadMeshPrefix, data, sizeof(networkInfo.ThreadMeshPrefix));
311 data += sizeof(networkInfo.ThreadMeshPrefix);
312 dataLen -= sizeof(networkInfo.ThreadMeshPrefix);
314 VerifyOrExit(dataLen >= sizeof(networkInfo.ThreadMasterKey),
315 ChipLogProgress(NetworkProvisioning, "Invalid network provision message"));
316 memcpy(networkInfo.ThreadMasterKey, data, sizeof(networkInfo.ThreadMasterKey));
317 data += sizeof(networkInfo.ThreadMasterKey);
318 dataLen -= sizeof(networkInfo.ThreadMasterKey);
320 VerifyOrExit(dataLen >= sizeof(networkInfo.ThreadPSKc),
321 ChipLogProgress(NetworkProvisioning, "Invalid network provision message"));
322 memcpy(networkInfo.ThreadPSKc, data, sizeof(networkInfo.ThreadPSKc));
323 data += sizeof(networkInfo.ThreadPSKc);
324 dataLen -= sizeof(networkInfo.ThreadPSKc);
326 VerifyOrExit(dataLen >= sizeof(networkInfo.ThreadPANId),
327 ChipLogProgress(NetworkProvisioning, "Invalid network provision message"));
328 networkInfo.ThreadPANId = Encoding::LittleEndian::Get16(data);
329 data += sizeof(networkInfo.ThreadPANId);
330 dataLen -= sizeof(networkInfo.ThreadPANId);
332 VerifyOrExit(dataLen >= sizeof(networkInfo.ThreadChannel),
333 ChipLogProgress(NetworkProvisioning, "Invalid network provision message"));
334 networkInfo.ThreadChannel = data[0];
335 data += sizeof(networkInfo.ThreadChannel);
336 dataLen -= sizeof(networkInfo.ThreadChannel);
338 VerifyOrExit(dataLen >= 3, ChipLogProgress(NetworkProvisioning, "Invalid network provision message"));
339 networkInfo.FieldPresent.ThreadExtendedPANId = *data;
341 networkInfo.FieldPresent.ThreadMeshPrefix = *data;
343 networkInfo.FieldPresent.ThreadPSKc = *data;
345 networkInfo.NetworkId = 0;
346 networkInfo.FieldPresent.NetworkId = true;
348 #if CONFIG_DEVICE_LAYER
349 // Start listening for OpenThread changes to be able to respond with SLAAC/On-Mesh IP Address
350 DeviceLayer::PlatformMgr().AddEventHandler(ConnectivityHandler, reinterpret_cast<intptr_t>(this));
351 #if defined(CHIP_DEVICE_LAYER_TARGET)
353 DeviceLayer::DeviceNetworkProvisioningDelegateImpl deviceDelegate;
354 err = deviceDelegate.ProvisionThread(networkInfo);
362 #else // CHIP_ENABLE_OPENTHREAD
363 CHIP_ERROR NetworkProvisioning::DecodeThreadAssociationRequest(const System::PacketBufferHandle &)
365 return CHIP_ERROR_INVALID_MESSAGE_TYPE;
367 #endif // CHIP_ENABLE_OPENTHREAD
369 #if CONFIG_DEVICE_LAYER
370 void NetworkProvisioning::ConnectivityHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg)
372 NetworkProvisioning * session = reinterpret_cast<NetworkProvisioning *>(arg);
374 VerifyOrExit(session != nullptr, /**/);
376 if (event->Type == DeviceLayer::DeviceEventType::kInternetConnectivityChange &&
377 event->InternetConnectivityChange.IPv4 == DeviceLayer::kConnectivity_Established)
379 Inet::IPAddress addr;
380 Inet::IPAddress::FromString(event->InternetConnectivityChange.address, addr);
381 (void) session->SendIPAddress(addr);
384 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
385 if (event->Type == DeviceLayer::DeviceEventType::kThreadStateChange && event->ThreadStateChange.AddressChanged)
387 Inet::IPAddress addr;
388 SuccessOrExit(DeviceLayer::ThreadStackMgr().GetExternalIPv6Address(addr));
389 (void) session->SendIPAddress(addr);