Simple interface for Mbed Cloud Client

Dependents:  

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers update_client_hub_state_machine.c Source File

update_client_hub_state_machine.c

00001 // ----------------------------------------------------------------------------
00002 // Copyright 2016-2017 ARM Ltd.
00003 //
00004 // SPDX-License-Identifier: Apache-2.0
00005 //
00006 // Licensed under the Apache License, Version 2.0 (the "License");
00007 // you may not use this file except in compliance with the License.
00008 // You may obtain a copy of the License at
00009 //
00010 //     http://www.apache.org/licenses/LICENSE-2.0
00011 //
00012 // Unless required by applicable law or agreed to in writing, software
00013 // distributed under the License is distributed on an "AS IS" BASIS,
00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 // See the License for the specific language governing permissions and
00016 // limitations under the License.
00017 // ----------------------------------------------------------------------------
00018 
00019 #include "update_client_hub_state_machine.h"
00020 #include "update_client_hub_error_handler.h"
00021 #include "update-client-hub/update_client_hub.h"
00022 
00023 #include "update-client-common/arm_uc_common.h"
00024 #include "update-client-firmware-manager/arm_uc_firmware_manager.h"
00025 #include "update-client-manifest-manager/update-client-manifest-manager.h"
00026 #include "update-client-source-manager/arm_uc_source_manager.h"
00027 #include "update-client-control-center/arm_uc_control_center.h"
00028 #include "update-client-control-center/arm_uc_pre_shared_key.h"
00029 
00030 #include "mbedtls/aes.h"
00031 
00032 #include "pal.h"
00033 #include "sotp.h"
00034 
00035 #include <inttypes.h>
00036 
00037 /*****************************************************************************/
00038 /* Global variables                                                          */
00039 /*****************************************************************************/
00040 
00041 #ifndef MAX_FIRMWARE_LOCATIONS
00042 #define MAX_FIRMWARE_LOCATIONS 1
00043 #endif
00044 
00045 // state of the hub state machine
00046 static arm_uc_hub_state_t arm_uc_hub_state = ARM_UC_HUB_STATE_UNINITIALIZED;
00047 
00048 // the call back function registered by the user to signal end of intilisation
00049 static void (*arm_uc_hub_init_cb)(int32_t) = NULL;
00050 
00051 // The hub uses a double buffer system to speed up firmware download and storage
00052 #define BUFFER_SIZE_MAX (ARM_UC_BUFFER_SIZE / 2) //  define size of the double buffers
00053 static uint8_t message[BUFFER_SIZE_MAX];
00054 static arm_uc_buffer_t front_buffer = {
00055     .size_max = BUFFER_SIZE_MAX,
00056     .size = 0,
00057     .ptr = message
00058 };
00059 
00060 static uint8_t message2[BUFFER_SIZE_MAX];
00061 static arm_uc_buffer_t back_buffer = {
00062     .size_max = BUFFER_SIZE_MAX,
00063     .size = 0,
00064     .ptr = message2
00065 };
00066 
00067 // version (timestamp) of the current running application
00068 static arm_uc_firmware_details_t arm_uc_active_details = { 0 };
00069 
00070 // bootloader information
00071 static arm_uc_installer_details_t arm_uc_installer_details = { 0 };
00072 
00073 // variable to keep track of the offset into the firmware image during download
00074 static uint32_t firmware_offset = 0;
00075 
00076 // variable to store the firmware config during firmware manager setup
00077 static ARM_UCFM_Setup_t arm_uc_hub_firmware_config = { 0 };
00078 
00079 // the structure used to count the number of stored update images
00080 typedef struct {
00081     uint32_t current_id;
00082     uint32_t num_images;
00083     uint64_t image_version;
00084     arm_uc_firmware_details_t details;
00085 } arm_uc_stored_images_t;
00086 
00087 // variable to store the stored images structure above
00088 static arm_uc_stored_images_t stored_images = { 0 };
00089 
00090 // buffer to store the decoded firmware key
00091 #define PLAIN_FIRMWARE_KEY_SIZE 16
00092 static uint8_t plainFirmwareKey[PLAIN_FIRMWARE_KEY_SIZE];
00093 static arm_uc_buffer_t arm_uc_hub_plain_key = {
00094     .size_max = PLAIN_FIRMWARE_KEY_SIZE,
00095     .size     = PLAIN_FIRMWARE_KEY_SIZE,
00096     .ptr      = plainFirmwareKey
00097 };
00098 
00099 static arm_uc_mmContext_t manifestManagerContext = { 0 };
00100 static arm_uc_mmContext_t* pManifestManagerContext = &manifestManagerContext;
00101 static manifest_firmware_info_t fwinfo = { 0 };
00102 
00103 // buffer to store a uri struct
00104 #define URI_STRING_LEN 256
00105 uint8_t uri_buffer[URI_STRING_LEN] = {0};
00106 
00107 static arm_uc_uri_t uri = {
00108     .size_max = sizeof(uri_buffer),
00109     .size     = 0,
00110     .ptr      = uri_buffer,
00111     .port     = 0,
00112     .scheme   = URI_SCHEME_NONE,
00113     .host     = NULL,
00114     .path     = NULL,
00115 };
00116 
00117 /*****************************************************************************/
00118 /* Debug                                                                     */
00119 /*****************************************************************************/
00120 
00121 #if ARM_UC_HUB_TRACE_ENABLE
00122 static void arm_uc_hub_debug_output()
00123 {
00124     printf("Manifest timestamp: %" PRIu64 "\r\n", fwinfo.timestamp);
00125 
00126     if (uri.scheme == URI_SCHEME_HTTP)
00127     {
00128         printf("Firmware URL http://%s:%" PRIu16 "%s\r\n",
00129             uri.host, uri.port, uri.path);
00130     }
00131 
00132     printf("Firmware size: %" PRIu32 "\r\n",fwinfo.size);
00133 
00134     printf("Firmware hash (%" PRIu32 "): ", fwinfo.hash.size);
00135     for (unsigned i = 0; i < fwinfo.hash.size; i++)
00136     {
00137         printf("%02" PRIx8, fwinfo.hash.ptr[i]);
00138     }
00139     printf("\r\n");
00140 
00141     if (fwinfo.cipherMode == ARM_UC_MM_CIPHERMODE_PSK)
00142     {
00143         printf("PSK ID: ");
00144         for (unsigned i = 0; i < fwinfo.psk.keyID.size; i++)
00145         {
00146             printf("%02" PRIx8, *(fwinfo.psk.keyID.ptr+i));
00147         }
00148         printf("\r\n");
00149 
00150         printf("cipherKey(16): ");
00151         for (unsigned i = 0; i < 16; i++)
00152         {
00153             printf("%02" PRIx8, *(fwinfo.psk.cipherKey.ptr+i));
00154         }
00155         printf("\r\n");
00156 
00157         printf("Decrypted Firmware Symmetric Key(16): ");
00158         for (unsigned i = 0; i < 16; i++)
00159         {
00160             printf("%02" PRIx8, arm_uc_hub_plain_key.ptr[i]);
00161         }
00162         printf("\r\n");
00163 
00164         printf("fwinfo.initVector\r\n");
00165         for (unsigned i = 0; i < 16; i++)
00166         {
00167             printf("%02" PRIx8, *(fwinfo.initVector.ptr+i));
00168         }
00169         printf("\r\n");
00170     }
00171 
00172     printf("Storage location: %" PRIu32 "\r\n",
00173            arm_uc_hub_firmware_config.package_id);
00174 }
00175 #endif
00176 
00177 /*****************************************************************************/
00178 /* State machine                                                             */
00179 /*****************************************************************************/
00180 
00181 /* Short hand for simple error handling code */
00182 #define HANDLE_ERROR(retval, msg, ...)                  \
00183     if (retval.error != ERR_NONE)                       \
00184     {                                                   \
00185         UC_HUB_ERR_MSG(msg " error code %s",            \
00186                        ##__VA_ARGS__,                   \
00187                        ARM_UC_err2Str(retval));         \
00188         new_state = ARM_UC_HUB_STATE_IDLE;              \
00189         break;                                          \
00190     }
00191 
00192 arm_uc_hub_state_t ARM_UC_HUB_getState()
00193 {
00194     return arm_uc_hub_state;
00195 }
00196 
00197 void ARM_UC_HUB_setInitializationCallback(void (*callback)(int32_t))
00198 {
00199     arm_uc_hub_init_cb = callback;
00200 }
00201 
00202 void ARM_UC_HUB_setState(arm_uc_hub_state_t new_state)
00203 {
00204     arm_uc_error_t retval;
00205 
00206     /* Loop until state is unchanged.
00207        First loop is mandatory regardless of current state.
00208     */
00209     do
00210     {
00211         /* store new stage */
00212         arm_uc_hub_state = new_state;
00213 
00214         switch (arm_uc_hub_state)
00215         {
00216             /*****************************************************************/
00217             /* Initialization                                                */
00218             /*****************************************************************/
00219             case ARM_UC_HUB_STATE_INITIALIZED:
00220                 UC_HUB_TRACE("ARM_UC_HUB_STATE_INITIALIZED");
00221 
00222                 /* signal that the Hub is initialized */
00223                 if (arm_uc_hub_init_cb)
00224                 {
00225                     arm_uc_hub_init_cb(ARM_UC_INIT_DONE);
00226                 }
00227 
00228                 /* report the active firmware hash to the Cloud in parallel
00229                    with the main user application.
00230                 */
00231                 new_state = ARM_UC_HUB_STATE_GET_ACTIVE_FIRMWARE_DETAILS;
00232                 break;
00233 
00234             /*****************************************************************/
00235             /* Report current firmware hash                                  */
00236             /*****************************************************************/
00237             case ARM_UC_HUB_STATE_GET_ACTIVE_FIRMWARE_DETAILS:
00238                 UC_HUB_TRACE("ARM_UC_HUB_STATE_GET_ACTIVE_FIRMWARE_DETAILS");
00239 
00240                 retval = ARM_UC_FirmwareManager.GetActiveFirmwareDetails(&arm_uc_active_details);
00241                 HANDLE_ERROR(retval, "Firmware manager GetActiveFirmwareDetails failed");
00242                 break;
00243 
00244             case ARM_UC_HUB_STATE_REPORT_ACTIVE_HASH:
00245                 UC_HUB_TRACE("ARM_UC_HUB_STATE_REPORT_ACTIVE_HASH");
00246 
00247                 /* copy hash to buffer */
00248                 memcpy(front_buffer.ptr,
00249                        arm_uc_active_details.hash,
00250                        ARM_UC_SHA256_SIZE);
00251 
00252                 front_buffer.size = ARM_UC_SHA256_SIZE;
00253 
00254                 /* send hash to update service */
00255                 ARM_UC_ControlCenter_ReportName(&front_buffer);
00256 
00257                 new_state = ARM_UC_HUB_STATE_REPORT_ACTIVE_VERSION;
00258                 break;
00259 
00260             /*****************************************************************/
00261             /* Report current firmware version                               */
00262             /*****************************************************************/
00263             case ARM_UC_HUB_STATE_REPORT_ACTIVE_VERSION:
00264                 UC_HUB_TRACE("ARM_UC_HUB_STATE_REPORT_ACTIVE_VERSION");
00265 
00266                 UC_HUB_TRACE("Active version: %" PRIu64,
00267                              arm_uc_active_details.version);
00268 
00269                 /* send timestamp to update service */
00270                 ARM_UC_ControlCenter_ReportVersion(arm_uc_active_details.version);
00271 
00272                 new_state = ARM_UC_HUB_STATE_GET_INSTALLER_DETAILS;
00273                 break;
00274 
00275             /*****************************************************************/
00276             /* Report bootloader information                                 */
00277             /*****************************************************************/
00278             case ARM_UC_HUB_STATE_GET_INSTALLER_DETAILS:
00279                 UC_HUB_TRACE("ARM_UC_HUB_STATE_GET_INSTALLER_DETAILS");
00280 
00281                 retval = ARM_UC_FirmwareManager.GetInstallerDetails(&arm_uc_installer_details);
00282                 if (retval.error != ERR_NONE)
00283                 {
00284                     UC_HUB_ERR_MSG("Firmware manager GetInstallerDetails failed error code %s",
00285                                    ARM_UC_err2Str(retval));
00286                     new_state = ARM_UC_HUB_STATE_CHECK_OEM_MODE_RESET;
00287                 }
00288                 break;
00289 
00290             case ARM_UC_HUB_STATE_REPORT_INSTALLER_DETAILS:
00291                 UC_HUB_TRACE("ARM_UC_HUB_STATE_REPORT_INSTALLER_DETAILS");
00292 
00293 #if 0
00294                 printf("bootloader: ");
00295                 for (uint32_t index = 0; index < 20; index++)
00296                 {
00297                     printf("%02X", arm_uc_installer_details.arm_hash[index]);
00298                 }
00299                 printf("\r\n");
00300 
00301                 printf("layout: %" PRIu32 "\r\n", arm_uc_installer_details.layout);
00302 #endif
00303 
00304                 /* report installer details to mbed cloud */
00305                 arm_uc_buffer_t bootloader_hash = {
00306                     .size_max = ARM_UC_SHA256_SIZE,
00307                     .size = ARM_UC_SHA256_SIZE,
00308                     .ptr = (arm_uc_installer_details.arm_hash)
00309                 };
00310                 ARM_UC_ControlCenter_ReportBootloaderHash(&bootloader_hash);
00311 
00312                 bootloader_hash.ptr = (arm_uc_installer_details.oem_hash);
00313                 ARM_UC_ControlCenter_ReportOEMBootloaderHash(&bootloader_hash);
00314 
00315                 /* set new state */
00316                 new_state = ARM_UC_HUB_STATE_CHECK_OEM_MODE_RESET;
00317                 break;
00318 
00319             /*****************************************************************/
00320             /* Check if the OEM transfer mode needs to be reset              */
00321             /*****************************************************************/
00322             case ARM_UC_HUB_STATE_CHECK_OEM_MODE_RESET:
00323                 UC_HUB_TRACE("ARM_UC_HUB_STATE_CHECK_OEM_MODE_RESET");
00324                 {
00325                     uint32_t temp32 = 0;
00326                     /* read the "OEM transfer mode" flag and check if it is valid */
00327                     arm_uc_error_t sotp_status = arm_uc_read_sotp_uint(SOTP_TYPE_OEM_TRANSFER_MODE_ENABLED,
00328                                                                            sizeof(uint32_t), &temp32);
00329                     /* if the "OEM transfer mode" is enabled, check if it needs to be reset */
00330                     if (sotp_status.code == ERR_NONE && temp32 > 0)
00331                     {
00332                         UC_HUB_TRACE("Checking if the OEM transfer mode flag needs to be cleared");
00333                         /* "OEM transfer mode" needs to be reset if there is exactly one
00334                            candidate image and that it has the same timestamp as the active
00335                            image. So start looking at the available update images by changing
00336                            the state to ARM_UC_HUB_STATE_GET_STORED_FIRMWARE_DETAILS.
00337                         */
00338                         new_state = ARM_UC_HUB_STATE_GET_STORED_FIRMWARE_DETAILS;
00339                     }
00340                     else
00341                     {
00342                         new_state = ARM_UC_HUB_STATE_IDLE;
00343                     }
00344                 }
00345                 break;
00346 
00347             case ARM_UC_HUB_STATE_GET_STORED_FIRMWARE_DETAILS:
00348                 UC_HUB_TRACE("ARM_UC_HUB_STATE_GET_STORED_FIRMWARE_DETAILS");
00349                 /* Stop looking for firmware images either when the current image ID
00350                    is too large or when we found more than one valid stored image.
00351                 */
00352                 while (new_state == ARM_UC_HUB_STATE_GET_STORED_FIRMWARE_DETAILS)
00353                 {
00354                     if (stored_images.current_id == MAX_FIRMWARE_LOCATIONS || stored_images.num_images > 1)
00355                     {
00356                         if (stored_images.num_images == 1 &&
00357                             stored_images.image_version == arm_uc_active_details.version)
00358                         {
00359                             /* set "OEM tranfer mode" to 0 */
00360                             uint32_t temp32 = 0;
00361                             arm_uc_error_t sotp_status = arm_uc_write_sotp_uint(SOTP_TYPE_OEM_TRANSFER_MODE_ENABLED,
00362                                                                                     sizeof(uint32_t), &temp32);
00363                             if (sotp_status.code == ERR_NONE)
00364                             {
00365                                 UC_HUB_TRACE("OEM transfer mode flag cleared");
00366                             }
00367                             else
00368                             {
00369                                 UC_HUB_ERR_MSG("Unable to clear the OEM tranfer mode flag");
00370                             }
00371                         }
00372                         new_state = ARM_UC_HUB_STATE_IDLE;
00373                     }
00374                     else
00375                     {
00376                         UC_HUB_TRACE("GetFirmwareDetails for image %" PRIu32, stored_images.current_id);
00377                         arm_uc_error_t ucp_status = ARM_UCP_GetFirmwareDetails(stored_images.current_id,
00378                                                                             &stored_images.details);
00379                         if (ucp_status.error != ERR_NONE)
00380                         {
00381                             UC_HUB_TRACE("GetFirmwareDetails for image %" PRIu32 " failed",
00382                                         stored_images.current_id);
00383                             /* error reading this image, try to read the next one */
00384                             stored_images.current_id ++;
00385                         }
00386                         else
00387                         {
00388                             /* GetFirmwareDetails will raise an event when it's done, which will change
00389                                the state to either ARM_UC_HUB_STATE_STORED_FIRMWARE_DETAILS_OK or
00390                                ARM_UC_HUB_STATE_STORED_FIRMWARE_DETAILS_ERROR below */
00391                             break;
00392                         }
00393                     }
00394                 }
00395                 break;
00396 
00397             case ARM_UC_HUB_STATE_STORED_FIRMWARE_DETAILS_OK:
00398                 UC_HUB_TRACE("ARM_UC_HUB_STATE_STORED_FIRMWARE_DETAILS_OK");
00399                 stored_images.num_images ++;
00400                 if (stored_images.num_images == 1)
00401                 {
00402                     /* Store the image version that will be checked only for the first image.
00403                        If there are more images, the version is not relevant anymore, since
00404                        the "OEM transfer mode" won't be reset anyway, because it requires
00405                        exacly one valid stored image to be present.
00406                     */
00407                     stored_images.image_version = stored_images.details.version;
00408                 }
00409                 stored_images.current_id ++;
00410                 new_state = ARM_UC_HUB_STATE_GET_STORED_FIRMWARE_DETAILS;
00411                 break;
00412 
00413             case ARM_UC_HUB_STATE_STORED_FIRMWARE_DETAILS_ERROR:
00414                 UC_HUB_TRACE("ARM_UC_HUB_STATE_STORED_FIRMWARE_DETAILS_ERROR");
00415                 stored_images.current_id ++;
00416                 new_state = ARM_UC_HUB_STATE_GET_STORED_FIRMWARE_DETAILS;
00417                 break;
00418 
00419             /*****************************************************************/
00420             /* Idle                                                          */
00421             /*****************************************************************/
00422             case ARM_UC_HUB_STATE_IDLE:
00423                 UC_HUB_TRACE("ARM_UC_MONITOR_STATE_IDLE");
00424 
00425                 /* signal monitor that device has entered IDLE state */
00426                 ARM_UC_ControlCenter_ReportState(ARM_UC_MONITOR_STATE_IDLE);
00427                 break;
00428 
00429             /*****************************************************************/
00430             /* Download manifest                                             */
00431             /*****************************************************************/
00432             case ARM_UC_HUB_STATE_NOTIFIED:
00433                 UC_HUB_TRACE("ARM_UC_HUB_STATE_NOTIFIED");
00434 
00435                 /* notification received of a new manifest, hence go get said manifest */
00436                 retval = ARM_UC_SourceManager.GetManifest(&front_buffer, 0);
00437                 HANDLE_ERROR(retval, "Source manager GetManifest failed");
00438                 break;
00439 
00440             case ARM_UC_HUB_STATE_MANIFEST_FETCHED:
00441                 UC_HUB_TRACE("ARM_UC_HUB_STATE_MANIFEST_FETCHED");
00442 
00443                 /* Save the manifest for later */
00444                 memcpy(&fwinfo.manifestBuffer, front_buffer.ptr,
00445                     ARM_UC_util_min(sizeof(fwinfo.manifestBuffer), front_buffer.size));
00446                 /* Save the manifest size for later */
00447                 fwinfo.manifestSize = front_buffer.size;
00448                 /* insert the manifest we just fetched into manifest manager */
00449                 retval = ARM_UC_mmInsert(&pManifestManagerContext, &front_buffer, &back_buffer,  NULL);
00450                 if (retval.code != MFST_ERR_PENDING)
00451                 {
00452                     HANDLE_ERROR(retval, "Manifest manager Insert failed")
00453                 }
00454                 break;
00455 
00456             /*****************************************************************/
00457             /* Rollback protection                                           */
00458             /*****************************************************************/
00459             case ARM_UC_HUB_STATE_MANIFEST_COMPLETE:
00460                 UC_HUB_TRACE("ARM_UC_HUB_STATE_MANIFEST_COMPLETE");
00461 
00462                 /* get the firmware info out of the manifest we just inserted
00463                    into the manifest manager
00464                 */
00465                 retval = ARM_UC_mmFetchFirmwareInfo(&pManifestManagerContext,
00466                                                     &fwinfo,
00467                                                     NULL);
00468                 if (retval.code != MFST_ERR_PENDING)
00469                 {
00470                     HANDLE_ERROR(retval, "Manifest manager fetch info failed")
00471                 }
00472                 break;
00473 
00474             case ARM_UC_HUB_STATE_CHECK_VERSION:
00475                 UC_HUB_TRACE("ARM_UC_HUB_STATE_CHECK_VERSION");
00476                 {
00477                     /* check for OEM transfer mode and the minimal firmware version */
00478                     uint64_t min_fw_version = arm_uc_active_details.version;
00479                     uint32_t temp32 = 0;
00480                     /* read the "OEM transfer mode" flag and check if it is valid */
00481                     arm_uc_error_t sotp_status = arm_uc_read_sotp_uint(SOTP_TYPE_OEM_TRANSFER_MODE_ENABLED,
00482                                                                            sizeof(uint32_t), &temp32);
00483                     /* if the "OEM transfer mode" is enabled, read the minimum firmware version */
00484                     if (sotp_status.code == ERR_NONE && temp32 > 0)
00485                     {
00486                         uint64_t temp64 = 0;
00487                         sotp_status = arm_uc_read_sotp_uint(SOTP_TYPE_MIN_FW_VERSION, sizeof(uint64_t),
00488                                                                 &temp64);
00489                         if (sotp_status.code == ERR_NONE)
00490                         {
00491                             min_fw_version = temp64;
00492                             UC_HUB_TRACE("OEM transfer mode enabled, minimum FW version is %" PRIu64,
00493                                         min_fw_version);
00494                         }
00495                         else
00496                         {
00497                             UC_HUB_TRACE("Can't read minimum FW version, OEM transfer mode disabled");
00498                         }
00499                     }
00500 
00501                     /* only continue if timestamp is newer than active version */
00502                     if (fwinfo.timestamp > min_fw_version)
00503                     {
00504                         /* set new state */
00505                         new_state = ARM_UC_HUB_STATE_PREPARE_FIRMWARE_SETUP;
00506                     }
00507                     else
00508                     {
00509                         UC_HUB_ERR_MSG("version: %" PRIu64 " <= %" PRIu64,
00510                                     fwinfo.timestamp,
00511                                     min_fw_version);
00512 
00513                         /* signal warning through external handler */
00514                         ARM_UC_HUB_ErrorHandler(HUB_ERR_ROLLBACK_PROTECTION,
00515                                                 ARM_UC_HUB_STATE_CHECK_VERSION);
00516 
00517                         /* set new state */
00518                         new_state = ARM_UC_HUB_STATE_IDLE;
00519                     }
00520                 }
00521                 break;
00522 
00523             /*****************************************************************/
00524             /* Parse manifest                                                */
00525             /*****************************************************************/
00526             case ARM_UC_HUB_STATE_PREPARE_FIRMWARE_SETUP:
00527                 UC_HUB_TRACE("ARM_UC_HUB_STATE_PREPARE_FIRMWARE_SETUP");
00528 
00529                 /* store pointer to hash */
00530                 arm_uc_hub_firmware_config.hash = &fwinfo.hash;
00531 
00532                 /* parse the url string into a arm_uc_uri_t struct */
00533                 retval = arm_uc_str2uri(fwinfo.uri.ptr,
00534                                         fwinfo.uri.size,
00535                                         &uri);
00536 
00537                 /* URI-based errors are propagated to monitor */
00538                 if (retval.error != ERR_NONE)
00539                 {
00540                     /* make sure that the URI string is always 0-terminated */
00541                     fwinfo.uri.ptr[fwinfo.uri.size_max - 1] = '\0';
00542                     UC_HUB_ERR_MSG("Unable to parse URI string %s", fwinfo.uri.ptr);
00543 
00544                     /* signal warning through external handler */
00545                     ARM_UC_HUB_ErrorHandler(SOMA_ERR_INVALID_PARAMETER,
00546                                             ARM_UC_HUB_STATE_PREPARE_FIRMWARE_SETUP);
00547 
00548                     /* set new state */
00549                     new_state = ARM_UC_HUB_STATE_IDLE;
00550                     break;
00551                 }
00552 
00553                 /* store firmware size */
00554                 arm_uc_hub_firmware_config.package_size = fwinfo.size;
00555 
00556                 /* read cryptography mode to determine if firmware is encrypted */
00557                 switch(fwinfo.cipherMode)
00558                 {
00559                     case ARM_UC_MM_CIPHERMODE_NONE:
00560                         arm_uc_hub_firmware_config.mode = UCFM_MODE_NONE_SHA_256;
00561                         break;
00562 
00563                     case ARM_UC_MM_CIPHERMODE_PSK:
00564                         {
00565                             /* Get pre-shared-key from the Control Center */
00566                             /* TODO: this call should be asynchronous */
00567                             const uint8_t* arm_uc_pre_shared_key = NULL;
00568                             retval = ARM_UC_PreSharedKey_GetKey(&arm_uc_pre_shared_key, 128);
00569                             HANDLE_ERROR(retval, "Unable to get PSK");
00570 
00571                             /* Decode the firmware key to be used to decode the firmware */
00572                             UC_HUB_TRACE("Decoding firmware AES key...");
00573                             mbedtls_aes_context ctx;
00574                             mbedtls_aes_init(&ctx);
00575                             mbedtls_aes_setkey_dec(&ctx, arm_uc_pre_shared_key, 128);
00576                             mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_DECRYPT, fwinfo.psk.cipherKey.ptr, arm_uc_hub_plain_key.ptr);
00577 
00578                             arm_uc_hub_firmware_config.mode = UCFM_MODE_AES_CTR_128_SHA_256;
00579                             arm_uc_hub_firmware_config.key  = &arm_uc_hub_plain_key;
00580                             arm_uc_hub_firmware_config.iv   = &fwinfo.initVector;
00581                         }
00582                         break;
00583 
00584                     case ARM_UC_MM_CIPHERMODE_CERT_CIPHERKEY:
00585                     case ARM_UC_MM_CIPHERMODE_CERT_KEYTABLE:
00586                     default:
00587                         retval.code = MFST_ERR_CRYPTO_MODE;
00588                         HANDLE_ERROR(retval, "Unsupported AES Key distribution mode...");
00589                         break;
00590                 }
00591 
00592                 /* check if storage ID has been set */
00593                 if (fwinfo.strgId.size == 0 || fwinfo.strgId.ptr == NULL)
00594                 {
00595                     /* no storage ID set, use default value 0 */
00596                     arm_uc_hub_firmware_config.package_id = 0;
00597                 }
00598                 else
00599                 {
00600                     /* check if storage ID is "default" */
00601                     uint32_t location = arm_uc_strnstrn(fwinfo.strgId.ptr,
00602                                                         fwinfo.strgId.size,
00603                                                         (const uint8_t*) "default",
00604                                                         7);
00605 
00606                     if (location != UINT32_MAX)
00607                     {
00608                         arm_uc_hub_firmware_config.package_id = 0;
00609                     }
00610                     else
00611                     {
00612                         /* parse storage ID */
00613                         bool success = false;
00614                         arm_uc_hub_firmware_config.package_id =
00615                             arm_uc_str2uint32(fwinfo.strgId.ptr,
00616                                               fwinfo.strgId.size,
00617                                               &success);
00618                     }
00619                 }
00620 
00621 #if ARM_UC_HUB_TRACE_ENABLE
00622                 arm_uc_hub_debug_output();
00623 #endif
00624 
00625                 /* Set new state */
00626                 new_state = ARM_UC_HUB_STATE_REQUEST_DOWNLOAD_AUTHORIZATION;
00627                 break;
00628 
00629             /*****************************************************************/
00630             /* Download authorization                                        */
00631             /*****************************************************************/
00632             case ARM_UC_HUB_STATE_REQUEST_DOWNLOAD_AUTHORIZATION:
00633                 UC_HUB_TRACE("ARM_UC_HUB_STATE_REQUEST_DOWNLOAD_AUTHORIZATION");
00634 
00635                 /* Signal control center */
00636                 ARM_UC_ControlCenter_GetAuthorization(ARM_UCCC_REQUEST_DOWNLOAD);
00637 
00638                 /* Set new state */
00639                 new_state = ARM_UC_HUB_STATE_WAIT_FOR_DOWNLOAD_AUTHORIZATION;
00640                 break;
00641 
00642             case ARM_UC_HUB_STATE_WAIT_FOR_DOWNLOAD_AUTHORIZATION:
00643                 UC_HUB_TRACE("ARM_UC_HUB_STATE_WAIT_FOR_DOWNLOAD_AUTHORIZATION");
00644                 break;
00645 
00646             case ARM_UC_HUB_STATE_DOWNLOAD_AUTHORIZED:
00647                 UC_HUB_TRACE("ARM_UC_HUB_STATE_DOWNLOAD_AUTHORIZED");
00648 
00649                 /* Set new state */
00650                 new_state = ARM_UC_HUB_STATE_SETUP_FIRMWARE;
00651                 break;
00652 
00653             /*****************************************************************/
00654             /* Download firmware                                             */
00655             /*****************************************************************/
00656 
00657             /* The firmware is downloaded in fragments. While one fragment is
00658                written to storage, the next fragment is being downloaded.
00659 
00660                In the ARM_UC_HUB_STATE_FETCH_FIRST_FRAGMENT state, the first
00661                fragment is being downloaded. Once completed, the first fragment
00662                will be in the front_buffer and both the network stack and
00663                storage stack will be idle.
00664 
00665                In the ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD state, the front and
00666                back buffers are swapped. The front buffer is being used for
00667                downloading the next fragment while the back buffer is being
00668                written to storage.
00669 
00670                ARM_UC_FirmwareManager.Write and
00671                ARM_UC_SourceManager.GetFirmwareFragment will both finish
00672                asynchronously generating two events:
00673                ARM_UC_SM_EVENT_FIRMWARE and UCFM_EVENT_UPDATE_DONE.
00674 
00675                If the ARM_UC_SM_EVENT_FIRMWARE event is generated first, the
00676                system enters the ARM_UC_HUB_STATE_WAIT_FOR_STORAGE state.
00677                If the UCFM_EVENT_UPDATE_DONE event is generated first, the
00678                system enters the ARM_UC_HUB_STATE_WAIT_FOR_NETWORK state.
00679                The second generated event will move the system back to the
00680                ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD state.
00681 
00682                The download will stop once the fragment offset is larger than
00683                the firmware size written in the manifest. This moves the system
00684                to the ARM_UC_HUB_STATE_STORE_LAST_FRAGMENT state.
00685 
00686                Once the last fragment is written, the newly written firmware
00687                committed in the ARM_UC_HUB_STATE_FINALIZE_STORAGE state.
00688             */
00689             case ARM_UC_HUB_STATE_SETUP_FIRMWARE:
00690                 {
00691                     UC_HUB_TRACE("ARM_UC_HUB_STATE_SETUP_FIRMWARE");
00692 
00693                     /* store the firmware info in the manifest_firmware_info_t struct */
00694                     arm_uc_firmware_details_t arm_uc_hub_firmware_details = { 0 };
00695 
00696                     /* use manifest timestamp as firmware header version */
00697                     arm_uc_hub_firmware_details.version = fwinfo.timestamp;
00698                     arm_uc_hub_firmware_details.size    = fwinfo.size;
00699 
00700                     /* copy hash */
00701                     memcpy(arm_uc_hub_firmware_details.hash,
00702                         fwinfo.hash.ptr,
00703                         ARM_UC_SHA256_SIZE);
00704 
00705     #if 0
00706                     memcpy(arm_uc_hub_firmware_details.campaign,
00707                         configuration.campaign,
00708                         ARM_UC_GUID_SIZE);
00709     #endif
00710 
00711                     /* setup the firmware manager to get ready for firmware storage */
00712                     retval = ARM_UC_FirmwareManager.Prepare(&arm_uc_hub_firmware_config,
00713                                                             &arm_uc_hub_firmware_details,
00714                                                             &front_buffer);
00715                     HANDLE_ERROR(retval, "ARM_UC_FirmwareManager Setup failed")
00716                 }
00717                 break;
00718 
00719             case ARM_UC_HUB_STATE_FETCH_FIRST_FRAGMENT:
00720                 UC_HUB_TRACE("ARM_UC_HUB_STATE_FETCH_FIRST_FRAGMENT");
00721 
00722                 /* set state to downloading when trying to fetch the first chunk of firmware */
00723                 UC_HUB_TRACE("Setting Monitor State: ARM_UC_MONITOR_STATE_DOWNLOADING");
00724                 ARM_UC_ControlCenter_ReportState(ARM_UC_MONITOR_STATE_DOWNLOADING);
00725 
00726                 /* reset download values */
00727                 front_buffer.size = 0;
00728                 back_buffer.size = 0;
00729                 firmware_offset = 0;
00730 
00731                 /* Check firmware size before entering the download state machine.
00732                    An empty firmware is used for erasing a slot.
00733                 */
00734                 if (firmware_offset < fwinfo.size)
00735                 {
00736                     /* get first firmware fragment */
00737                     UC_HUB_TRACE("Getting next chunk at offset %" PRIu32,
00738                                  firmware_offset);
00739                     retval = ARM_UC_SourceManager.GetFirmwareFragment(&uri,
00740                                                                       &front_buffer,
00741                                                                       firmware_offset);
00742                     HANDLE_ERROR(retval, "GetFirmwareFragment failed")
00743                 }
00744                 else
00745                 {
00746                     /* No download is necessary, send next state to monitor service
00747                        and close storage slot.
00748                     */
00749                     UC_HUB_TRACE("Firmware empty, skip download phase and finalize");
00750                     UC_HUB_TRACE("Setting Monitor State: ARM_UC_MONITOR_STATE_DOWNLOADED");
00751                     ARM_UC_ControlCenter_ReportState(ARM_UC_MONITOR_STATE_DOWNLOADED);
00752                     new_state = ARM_UC_HUB_STATE_FINALIZE_STORAGE;
00753                 }
00754                 break;
00755 
00756             case ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD:
00757                 UC_HUB_TRACE("ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD");
00758 
00759                 /* swap the front and back buffers
00760                    the back buffer contained just downloaded firmware chunk
00761                    the front buffer can now be cleared and used to download new chunk
00762                 */
00763                 {
00764                     arm_uc_buffer_t temp_buf_ptr = front_buffer;
00765                     front_buffer = back_buffer;
00766                     back_buffer = temp_buf_ptr;
00767                 }
00768 
00769                 UC_HUB_TRACE("Fragment: %" PRIu32 " %" PRIu32, firmware_offset, back_buffer.size);
00770 
00771                 /* increase offset by the amount that we just downloaded */
00772                 firmware_offset += back_buffer.size;
00773 
00774                 /* store the downloaded chunk in the back buffer */
00775                 if (back_buffer.size > 0)
00776                 {
00777                     retval = ARM_UC_FirmwareManager.Write(&back_buffer);
00778                     HANDLE_ERROR(retval, "ARM_UC_FirmwareManager Update failed")
00779                 }
00780 
00781                 /* go fetch a new chunk using the front buffer if more are expected */
00782                 if (firmware_offset < fwinfo.size)
00783                 {
00784                     front_buffer.size = 0;
00785                     UC_HUB_TRACE("Getting next chunk at offset: %" PRIu32, firmware_offset);
00786                     retval = ARM_UC_SourceManager.GetFirmwareFragment(&uri, &front_buffer, firmware_offset);
00787                     HANDLE_ERROR(retval, "GetFirmwareFragment failed")
00788                 }
00789                 else
00790                 {
00791                     UC_HUB_TRACE("Store last fragment");
00792                     new_state = ARM_UC_HUB_STATE_STORE_LAST_FRAGMENT;
00793                 }
00794 
00795                 /* report progress */
00796                 ARM_UC_ControlCenter_ReportProgress(firmware_offset, fwinfo.size);
00797                 break;
00798 
00799             case ARM_UC_HUB_STATE_WAIT_FOR_STORAGE:
00800                 UC_HUB_TRACE("ARM_UC_HUB_STATE_WAIT_FOR_STORAGE");
00801                 break;
00802 
00803             case ARM_UC_HUB_STATE_WAIT_FOR_NETWORK:
00804                 UC_HUB_TRACE("ARM_UC_HUB_STATE_WAIT_FOR_NETWORK");
00805                 break;
00806 
00807             case ARM_UC_HUB_STATE_STORE_LAST_FRAGMENT:
00808                 UC_HUB_TRACE("ARM_UC_HUB_STATE_STORE_LAST_FRAGMENT");
00809 
00810                 /* set state to downloaded when the full size of the firmware
00811                    have been fetched.
00812                 */
00813                 UC_HUB_TRACE("Setting Monitor State: ARM_UC_MONITOR_STATE_DOWNLOADED");
00814                 ARM_UC_ControlCenter_ReportState(ARM_UC_MONITOR_STATE_DOWNLOADED);
00815                 break;
00816 
00817             case ARM_UC_HUB_STATE_FINALIZE_STORAGE:
00818                 UC_HUB_TRACE("ARM_UC_HUB_STATE_FINALIZE_STORAGE");
00819 
00820                 retval = ARM_UC_FirmwareManager.Finalize(&front_buffer, &back_buffer);
00821                 HANDLE_ERROR(retval, "ARM_UC_FirmwareManager Finalize failed")
00822                 break;
00823 
00824             /*****************************************************************/
00825             /* Install authorization                                         */
00826             /*****************************************************************/
00827             case ARM_UC_HUB_STATE_STORAGE_FINALIZED:
00828                 UC_HUB_TRACE("ARM_UC_HUB_STATE_STORAGE_FINALIZED");
00829 
00830                 /* Signal control center */
00831                 ARM_UC_ControlCenter_GetAuthorization(ARM_UCCC_REQUEST_INSTALL);
00832 
00833                 /* Set new state */
00834                 new_state = ARM_UC_HUB_STATE_WAIT_FOR_INSTALL_AUTHORIZATION;
00835                 break;
00836 
00837             case ARM_UC_HUB_STATE_WAIT_FOR_INSTALL_AUTHORIZATION:
00838                 UC_HUB_TRACE("ARM_UC_HUB_STATE_WAIT_FOR_INSTALL_AUTHORIZATION");
00839                 break;
00840 
00841             case ARM_UC_HUB_STATE_INSTALL_AUTHORIZED:
00842                 UC_HUB_TRACE("ARM_UC_HUB_STATE_INSTALL_AUTHORIZED");
00843 
00844                 UC_HUB_TRACE("Setting Monitor State: ARM_UC_MONITOR_STATE_UPDATING");
00845                 ARM_UC_ControlCenter_ReportState(ARM_UC_MONITOR_STATE_UPDATING);
00846 
00847 /* TODO: set timeout on ReportState before relying on callback to progress state machine */
00848                 new_state = ARM_UC_HUB_STATE_ACTIVATE_FIRMWARE;
00849                 break;
00850 
00851             case ARM_UC_HUB_STATE_ACTIVATE_FIRMWARE:
00852                 UC_HUB_TRACE("ARM_UC_HUB_STATE_ACTIVATE_FIRMWARE");
00853 
00854                 /* Firmware verification passes, activate firmware image.
00855                 */
00856                 ARM_UC_FirmwareManager.Activate(arm_uc_hub_firmware_config.package_id);
00857                 break;
00858 
00859             case ARM_UC_HUB_STATE_REBOOT:
00860                 UC_HUB_TRACE("ARM_UC_HUB_STATE_REBOOT");
00861 
00862                 /* Firmware activated, now reboot the system to apply
00863                    the new image.
00864                 */
00865                 pal_osReboot();
00866 
00867                 /* Reboot not implemented on this platform.
00868                    Report new firmware hash and continue operation.
00869                 */
00870                 new_state = ARM_UC_HUB_STATE_GET_ACTIVE_FIRMWARE_DETAILS;
00871                 break;
00872 
00873             /*****************************************************************/
00874             /* Error                                                         */
00875             /*****************************************************************/
00876             case ARM_UC_HUB_STATE_ERROR_FIRMWARE_MANAGER:
00877                 UC_HUB_TRACE("ARM_UC_HUB_STATE_ERROR_FIRMWARE_MANAGER");
00878                 new_state = ARM_UC_HUB_STATE_IDLE;
00879                 break;
00880 
00881             case ARM_UC_HUB_STATE_ERROR_MANIFEST_MANAGER:
00882                 UC_HUB_TRACE("ARM_UC_HUB_STATE_ERROR_MANIFEST_MANAGER");
00883                 new_state = ARM_UC_HUB_STATE_IDLE;
00884                 break;
00885 
00886             case ARM_UC_HUB_STATE_ERROR_SOURCE_MANAGER:
00887                 UC_HUB_TRACE("ARM_UC_HUB_STATE_ERROR_SOURCE_MANAGER");
00888                 new_state = ARM_UC_HUB_STATE_IDLE;
00889                 break;
00890 
00891             case ARM_UC_HUB_STATE_ERROR_CONTROL_CENTER:
00892                 UC_HUB_TRACE("ARM_UC_HUB_STATE_ERROR_CONTROL_CENTER");
00893                 new_state = ARM_UC_HUB_STATE_IDLE;
00894                 break;
00895 
00896             default:
00897                 new_state = ARM_UC_HUB_STATE_IDLE;
00898                 break;
00899         }
00900     }
00901     while (arm_uc_hub_state != new_state);
00902 }
00903