main.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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. #include "AppMain.h"
  19. #include <app/clusters/network-commissioning/network-commissioning.h>
  20. #include <app/clusters/ota-requestor/BDXDownloader.h>
  21. #include <app/clusters/ota-requestor/DefaultOTARequestor.h>
  22. #include <app/clusters/ota-requestor/DefaultOTARequestorStorage.h>
  23. #include <app/clusters/ota-requestor/DefaultOTARequestorUserConsent.h>
  24. #include <app/clusters/ota-requestor/ExtendedOTARequestorDriver.h>
  25. #include <app/util/af.h>
  26. #include <platform/Linux/OTAImageProcessorImpl.h>
  27. using chip::BDXDownloader;
  28. using chip::ByteSpan;
  29. using chip::CharSpan;
  30. using chip::EndpointId;
  31. using chip::FabricIndex;
  32. using chip::GetRequestorInstance;
  33. using chip::NodeId;
  34. using chip::OnDeviceConnected;
  35. using chip::OnDeviceConnectionFailure;
  36. using chip::OTADownloader;
  37. using chip::OTAImageProcessorImpl;
  38. using chip::PeerId;
  39. using chip::Server;
  40. using chip::VendorId;
  41. using chip::app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum;
  42. using chip::Callback::Callback;
  43. using chip::System::Layer;
  44. using chip::Transport::PeerAddress;
  45. using namespace chip;
  46. using namespace chip::app;
  47. using namespace chip::ArgParser;
  48. using namespace chip::DeviceLayer;
  49. using namespace chip::Messaging;
  50. using namespace chip::app::Clusters::OtaSoftwareUpdateProvider::Commands;
  51. class CustomOTARequestorDriver : public DeviceLayer::ExtendedOTARequestorDriver
  52. {
  53. public:
  54. bool CanConsent() override;
  55. void UpdateDownloaded() override;
  56. };
  57. DefaultOTARequestor gRequestorCore;
  58. DefaultOTARequestorStorage gRequestorStorage;
  59. CustomOTARequestorDriver gRequestorUser;
  60. BDXDownloader gDownloader;
  61. OTAImageProcessorImpl gImageProcessor;
  62. chip::ota::DefaultOTARequestorUserConsent gUserConsentProvider;
  63. static chip::ota::UserConsentState gUserConsentState = chip::ota::UserConsentState::kUnknown;
  64. bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue);
  65. constexpr uint16_t kOptionAutoApplyImage = 'a';
  66. constexpr uint16_t kOptionRequestorCanConsent = 'c';
  67. constexpr uint16_t kOptionOtaDownloadPath = 'f';
  68. constexpr uint16_t kOptionPeriodicQueryTimeout = 'p';
  69. constexpr uint16_t kOptionUserConsentState = 'u';
  70. constexpr uint16_t kOptionWatchdogTimeout = 'w';
  71. constexpr size_t kMaxFilePathSize = 256;
  72. uint32_t gPeriodicQueryTimeoutSec = 0;
  73. uint32_t gWatchdogTimeoutSec = 0;
  74. chip::Optional<bool> gRequestorCanConsent;
  75. static char gOtaDownloadPath[kMaxFilePathSize] = "/tmp/test.bin";
  76. bool gAutoApplyImage = false;
  77. OptionDef cmdLineOptionsDef[] = {
  78. { "autoApplyImage", chip::ArgParser::kNoArgument, kOptionAutoApplyImage },
  79. { "requestorCanConsent", chip::ArgParser::kArgumentRequired, kOptionRequestorCanConsent },
  80. { "otaDownloadPath", chip::ArgParser::kArgumentRequired, kOptionOtaDownloadPath },
  81. { "periodicQueryTimeout", chip::ArgParser::kArgumentRequired, kOptionPeriodicQueryTimeout },
  82. { "userConsentState", chip::ArgParser::kArgumentRequired, kOptionUserConsentState },
  83. { "watchdogTimeout", chip::ArgParser::kArgumentRequired, kOptionWatchdogTimeout },
  84. {},
  85. };
  86. OptionSet cmdLineOptions = {
  87. HandleOptions, cmdLineOptionsDef, "PROGRAM OPTIONS",
  88. " -a, --autoApplyImage\n"
  89. " If supplied, apply the image immediately after download.\n"
  90. " Otherwise, the OTA update is complete after image download.\n"
  91. " -c, --requestorCanConsent <true | false>\n"
  92. " Value for the RequestorCanConsent field in the QueryImage command.\n"
  93. " If not supplied, the value is determined by the driver.\n"
  94. " -f, --otaDownloadPath <file path>\n"
  95. " If supplied, the OTA image is downloaded to the given fully-qualified file-path.\n"
  96. " Otherwise, the default location for the downloaded image is at /tmp/test.bin\n"
  97. " -p, --periodicQueryTimeout <time in seconds>\n"
  98. " The periodic time interval to wait before attempting to query a provider from the default OTA provider list.\n"
  99. " If none or zero is supplied, the timeout is determined by the driver.\n"
  100. " -u, --userConsentState <granted | denied | deferred>\n"
  101. " Represents the current user consent status when the OTA Requestor is acting as a user consent\n"
  102. " delegate. This value is only applicable if value of the UserConsentNeeded field in the\n"
  103. " QueryImageResponse is set to true. This value is used for the first attempt to\n"
  104. " download. For all subsequent queries, the value of granted will be used.\n"
  105. " granted: Authorize OTA requestor to download an OTA image\n"
  106. " denied: Forbid OTA requestor to download an OTA image\n"
  107. " deferred: Defer obtaining user consent\n"
  108. " -w, --watchdogTimeout <time in seconds>\n"
  109. " Maximum amount of time allowed for an OTA download before the process is cancelled and state reset to idle.\n"
  110. " If none or zero is supplied, the timeout is determined by the driver.\n"
  111. };
  112. OptionSet * allOptions[] = { &cmdLineOptions, nullptr };
  113. // Network commissioning
  114. namespace {
  115. constexpr EndpointId kNetworkCommissioningEndpointMain = 0;
  116. constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE;
  117. // This file is being used by platforms other than Linux, so we need this check to disable related features since we only
  118. // implemented them on linux.
  119. #if CHIP_DEVICE_LAYER_TARGET_LINUX
  120. #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
  121. NetworkCommissioning::LinuxThreadDriver sLinuxThreadDriver;
  122. Clusters::NetworkCommissioning::Instance sThreadNetworkCommissioningInstance(kNetworkCommissioningEndpointMain,
  123. &sLinuxThreadDriver);
  124. #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD
  125. #if CHIP_DEVICE_CONFIG_ENABLE_WPA
  126. NetworkCommissioning::LinuxWiFiDriver sLinuxWiFiDriver;
  127. Clusters::NetworkCommissioning::Instance sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointSecondary,
  128. &sLinuxWiFiDriver);
  129. #endif // CHIP_DEVICE_CONFIG_ENABLE_WPA
  130. NetworkCommissioning::LinuxEthernetDriver sLinuxEthernetDriver;
  131. Clusters::NetworkCommissioning::Instance sEthernetNetworkCommissioningInstance(kNetworkCommissioningEndpointMain,
  132. &sLinuxEthernetDriver);
  133. #else // CHIP_DEVICE_LAYER_TARGET_LINUX
  134. Clusters::NetworkCommissioning::NullNetworkDriver sNullNetworkDriver;
  135. Clusters::NetworkCommissioning::Instance sNullNetworkCommissioningInstance(kNetworkCommissioningEndpointMain, &sNullNetworkDriver);
  136. #endif // CHIP_DEVICE_LAYER_TARGET_LINUX
  137. } // namespace
  138. bool CustomOTARequestorDriver::CanConsent()
  139. {
  140. return gRequestorCanConsent.ValueOr(DeviceLayer::ExtendedOTARequestorDriver::CanConsent());
  141. }
  142. void CustomOTARequestorDriver::UpdateDownloaded()
  143. {
  144. if (gAutoApplyImage)
  145. {
  146. // Let the default driver take further action to apply the image.
  147. // All member variables will be implicitly reset upon loading into the new image.
  148. DefaultOTARequestorDriver::UpdateDownloaded();
  149. }
  150. else
  151. {
  152. // Download complete but we're not going to apply image, so reset provider retry counter.
  153. mProviderRetryCount = 0;
  154. // Reset to put the state back to idle to allow the next OTA update to occur
  155. gRequestorCore.Reset();
  156. }
  157. }
  158. static void InitOTARequestor(void)
  159. {
  160. // Set the global instance of the OTA requestor core component
  161. SetRequestorInstance(&gRequestorCore);
  162. // Periodic query timeout must be set prior to the driver being initialized
  163. gRequestorUser.SetPeriodicQueryTimeout(gPeriodicQueryTimeoutSec);
  164. // Watchdog timeout can be set any time before a query image is sent
  165. gRequestorUser.SetWatchdogTimeout(gWatchdogTimeoutSec);
  166. gRequestorStorage.Init(chip::Server::GetInstance().GetPersistentStorage());
  167. gRequestorCore.Init(chip::Server::GetInstance(), gRequestorStorage, gRequestorUser, gDownloader);
  168. gRequestorUser.Init(&gRequestorCore, &gImageProcessor);
  169. gImageProcessor.SetOTAImageFile(gOtaDownloadPath);
  170. gImageProcessor.SetOTADownloader(&gDownloader);
  171. // Set the image processor instance used for handling image being downloaded
  172. gDownloader.SetImageProcessorDelegate(&gImageProcessor);
  173. if (gUserConsentState != chip::ota::UserConsentState::kUnknown)
  174. {
  175. gUserConsentProvider.SetUserConsentState(gUserConsentState);
  176. gRequestorUser.SetUserConsentDelegate(&gUserConsentProvider);
  177. }
  178. }
  179. static void InitNetworkCommissioning(void)
  180. {
  181. (void) kNetworkCommissioningEndpointMain;
  182. // Enable secondary endpoint only when we need it, this should be applied to all platforms.
  183. emberAfEndpointEnableDisable(kNetworkCommissioningEndpointSecondary, false);
  184. #if CHIP_DEVICE_LAYER_TARGET_LINUX
  185. const bool kThreadEnabled = {
  186. #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
  187. LinuxDeviceOptions::GetInstance().mThread
  188. #else
  189. false
  190. #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD
  191. };
  192. const bool kWiFiEnabled = {
  193. #if CHIP_DEVICE_CONFIG_ENABLE_WPA
  194. LinuxDeviceOptions::GetInstance().mWiFi
  195. #else
  196. false
  197. #endif // CHIP_DEVICE_CONFIG_ENABLE_WPA
  198. };
  199. if (kThreadEnabled && kWiFiEnabled)
  200. {
  201. #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
  202. sThreadNetworkCommissioningInstance.Init();
  203. #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD
  204. #if CHIP_DEVICE_CONFIG_ENABLE_WPA
  205. sWiFiNetworkCommissioningInstance.Init();
  206. #endif // CHIP_DEVICE_CONFIG_ENABLE_WPA
  207. // Only enable secondary endpoint for network commissioning cluster when both WiFi and Thread are enabled.
  208. emberAfEndpointEnableDisable(kNetworkCommissioningEndpointSecondary, true);
  209. }
  210. else if (kThreadEnabled)
  211. {
  212. #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
  213. sThreadNetworkCommissioningInstance.Init();
  214. #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD
  215. }
  216. else if (kWiFiEnabled)
  217. {
  218. #if CHIP_DEVICE_CONFIG_ENABLE_WPA
  219. // If we only enable WiFi on this device, "move" WiFi instance to main NetworkCommissioning cluster endpoint.
  220. sWiFiNetworkCommissioningInstance.~Instance();
  221. new (&sWiFiNetworkCommissioningInstance)
  222. Clusters::NetworkCommissioning::Instance(kNetworkCommissioningEndpointMain, &sLinuxWiFiDriver);
  223. sWiFiNetworkCommissioningInstance.Init();
  224. #endif // CHIP_DEVICE_CONFIG_ENABLE_WPA
  225. }
  226. else
  227. #endif // CHIP_DEVICE_LAYER_TARGET_LINUX
  228. {
  229. #if CHIP_DEVICE_LAYER_TARGET_LINUX
  230. sEthernetNetworkCommissioningInstance.Init();
  231. #else
  232. // Use NullNetworkCommissioningInstance to disable the network commissioning functions.
  233. sNullNetworkCommissioningInstance.Init();
  234. #endif // CHIP_DEVICE_LAYER_TARGET_LINUX
  235. }
  236. }
  237. bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue)
  238. {
  239. bool retval = true;
  240. switch (aIdentifier)
  241. {
  242. case kOptionPeriodicQueryTimeout:
  243. gPeriodicQueryTimeoutSec = static_cast<uint32_t>(strtoul(aValue, NULL, 0));
  244. break;
  245. case kOptionRequestorCanConsent:
  246. if (strcmp(aValue, "true") == 0)
  247. {
  248. gRequestorCanConsent.SetValue(true);
  249. }
  250. else if (strcmp(aValue, "false") == 0)
  251. {
  252. gRequestorCanConsent.SetValue(false);
  253. }
  254. else
  255. {
  256. ChipLogError(SoftwareUpdate, "%s: ERROR: Invalid requestorCanConsent parameter: %s\n", aProgram, aValue);
  257. retval = false;
  258. }
  259. break;
  260. case kOptionOtaDownloadPath:
  261. chip::Platform::CopyString(gOtaDownloadPath, aValue);
  262. break;
  263. case kOptionUserConsentState:
  264. if (strcmp(aValue, "granted") == 0)
  265. {
  266. gUserConsentState = chip::ota::UserConsentState::kGranted;
  267. }
  268. else if (strcmp(aValue, "denied") == 0)
  269. {
  270. gUserConsentState = chip::ota::UserConsentState::kDenied;
  271. }
  272. else if (strcmp(aValue, "deferred") == 0)
  273. {
  274. gUserConsentState = chip::ota::UserConsentState::kObtaining;
  275. }
  276. else
  277. {
  278. ChipLogError(SoftwareUpdate, "%s: ERROR: Invalid UserConsent parameter: %s\n", aProgram, aValue);
  279. retval = false;
  280. }
  281. break;
  282. case kOptionAutoApplyImage:
  283. gAutoApplyImage = true;
  284. break;
  285. case kOptionWatchdogTimeout:
  286. gWatchdogTimeoutSec = static_cast<uint32_t>(strtoul(aValue, NULL, 0));
  287. break;
  288. default:
  289. ChipLogError(SoftwareUpdate, "%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName);
  290. retval = false;
  291. break;
  292. }
  293. return (retval);
  294. }
  295. void ApplicationInit()
  296. {
  297. // Initialize all OTA download components
  298. InitOTARequestor();
  299. // Initialize Network Commissioning instances
  300. InitNetworkCommissioning();
  301. }
  302. int main(int argc, char * argv[])
  303. {
  304. VerifyOrDie(ChipLinuxAppInit(argc, argv, &cmdLineOptions) == 0);
  305. ChipLinuxAppMainLoop();
  306. // If the event loop had been stopped due to an update being applied, boot into the new image
  307. if (gRequestorCore.GetCurrentUpdateState() == OTAUpdateStateEnum::kApplying)
  308. {
  309. if (kMaxFilePathSize <= strlen(kImageExecPath))
  310. {
  311. ChipLogError(SoftwareUpdate, "Buffer too small for the new image file path: %s", kImageExecPath);
  312. return -1;
  313. }
  314. argv[0] = kImageExecPath;
  315. execv(argv[0], argv);
  316. // If successfully executing the new image, execv should not return
  317. ChipLogError(SoftwareUpdate, "The OTA image is invalid");
  318. }
  319. return 0;
  320. }