ble_dfu_bonded.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /**
  2. * Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. #include <stdint.h>
  41. #include <stdbool.h>
  42. #include <stddef.h>
  43. #include "nrf_dfu_ble_svci_bond_sharing.h"
  44. #include "nordic_common.h"
  45. #include "nrf_error.h"
  46. #include "ble_dfu.h"
  47. #include "nrf_log.h"
  48. #include "peer_manager.h"
  49. #include "gatts_cache_manager.h"
  50. #include "peer_id.h"
  51. #include "nrf_sdh_soc.h"
  52. #include "nrf_strerror.h"
  53. #if (NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS)
  54. void ble_dfu_buttonless_on_sys_evt(uint32_t, void * );
  55. uint32_t nrf_dfu_svci_vector_table_set(void);
  56. uint32_t nrf_dfu_svci_vector_table_unset(void);
  57. /**@brief Define function for async interface to set peer data. */
  58. NRF_SVCI_ASYNC_FUNC_DEFINE(NRF_DFU_SVCI_SET_PEER_DATA, nrf_dfu_set_peer_data, nrf_dfu_peer_data_t);
  59. // Register SoC observer for the Buttonless Secure DFU service
  60. NRF_SDH_SOC_OBSERVER(m_dfu_buttonless_soc_obs, BLE_DFU_SOC_OBSERVER_PRIO, ble_dfu_buttonless_on_sys_evt, NULL);
  61. ble_dfu_buttonless_t * mp_dfu;
  62. static nrf_dfu_peer_data_t m_peer_data;
  63. /**@brief Function for handling Peer Manager events.
  64. *
  65. * @param[in] p_evt Peer Manager event.
  66. */
  67. static void pm_evt_handler(pm_evt_t const * p_evt)
  68. {
  69. uint32_t ret;
  70. if (mp_dfu == NULL)
  71. {
  72. return;
  73. }
  74. // Only handle this when we are waiting to reset into DFU mode
  75. if (!mp_dfu->is_waiting_for_reset)
  76. {
  77. return;
  78. }
  79. switch(p_evt->evt_id)
  80. {
  81. case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
  82. if (p_evt->params.peer_data_update_succeeded.data_id == PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING)
  83. {
  84. mp_dfu->peers_count--;
  85. NRF_LOG_DEBUG("Updating Service Changed indication for peers, %d left", mp_dfu->peers_count);
  86. if (mp_dfu->peers_count == 0)
  87. {
  88. NRF_LOG_DEBUG("Finished updating Service Changed indication for peers");
  89. // We have updated Service Changed Indication for all devices.
  90. ret = ble_dfu_buttonless_bootloader_start_finalize();
  91. if (ret != NRF_SUCCESS)
  92. {
  93. mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
  94. }
  95. }
  96. }
  97. break;
  98. case PM_EVT_PEER_DATA_UPDATE_FAILED:
  99. // Failure to update data. Service Changed cannot be sent but DFU mode is still possible
  100. ret = ble_dfu_buttonless_bootloader_start_finalize();
  101. if (ret != NRF_SUCCESS)
  102. {
  103. mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
  104. }
  105. break;
  106. default:
  107. break;
  108. }
  109. }
  110. static uint32_t retrieve_peer_data(void)
  111. {
  112. ret_code_t ret;
  113. pm_peer_data_bonding_t bonding_data = {0};
  114. pm_peer_id_t peer_id;
  115. ret = pm_peer_id_get(mp_dfu->conn_handle, &peer_id);
  116. VERIFY_SUCCESS(ret);
  117. if (peer_id == PM_PEER_ID_INVALID)
  118. {
  119. return NRF_ERROR_FORBIDDEN;
  120. }
  121. ret = pm_peer_data_bonding_load(peer_id, &bonding_data);
  122. VERIFY_SUCCESS(ret);
  123. memcpy(&m_peer_data.ble_id, &bonding_data.peer_ble_id, sizeof(ble_gap_id_key_t));
  124. memcpy(&m_peer_data.enc_key, &bonding_data.own_ltk, sizeof(ble_gap_enc_key_t));
  125. uint16_t len = SYSTEM_SERVICE_ATT_SIZE;
  126. ret = sd_ble_gatts_sys_attr_get(mp_dfu->conn_handle,
  127. m_peer_data.sys_serv_attr,
  128. &len,
  129. BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
  130. NRF_LOG_DEBUG("system attribute table len: %d", len);
  131. return ret;
  132. }
  133. /**@brief Function for entering the bootloader.
  134. *
  135. * @details This starts forwarding peer data to the Secure DFU bootloader.
  136. */
  137. static uint32_t enter_bootloader(void)
  138. {
  139. uint32_t ret;
  140. NRF_LOG_INFO("Writing peer data to the bootloader...");
  141. if (mp_dfu->is_waiting_for_svci)
  142. {
  143. return ble_dfu_buttonless_resp_send(DFU_OP_ENTER_BOOTLOADER, DFU_RSP_BUSY);
  144. }
  145. // If retrieve_peer_data returns NRF_ERROR_FORBIDDEN, then the device was not bonded.
  146. ret = retrieve_peer_data();
  147. VERIFY_SUCCESS(ret);
  148. ret = nrf_dfu_set_peer_data(&m_peer_data);
  149. if (ret == NRF_SUCCESS)
  150. {
  151. // The request was accepted. Waiting for sys events to progress.
  152. mp_dfu->is_waiting_for_svci = true;
  153. }
  154. else if (ret == NRF_ERROR_FORBIDDEN)
  155. {
  156. NRF_LOG_ERROR("The bootloader has write protected its settings page. This prohibits setting the peer data. "\
  157. "The bootloader must be compiled with NRF_BL_SETTINGS_PAGE_PROTECT=0 to allow setting the peer data.");
  158. }
  159. return ret;
  160. }
  161. uint32_t ble_dfu_buttonless_backend_init(ble_dfu_buttonless_t * p_dfu)
  162. {
  163. VERIFY_PARAM_NOT_NULL(p_dfu);
  164. // Set the memory used by the backend.
  165. mp_dfu = p_dfu;
  166. // Initialize the Peer manager handler.
  167. return pm_register(pm_evt_handler);
  168. }
  169. uint32_t ble_dfu_buttonless_async_svci_init(void)
  170. {
  171. uint32_t ret;
  172. // Set the vector table base address to the bootloader.
  173. ret = nrf_dfu_svci_vector_table_set();
  174. NRF_LOG_DEBUG("nrf_dfu_svci_vector_table_set() -> %s",
  175. (ret == NRF_SUCCESS) ? "success" : nrf_strerror_get(ret));
  176. VERIFY_SUCCESS(ret);
  177. // Initialize the asynchronous SuperVisor interface to set peer data in Secure DFU bootloader.
  178. ret = nrf_dfu_set_peer_data_init();
  179. NRF_LOG_DEBUG("nrf_dfu_set_peer_data_init() -> %s",
  180. (ret == NRF_SUCCESS) ? "success" : nrf_strerror_get(ret));
  181. VERIFY_SUCCESS(ret);
  182. // Set the vector table base address back to main application.
  183. ret = nrf_dfu_svci_vector_table_unset();
  184. NRF_LOG_DEBUG("nrf_dfu_svci_vector_table_unset() -> %s",
  185. (ret == NRF_SUCCESS) ? "success" : nrf_strerror_get(ret));
  186. return ret;
  187. }
  188. void ble_dfu_buttonless_on_sys_evt(uint32_t sys_evt, void * p_context)
  189. {
  190. uint32_t ret;
  191. if (!nrf_dfu_set_peer_data_is_initialized())
  192. {
  193. return;
  194. }
  195. ret = nrf_dfu_set_peer_data_on_sys_evt(sys_evt);
  196. if (ret == NRF_ERROR_INVALID_STATE)
  197. {
  198. // The system event is not from an operation started by buttonless DFU.
  199. // No action is taken, and nothing is reported.
  200. }
  201. else if (ret == NRF_SUCCESS)
  202. {
  203. // Peer data was successfully forwarded to the Secure DFU bootloader.
  204. // Set the flag indicating that we are waiting for indication response
  205. // to activate the reset.
  206. mp_dfu->is_waiting_for_reset = true;
  207. mp_dfu->is_waiting_for_svci = false;
  208. // Report back the positive response
  209. ret = ble_dfu_buttonless_resp_send(DFU_OP_ENTER_BOOTLOADER, DFU_RSP_SUCCESS);
  210. if (ret != NRF_SUCCESS)
  211. {
  212. mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
  213. mp_dfu->is_waiting_for_reset = false;
  214. }
  215. }
  216. else
  217. {
  218. // Failed to set peer data. Report this.
  219. mp_dfu->is_waiting_for_reset = false;
  220. mp_dfu->is_waiting_for_svci = false;
  221. ret = ble_dfu_buttonless_resp_send(DFU_OP_ENTER_BOOTLOADER, DFU_RSP_BUSY);
  222. // Report the failure to send the response to the client
  223. if (ret != NRF_SUCCESS)
  224. {
  225. mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
  226. }
  227. // Report the failure to enter DFU mode
  228. mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
  229. }
  230. }
  231. uint32_t ble_dfu_buttonless_char_add(ble_dfu_buttonless_t * p_dfu)
  232. {
  233. ble_add_char_params_t add_char_params;
  234. memset(&add_char_params, 0, sizeof(add_char_params));
  235. add_char_params.uuid = BLE_DFU_BUTTONLESS_BONDED_CHAR_UUID;
  236. add_char_params.uuid_type = p_dfu->uuid_type;
  237. add_char_params.char_props.indicate = 1;
  238. add_char_params.char_props.write = 1;
  239. add_char_params.is_defered_write = true;
  240. add_char_params.is_var_len = true;
  241. add_char_params.max_len = BLE_GATT_ATT_MTU_DEFAULT;
  242. add_char_params.cccd_write_access = SEC_JUST_WORKS;
  243. add_char_params.write_access = SEC_JUST_WORKS;
  244. add_char_params.read_access = SEC_OPEN;
  245. return characteristic_add(p_dfu->service_handle, &add_char_params, &p_dfu->control_point_char);
  246. }
  247. void ble_dfu_buttonless_on_ctrl_pt_write(ble_gatts_evt_write_t const * p_evt_write)
  248. {
  249. uint32_t ret;
  250. ble_dfu_buttonless_rsp_code_t rsp_code = DFU_RSP_OPERATION_FAILED;
  251. // Start executing the control point write action
  252. switch (p_evt_write->data[0])
  253. {
  254. case DFU_OP_ENTER_BOOTLOADER:
  255. ret = enter_bootloader();
  256. if (ret == NRF_SUCCESS)
  257. {
  258. rsp_code = DFU_RSP_SUCCESS;
  259. }
  260. else if (ret == NRF_ERROR_BUSY)
  261. {
  262. rsp_code = DFU_RSP_BUSY;
  263. }
  264. else if (ret == NRF_ERROR_FORBIDDEN)
  265. {
  266. rsp_code = DFU_RSP_NOT_BONDED;
  267. }
  268. break;
  269. default:
  270. rsp_code = DFU_RSP_OP_CODE_NOT_SUPPORTED;
  271. break;
  272. }
  273. // Report back in case of error
  274. if (rsp_code != DFU_RSP_SUCCESS)
  275. {
  276. ret = ble_dfu_buttonless_resp_send((ble_dfu_buttonless_op_code_t)p_evt_write->data[0],
  277. rsp_code);
  278. if (ret != NRF_SUCCESS)
  279. {
  280. mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
  281. }
  282. // Report the error to the main application
  283. mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
  284. }
  285. }
  286. uint32_t ble_dfu_buttonless_bootloader_start_prepare(void)
  287. {
  288. NRF_LOG_DEBUG("In ble_dfu_buttonless_bootloader_start_prepare");
  289. // Indicate to main app that DFU mode is starting.
  290. // This event can be used to let the device take down any connection to
  291. // bonded devices.
  292. mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE);
  293. // Store the number of peers for which Peer Manager is expected to successfully write events.
  294. mp_dfu->peers_count = peer_id_n_ids();
  295. // Set local database changed to get Service Changed indication for all bonded peers
  296. // on next bootup (either because of a successful or aborted DFU).
  297. gscm_local_database_has_changed();
  298. return NRF_SUCCESS;
  299. }
  300. #endif // NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS