Apply Upstream code (2021-03-15)
[platform/upstream/connectedhomeip.git] / src / platform / Linux / ThreadStackManagerImpl.cpp
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 #include <array>
19 #include <limits.h>
20 #include <string.h>
21
22 #include "platform/internal/CHIPDeviceLayerInternal.h"
23 #include "platform/internal/DeviceNetworkInfo.h"
24
25 #include "platform/PlatformManager.h"
26 #include "platform/ThreadStackManager.h"
27 #include "support/CodeUtils.h"
28 #include "support/logging/CHIPLogging.h"
29
30 #include "dbus/client/thread_api_dbus.hpp"
31
32 using chip::DeviceLayer::Internal::DeviceNetworkInfo;
33 using otbr::DBus::ClientError;
34 using otbr::DBus::DeviceRole;
35 using otbr::DBus::LinkModeConfig;
36 using otbr::DBus::NeighborInfo;
37
38 #ifndef CHIP_CONFIG_OTBR_CLIENT_ERROR_MIN
39 #define CHIP_CONFIG_OTBR_CLIENT_ERROR_MIN 8000000
40 #endif
41
42 #define OTBR_TO_CHIP_ERROR(x)                                                                                                      \
43     (x == ClientError::ERROR_NONE ? CHIP_NO_ERROR : _CHIP_ERROR(CHIP_CONFIG_OTBR_CLIENT_ERROR_MIN + static_cast<int>(x)))
44
45 #define LogClientError(error)                                                                                                      \
46     do                                                                                                                             \
47     {                                                                                                                              \
48         if (error != ClientError::ERROR_NONE)                                                                                      \
49         {                                                                                                                          \
50             ChipLogError(DeviceLayer, __FILE__ " %d: Otbr ClientError %d", __LINE__, static_cast<int>(error));                     \
51         }                                                                                                                          \
52     } while (0)
53
54 namespace chip {
55 namespace DeviceLayer {
56
57 ThreadStackManagerImpl ThreadStackManagerImpl::sInstance;
58
59 ThreadStackManagerImpl::ThreadStackManagerImpl() : mThreadApi(nullptr), mConnection(nullptr), mNetworkInfo(), mAttached(false) {}
60
61 CHIP_ERROR ThreadStackManagerImpl::_InitThreadStack()
62 {
63     ClientError error;
64     DeviceRole role;
65     DBusError dbusError;
66     DBusConnection * dispatchConnection;
67
68     dbus_error_init(&dbusError);
69     mConnection = UniqueDBusConnection(dbus_bus_get(DBUS_BUS_SYSTEM, &dbusError));
70     VerifyOrExit(dbus_bus_register(mConnection.get(), &dbusError), error = ClientError::ERROR_DBUS);
71
72     VerifyOrExit(mConnection != nullptr, error = ClientError::ERROR_DBUS);
73     mThreadApi = std::unique_ptr<otbr::DBus::ThreadApiDBus>(new otbr::DBus::ThreadApiDBus(mConnection.get()));
74     mThreadApi->AddDeviceRoleHandler([this](DeviceRole newRole) { this->_ThreadDevcieRoleChangedHandler(newRole); });
75
76     SuccessOrExit(error = mThreadApi->GetDeviceRole(role));
77     _ThreadDevcieRoleChangedHandler(role);
78     mAttached = (role != DeviceRole::OTBR_DEVICE_ROLE_DETACHED && role != DeviceRole::OTBR_DEVICE_ROLE_DISABLED);
79
80     dispatchConnection = mConnection.get();
81     mDBusEventLoop     = std::thread([dispatchConnection]() {
82         while (true)
83         {
84             dbus_connection_read_write_dispatch(dispatchConnection, -1);
85         }
86     });
87     mDBusEventLoop.detach();
88 exit:
89     dbus_error_free(&dbusError);
90     LogClientError(error);
91     return OTBR_TO_CHIP_ERROR(error);
92 }
93
94 void ThreadStackManagerImpl::_ThreadDevcieRoleChangedHandler(DeviceRole role)
95 {
96     bool attached         = (role != DeviceRole::OTBR_DEVICE_ROLE_DETACHED && role != DeviceRole::OTBR_DEVICE_ROLE_DISABLED);
97     ChipDeviceEvent event = ChipDeviceEvent{};
98
99     if (attached != mAttached)
100     {
101         event.Type = DeviceEventType::kThreadConnectivityChange;
102         event.ThreadConnectivityChange.Result =
103             attached ? ConnectivityChange::kConnectivity_Established : ConnectivityChange::kConnectivity_Lost;
104         PlatformMgr().PostEvent(&event);
105     }
106
107     event.Type                          = DeviceEventType::kThreadStateChange;
108     event.ThreadStateChange.RoleChanged = true;
109     PlatformMgr().PostEvent(&event);
110 }
111
112 void ThreadStackManagerImpl::_ProcessThreadActivity() {}
113
114 static bool RouteMatch(const otbr::DBus::Ip6Prefix & prefix, const Inet::IPAddress & addr)
115 {
116     bool match = true;
117     const uint8_t * prefixBuffer;
118     const uint8_t * addrBuffer;
119     uint8_t wholeBytes  = prefix.mLength / CHAR_BIT;
120     uint8_t pendingBits = prefix.mLength % CHAR_BIT;
121
122     VerifyOrExit(addr.IsIPv6(), match = false);
123     VerifyOrExit(prefix.mLength > 0, match = false);
124
125     prefixBuffer = static_cast<const uint8_t *>(&prefix.mPrefix[0]);
126     addrBuffer   = reinterpret_cast<const uint8_t *>(&addr.Addr);
127     VerifyOrExit(memcmp(addrBuffer, prefixBuffer, wholeBytes) == 0, match = false);
128     if (pendingBits)
129     {
130         uint8_t mask = static_cast<uint8_t>(((UINT8_MAX >> pendingBits) << (CHAR_BIT - pendingBits)));
131
132         VerifyOrExit((addrBuffer[wholeBytes] & mask) == (addrBuffer[wholeBytes] & mask), match = false);
133     }
134     VerifyOrExit(memcmp(addrBuffer, prefixBuffer, wholeBytes) == 0, match = false);
135
136 exit:
137     return match;
138 }
139
140 bool ThreadStackManagerImpl::_HaveRouteToAddress(const Inet::IPAddress & destAddr)
141 {
142     std::vector<otbr::DBus::ExternalRoute> routes;
143     bool match = false;
144
145     VerifyOrExit(mThreadApi->GetExternalRoutes(routes) == ClientError::ERROR_NONE, match = false);
146     VerifyOrExit(_IsThreadAttached(), match = false);
147     VerifyOrExit(destAddr.IsIPv6LinkLocal(), match = true);
148     for (const auto & route : routes)
149     {
150         VerifyOrExit(!(match = RouteMatch(route.mPrefix, destAddr)), );
151     }
152
153 exit:
154     return match;
155 }
156
157 void ThreadStackManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
158 {
159     (void) event;
160     // The otbr-agent processes the Thread state handling by itself so there
161     // isn't much to do in the Chip stack.
162 }
163
164 CHIP_ERROR ThreadStackManagerImpl::_SetThreadProvision(const Internal::DeviceNetworkInfo & netInfo)
165 {
166     mNetworkInfo = netInfo;
167
168     // post an event alerting other subsystems about change in provisioning state
169     ChipDeviceEvent event;
170     event.Type                                           = DeviceEventType::kServiceProvisioningChange;
171     event.ServiceProvisioningChange.IsServiceProvisioned = true;
172     PlatformMgr().PostEvent(&event);
173
174     return CHIP_NO_ERROR;
175 }
176
177 CHIP_ERROR ThreadStackManagerImpl::_SetThreadProvision(const uint8_t * operationalDataset, size_t operationalDatasetLen)
178 {
179     mOperationalDatasetTlv = std::vector<uint8_t>(operationalDataset, operationalDataset + operationalDatasetLen);
180
181     // post an event alerting other subsystems about change in provisioning state
182     ChipDeviceEvent event;
183     event.Type                                           = DeviceEventType::kServiceProvisioningChange;
184     event.ServiceProvisioningChange.IsServiceProvisioned = true;
185     PlatformMgr().PostEvent(&event);
186
187     return CHIP_NO_ERROR;
188 }
189
190 CHIP_ERROR ThreadStackManagerImpl::_GetThreadProvision(Internal::DeviceNetworkInfo & netInfo, bool includeCredentials)
191 {
192     netInfo = mNetworkInfo;
193
194     if (!includeCredentials)
195     {
196         memset(&netInfo.ThreadMasterKey, 0, sizeof(netInfo.ThreadMasterKey));
197         memset(&netInfo.ThreadPSKc, 0, sizeof(netInfo.ThreadPSKc));
198         netInfo.FieldPresent.ThreadPSKc = false;
199     }
200
201     return CHIP_NO_ERROR;
202 }
203
204 bool ThreadStackManagerImpl::_IsThreadProvisioned()
205 {
206     return mNetworkInfo.ThreadNetworkName[0] != '\0';
207 }
208
209 void ThreadStackManagerImpl::_ErasePersistentInfo()
210 {
211     mNetworkInfo = Internal::DeviceNetworkInfo{};
212 }
213
214 bool ThreadStackManagerImpl::_IsThreadEnabled()
215 {
216     bool enabled = false;
217     DeviceRole role;
218     ClientError error;
219
220     SuccessOrExit(error = mThreadApi->GetDeviceRole(role));
221     enabled = (role != DeviceRole::OTBR_DEVICE_ROLE_DISABLED);
222 exit:
223     LogClientError(error);
224     return enabled;
225 }
226
227 bool ThreadStackManagerImpl::_IsThreadAttached()
228 {
229     return mAttached;
230 }
231
232 CHIP_ERROR ThreadStackManagerImpl::_SetThreadEnabled(bool val)
233 {
234     ClientError error = ClientError::ERROR_NONE;
235
236     if (val)
237     {
238         if (mOperationalDatasetTlv.size() > 0)
239         {
240             SuccessOrExit(error = mThreadApi->SetActiveDatasetTlvs(mOperationalDatasetTlv));
241             SuccessOrExit(error = mThreadApi->Attach([](ClientError result) {
242                 // ThreadDevcieRoleChangedHandler should take care of this, so we don't emit another event.
243                 ChipLogProgress(DeviceLayer, "Thread attach result %d", result);
244             }));
245         }
246         else
247         {
248             std::vector<uint8_t> masterkey(std::begin(mNetworkInfo.ThreadMasterKey), std::end(mNetworkInfo.ThreadMasterKey));
249             std::vector<uint8_t> pskc;
250             uint64_t extPanId    = UINT64_MAX;
251             uint32_t channelMask = UINT32_MAX;
252
253             if (mNetworkInfo.FieldPresent.ThreadExtendedPANId)
254             {
255                 extPanId = 0;
256                 for (size_t i = 0; i < extPanId; i++)
257                 {
258                     extPanId <<= CHAR_BIT;
259                     extPanId |= mNetworkInfo.ThreadExtendedPANId[i];
260                 }
261             }
262             if (mNetworkInfo.FieldPresent.ThreadPSKc)
263             {
264                 pskc = std::vector<uint8_t>(std::begin(mNetworkInfo.ThreadPSKc), std::end(mNetworkInfo.ThreadPSKc));
265             }
266             if (mNetworkInfo.ThreadChannel != Internal::kThreadChannel_NotSpecified)
267             {
268                 channelMask = 1 << mNetworkInfo.ThreadChannel;
269             }
270
271             if (mNetworkInfo.FieldPresent.ThreadMeshPrefix)
272             {
273                 std::array<uint8_t, Internal::kThreadMeshPrefixLength> prefix;
274
275                 std::copy(std::begin(mNetworkInfo.ThreadMeshPrefix), std::end(mNetworkInfo.ThreadMeshPrefix), std::begin(prefix));
276                 SuccessOrExit(error = mThreadApi->SetMeshLocalPrefix(prefix));
277             }
278
279             mThreadApi->Attach(mNetworkInfo.ThreadNetworkName, mNetworkInfo.ThreadPANId, extPanId, masterkey, pskc, channelMask,
280                                [](ClientError result) { ChipLogProgress(DeviceLayer, "Thread attach result %d", result); });
281         }
282     }
283     else
284     {
285         mThreadApi->Reset();
286     }
287 exit:
288     LogClientError(error);
289     return OTBR_TO_CHIP_ERROR(error);
290 }
291
292 ConnectivityManager::ThreadDeviceType ThreadStackManagerImpl::_GetThreadDeviceType()
293 {
294     ClientError error;
295     DeviceRole role;
296     LinkModeConfig linkMode;
297     ConnectivityManager::ThreadDeviceType type = ConnectivityManager::ThreadDeviceType::kThreadDeviceType_NotSupported;
298
299     SuccessOrExit(error = mThreadApi->GetDeviceRole(role));
300
301     switch (role)
302     {
303     case DeviceRole::OTBR_DEVICE_ROLE_DISABLED:
304     case DeviceRole::OTBR_DEVICE_ROLE_DETACHED:
305         break;
306     case DeviceRole::OTBR_DEVICE_ROLE_CHILD:
307         SuccessOrExit(error = mThreadApi->GetLinkMode(linkMode));
308         if (!linkMode.mRxOnWhenIdle)
309         {
310             type = ConnectivityManager::ThreadDeviceType::kThreadDeviceType_SleepyEndDevice;
311         }
312         else
313         {
314             type = linkMode.mDeviceType ? ConnectivityManager::ThreadDeviceType::kThreadDeviceType_FullEndDevice
315                                         : ConnectivityManager::ThreadDeviceType::kThreadDeviceType_MinimalEndDevice;
316         }
317         break;
318     case DeviceRole::OTBR_DEVICE_ROLE_ROUTER:
319     case DeviceRole::OTBR_DEVICE_ROLE_LEADER:
320         type = ConnectivityManager::ThreadDeviceType::kThreadDeviceType_Router;
321         break;
322     default:
323         ChipLogError(DeviceLayer, "Unknown Thread role: %d", static_cast<int>(role));
324         break;
325     }
326
327 exit:
328     LogClientError(error);
329     return type;
330 }
331
332 CHIP_ERROR ThreadStackManagerImpl::_SetThreadDeviceType(ConnectivityManager::ThreadDeviceType deviceType)
333 {
334     LinkModeConfig linkMode{ true, true, true };
335     ClientError error = ClientError::ERROR_NONE;
336
337     if (deviceType == ConnectivityManager::ThreadDeviceType::kThreadDeviceType_MinimalEndDevice)
338     {
339         linkMode.mNetworkData = false;
340     }
341     else if (deviceType == ConnectivityManager::ThreadDeviceType::kThreadDeviceType_SleepyEndDevice)
342     {
343         linkMode.mRxOnWhenIdle = false;
344         linkMode.mNetworkData  = false;
345     }
346
347     if (!linkMode.mNetworkData)
348     {
349         error = mThreadApi->SetLinkMode(linkMode);
350     }
351
352     LogClientError(error);
353     return OTBR_TO_CHIP_ERROR(error);
354 }
355
356 void ThreadStackManagerImpl::_GetThreadPollingConfig(ConnectivityManager::ThreadPollingConfig & pollingConfig)
357 {
358     (void) pollingConfig;
359
360     ChipLogError(DeviceLayer, "Polling config is not supported on linux");
361 }
362
363 CHIP_ERROR ThreadStackManagerImpl::_SetThreadPollingConfig(const ConnectivityManager::ThreadPollingConfig & pollingConfig)
364 {
365     (void) pollingConfig;
366
367     ChipLogError(DeviceLayer, "Polling config is not supported on linux");
368     return CHIP_ERROR_NOT_IMPLEMENTED;
369 }
370
371 bool ThreadStackManagerImpl::_HaveMeshConnectivity()
372 {
373     DeviceRole role;
374     ClientError error;
375     bool hasConnectivity = false;
376     std::vector<NeighborInfo> neighbors;
377
378     SuccessOrExit(error = mThreadApi->GetDeviceRole(role));
379     VerifyOrExit(role != DeviceRole::OTBR_DEVICE_ROLE_DETACHED && role != DeviceRole::OTBR_DEVICE_ROLE_DISABLED, );
380     if (role == DeviceRole::OTBR_DEVICE_ROLE_CHILD || role == DeviceRole::OTBR_DEVICE_ROLE_ROUTER)
381     {
382         hasConnectivity = true;
383     }
384
385     SuccessOrExit(error = mThreadApi->GetNeighborTable(neighbors));
386     for (const auto & neighbor : neighbors)
387     {
388         if (!neighbor.mIsChild)
389         {
390             hasConnectivity = true;
391             break;
392         }
393     }
394
395 exit:
396     LogClientError(error);
397     return hasConnectivity;
398 }
399
400 void ThreadStackManagerImpl::_OnMessageLayerActivityChanged(bool messageLayerIsActive)
401 {
402     (void) messageLayerIsActive;
403 }
404
405 void ThreadStackManagerImpl::_OnCHIPoBLEAdvertisingStart() {}
406
407 void ThreadStackManagerImpl::_OnCHIPoBLEAdvertisingStop() {}
408
409 CHIP_ERROR ThreadStackManagerImpl::_GetAndLogThreadStatsCounters()
410 {
411     // TODO: implement after we decide on the profiling protocol
412     return CHIP_ERROR_NOT_IMPLEMENTED;
413 }
414
415 CHIP_ERROR ThreadStackManagerImpl::_GetAndLogThreadTopologyMinimal()
416 {
417     // TODO: implement after we decide on the profiling protocol
418     return CHIP_ERROR_NOT_IMPLEMENTED;
419 }
420
421 CHIP_ERROR ThreadStackManagerImpl::_GetAndLogThreadTopologyFull()
422 {
423     // TODO: implement after we decide on the profiling protocol
424     return CHIP_ERROR_NOT_IMPLEMENTED;
425 }
426
427 CHIP_ERROR ThreadStackManagerImpl::_GetPrimary802154MACAddress(uint8_t * buf)
428 {
429     uint64_t extAddr;
430     ClientError error;
431     SuccessOrExit(error = mThreadApi->GetExtendedAddress(extAddr));
432
433     for (size_t i = 0; i < sizeof(extAddr); i++)
434     {
435         buf[sizeof(uint64_t) - i - 1] = (extAddr & UINT8_MAX);
436         extAddr >>= CHAR_BIT;
437     }
438
439 exit:
440     LogClientError(error);
441     return OTBR_TO_CHIP_ERROR(error);
442 }
443
444 CHIP_ERROR ThreadStackManagerImpl::_GetFactoryAssignedEUI64(uint8_t (&buf)[8])
445 {
446     return CHIP_ERROR_NOT_IMPLEMENTED;
447 }
448
449 CHIP_ERROR ThreadStackManagerImpl::_GetExternalIPv6Address(chip::Inet::IPAddress & addr)
450 {
451     return CHIP_ERROR_NOT_IMPLEMENTED;
452 }
453
454 CHIP_ERROR ThreadStackManagerImpl::_JoinerStart()
455 {
456     return CHIP_ERROR_NOT_IMPLEMENTED;
457 }
458
459 ThreadStackManager & ThreadStackMgr()
460 {
461     return chip::DeviceLayer::ThreadStackManagerImpl::sInstance;
462 }
463
464 ThreadStackManagerImpl & ThreadStackMgrImpl()
465 {
466     return chip::DeviceLayer::ThreadStackManagerImpl::sInstance;
467 }
468
469 } // namespace DeviceLayer
470 } // namespace chip