es_slot.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /**
  2. * Copyright (c) 2016 - 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 <string.h>
  42. #include "es_slot.h"
  43. #include "es_flash.h"
  44. #include "es_security.h"
  45. #include "es_slot_reg.h"
  46. #include "es_tlm.h"
  47. #include "fds.h"
  48. static es_slot_reg_t m_reg; //!< Slot registry.
  49. static bool m_eid_loaded_from_flash; //!< Set to true if EID slot has been loaded from flash.
  50. #define RANGING_DATA_INDEX (1) //!< Index of ranging data within frames that contain ranging data.
  51. #define RANGING_DATA_LENGTH (1) //!< Length of ranging data.
  52. /**@brief Enforce legal slot number.
  53. *
  54. * @param[in] p_slot Pointer to the slot number variable to check.
  55. */
  56. static void slot_boundary_check(uint8_t * p_slot)
  57. {
  58. if (*p_slot > (APP_MAX_ADV_SLOTS - 1))
  59. {
  60. *p_slot = (APP_MAX_ADV_SLOTS - 1);
  61. }
  62. }
  63. /**@brief Function loading slot data from flash.
  64. *
  65. * @param[in] slot_no Slot number to be used.
  66. */
  67. static void load_slot_from_flash(uint8_t slot_no)
  68. {
  69. ret_code_t err_code;
  70. err_code = es_flash_access_slot_configs(slot_no, &m_reg.slots[slot_no], ES_FLASH_ACCESS_READ);
  71. if (err_code != FDS_ERR_NOT_FOUND)
  72. {
  73. APP_ERROR_CHECK(err_code);
  74. if (m_reg.slots[slot_no].adv_frame.type == ES_FRAME_TYPE_EID)
  75. {
  76. m_eid_loaded_from_flash = true;
  77. es_security_eid_slots_restore(slot_no,
  78. m_reg.slots[slot_no].k_scaler,
  79. m_reg.slots[slot_no].seconds,
  80. (const uint8_t *)m_reg.slots[slot_no].ik);
  81. }
  82. else
  83. {
  84. // If a non-EID slot has been loaded, update the state of m_reg immediately.
  85. es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, m_reg.slots[slot_no].adv_frame.type, true);
  86. }
  87. }
  88. }
  89. /**@brief Function for setting the ranging data field to be broadcast in the frame.
  90. *
  91. * @param[in] slot_no The slot index.
  92. * @param[in] tx_power The radio tx power to be calibrated to ranging data.
  93. */
  94. static void set_ranging_data_for_slot(uint8_t slot_no, nrf_ble_escs_radio_tx_pwr_t tx_power)
  95. {
  96. int8_t ranging_data_array[ESCS_NUM_OF_SUPPORTED_TX_POWER] = APP_CONFIG_CALIBRATED_RANGING_DATA;
  97. nrf_ble_escs_radio_tx_pwr_t supported_tx[ESCS_NUM_OF_SUPPORTED_TX_POWER] =
  98. ESCS_SUPPORTED_TX_POWER;
  99. int8_t ranging_data = 0;
  100. if (m_reg.slots[slot_no].adv_custom_tx_power)
  101. {
  102. ranging_data = m_reg.slots[slot_no].custom_tx_power;
  103. }
  104. else
  105. {
  106. for (uint32_t i = 0; i < ESCS_NUM_OF_SUPPORTED_TX_POWER; ++i)
  107. {
  108. if (supported_tx[i] >= tx_power)
  109. {
  110. ranging_data = ranging_data_array[i];
  111. break;
  112. }
  113. }
  114. }
  115. es_adv_frame_t * frame = &m_reg.slots[slot_no].adv_frame;
  116. switch (frame->type)
  117. {
  118. case ES_FRAME_TYPE_UID:
  119. {
  120. es_uid_frame_t * uid = &frame->frame.uid;
  121. uid->ranging_data = ranging_data;
  122. break;
  123. }
  124. case ES_FRAME_TYPE_URL:
  125. {
  126. es_url_frame_t * url = &frame->frame.url;
  127. url->ranging_data = ranging_data;
  128. break;
  129. }
  130. case ES_FRAME_TYPE_EID:
  131. {
  132. es_eid_frame_t * eid = &frame->frame.eid;
  133. eid->ranging_data = ranging_data;
  134. break;
  135. }
  136. case ES_FRAME_TYPE_TLM:
  137. APP_ERROR_CHECK(NRF_ERROR_INVALID_PARAM);
  138. break;
  139. }
  140. }
  141. /**@brief Function configuring a non-EID slot.
  142. *
  143. * @param[in] slot_no Slot number to be used.
  144. * @param[in] length Length of write operation.
  145. * @param[in] p_frame_data Pointer to written data.
  146. */
  147. static void configure_slot(uint8_t slot_no, uint8_t length, uint8_t const * p_frame_data)
  148. {
  149. // If a TLM slot is being configured and there already exists a TLM.
  150. if ((es_frame_type_t)p_frame_data[0] == ES_FRAME_TYPE_TLM && m_reg.tlm_configured)
  151. {
  152. return; // Silently ignore any attempts to create more than one TLM slot as there is no point.
  153. }
  154. es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, (es_frame_type_t)p_frame_data[0], false);
  155. // For convenience, frame_type is stored in two places, set both.
  156. m_reg.slots[slot_no].adv_frame.type = (es_frame_type_t)p_frame_data[0];
  157. memcpy(&m_reg.slots[slot_no].adv_frame.frame, &m_reg.slots[slot_no].adv_frame.type, 1);
  158. uint8_t * p_data_after_ranging_data = ((uint8_t *)(&m_reg.slots[slot_no].adv_frame.frame) +
  159. RANGING_DATA_INDEX + RANGING_DATA_LENGTH);
  160. switch (m_reg.slots[slot_no].adv_frame.type)
  161. {
  162. case ES_FRAME_TYPE_UID:
  163. // Fall through.
  164. case ES_FRAME_TYPE_URL:
  165. memcpy(p_data_after_ranging_data, &p_frame_data[1], length - 1);
  166. set_ranging_data_for_slot(slot_no, APP_CFG_DEFAULT_RADIO_TX_POWER);
  167. m_reg.slots[slot_no].adv_frame.length = length + 1; // + 1 for ranging data
  168. break;
  169. case ES_FRAME_TYPE_TLM:
  170. es_tlm_tlm_get(&m_reg.slots[slot_no].adv_frame.frame.tlm);
  171. m_reg.slots[slot_no].adv_frame.length = ES_TLM_LENGTH;
  172. break;
  173. default:
  174. break;
  175. }
  176. }
  177. /**@brief Function configuring an EID slot.
  178. *
  179. * @param[in] slot_no Slot number to be used.
  180. * @param[in] length Length of write operation.
  181. * @param[in] p_frame_data Pointer to written data.
  182. */
  183. static void configure_eid_slot(uint8_t slot_no, uint8_t length, uint8_t const * p_frame_data)
  184. {
  185. // Do not update slot count, as this will be done when in the callback invoked when the EID data
  186. // is ready.
  187. // As it takes a while to do the calculation, temporarily remove the slot being overwritten.
  188. // The slot will be re-added in the callback invoked when the EID data is ready.
  189. (void)es_slot_reg_clear_slot(&m_reg, slot_no);
  190. if (p_frame_data[0] != ES_FRAME_TYPE_EID)
  191. {
  192. APP_ERROR_CHECK(NRF_ERROR_INVALID_STATE);
  193. }
  194. if (length == ESCS_EID_WRITE_ECDH_LENGTH)
  195. {
  196. es_security_client_pub_ecdh_receive(slot_no,
  197. (uint8_t*)&p_frame_data[ESCS_EID_WRITE_PUB_KEY_INDEX],
  198. p_frame_data[ESCS_EID_WRITE_ECDH_LENGTH -1]);
  199. }
  200. else if (length == ESCS_EID_WRITE_IDK_LENGTH)
  201. {
  202. es_security_shared_ik_receive(slot_no,
  203. (uint8_t*)&p_frame_data[ESCS_EID_WRITE_ENC_ID_KEY_INDEX],
  204. p_frame_data[ESCS_EID_WRITE_IDK_LENGTH - 1]);
  205. }
  206. else
  207. {
  208. // Invalid length being written.
  209. APP_ERROR_CHECK(NRF_ERROR_INVALID_PARAM);
  210. }
  211. }
  212. ret_code_t es_slot_write_to_flash(uint8_t slot_no)
  213. {
  214. if (m_reg.slots[slot_no].configured)
  215. {
  216. // If its an EID, we need to store some metadata in order to re-initialize the EID.
  217. if (m_reg.slots[slot_no].adv_frame.type == ES_FRAME_TYPE_EID)
  218. {
  219. m_reg.slots[slot_no].seconds = es_security_clock_get(slot_no);
  220. m_reg.slots[slot_no].k_scaler = es_security_scaler_get(slot_no);
  221. es_security_plain_eid_id_key_get(slot_no, m_reg.slots[slot_no].ik);
  222. }
  223. return es_flash_access_slot_configs(slot_no, &m_reg.slots[slot_no], ES_FLASH_ACCESS_WRITE);
  224. }
  225. else
  226. {
  227. return es_flash_access_slot_configs(slot_no, NULL, ES_FLASH_ACCESS_CLEAR);
  228. }
  229. }
  230. void es_slot_radio_tx_pwr_set(uint8_t slot_no, nrf_ble_escs_radio_tx_pwr_t radio_tx_pwr)
  231. {
  232. slot_boundary_check(&slot_no);
  233. m_reg.slots[slot_no].radio_tx_pwr = radio_tx_pwr;
  234. if (!m_reg.slots[slot_no].adv_custom_tx_power) // Only update TX power in ADV if custom TX power is not set
  235. {
  236. set_ranging_data_for_slot(slot_no, radio_tx_pwr);
  237. }
  238. }
  239. void es_slot_set_adv_custom_tx_power(uint8_t slot_no, nrf_ble_escs_adv_tx_pwr_t tx_pwr)
  240. {
  241. slot_boundary_check(&slot_no);
  242. m_reg.slots[slot_no].adv_custom_tx_power = true;
  243. m_reg.slots[slot_no].custom_tx_power = tx_pwr;
  244. set_ranging_data_for_slot(slot_no, tx_pwr);
  245. }
  246. void es_slot_on_write(uint8_t slot_no, uint8_t length, uint8_t const * p_frame_data)
  247. {
  248. slot_boundary_check(&slot_no);
  249. if (p_frame_data == NULL)
  250. {
  251. APP_ERROR_CHECK(NRF_ERROR_NULL);
  252. }
  253. // Cleared
  254. if (length == 0 || (length == 1 && p_frame_data[0] == 0))
  255. {
  256. (void)es_slot_reg_clear_slot(&m_reg, slot_no);
  257. }
  258. // EID slot being configured
  259. else if (p_frame_data[0] == ES_FRAME_TYPE_EID &&
  260. (length == ESCS_EID_WRITE_ECDH_LENGTH || length == ESCS_EID_WRITE_IDK_LENGTH))
  261. {
  262. if (m_reg.slots[slot_no].configured)
  263. (void)es_slot_reg_clear_slot(&m_reg, slot_no);
  264. configure_eid_slot(slot_no, length, p_frame_data);
  265. }
  266. // Non-EID slot configured.
  267. else
  268. {
  269. if (m_reg.slots[slot_no].configured)
  270. (void)es_slot_reg_clear_slot(&m_reg, slot_no);
  271. configure_slot(slot_no, length, p_frame_data);
  272. }
  273. }
  274. void es_slot_encrypted_eid_id_key_set(uint8_t slot_no, nrf_ble_escs_eid_id_key_t * p_eid_id_key)
  275. {
  276. slot_boundary_check(&slot_no);
  277. if (p_eid_id_key != NULL)
  278. {
  279. memcpy(&(m_reg.slots[slot_no].encrypted_eid_id_key), p_eid_id_key,
  280. sizeof(nrf_ble_escs_eid_id_key_t));
  281. }
  282. }
  283. void es_slot_eid_ready(uint8_t slot_no)
  284. {
  285. m_reg.slots[slot_no].adv_frame.type = ES_FRAME_TYPE_EID;
  286. m_reg.slots[slot_no].adv_frame.length = ES_EID_LENGTH;
  287. es_security_eid_get(slot_no, (uint8_t *)m_reg.slots[slot_no].adv_frame.frame.eid.eid);
  288. m_reg.slots[slot_no].adv_frame.frame.eid.frame_type = ES_FRAME_TYPE_EID;
  289. set_ranging_data_for_slot(slot_no, m_reg.slots[slot_no].radio_tx_pwr);
  290. if (m_eid_loaded_from_flash)
  291. {
  292. es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, ES_FRAME_TYPE_EID, true);
  293. m_eid_loaded_from_flash = false;
  294. }
  295. else
  296. {
  297. es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, ES_FRAME_TYPE_EID, false);
  298. }
  299. }
  300. static bool slot_is_eid(uint8_t eid_slot_no)
  301. {
  302. for (uint32_t i = 0; i < m_reg.num_configured_eid_slots; ++i)
  303. {
  304. if (m_reg.eid_slots_configured[i] == eid_slot_no)
  305. {
  306. return true;
  307. }
  308. }
  309. return false;
  310. }
  311. void es_slot_tlm_update(void)
  312. {
  313. if (m_reg.tlm_configured)
  314. {
  315. es_tlm_tlm_get(&m_reg.slots[m_reg.tlm_slot].adv_frame.frame.tlm);
  316. }
  317. }
  318. void es_slot_etlm_update(uint8_t eid_slot_no)
  319. {
  320. es_tlm_frame_t tlm;
  321. es_etlm_frame_t etlm;
  322. // Ignore the request if eTLM is not required or slot no does not correspond to an EID slot.
  323. if (!es_slot_reg_etlm_required(&m_reg) || !slot_is_eid(eid_slot_no))
  324. {
  325. return;
  326. }
  327. es_tlm_tlm_get(&tlm);
  328. es_security_tlm_to_etlm(eid_slot_no, &tlm, &etlm);
  329. memcpy(&m_reg.slots[m_reg.tlm_slot].adv_frame.frame.etlm, &etlm, sizeof(es_etlm_frame_t));
  330. m_reg.slots[m_reg.tlm_slot].adv_frame.length = sizeof(es_etlm_frame_t);
  331. }
  332. const es_slot_reg_t * es_slot_get_registry(void)
  333. {
  334. return (const es_slot_reg_t *)&m_reg;
  335. }
  336. void es_slots_init(const es_slot_t * p_default_slot)
  337. {
  338. ret_code_t err_code;
  339. es_flash_flags_t flash_flags = {{0}};
  340. es_slot_reg_init(&m_reg);
  341. m_eid_loaded_from_flash = false;
  342. // Read the flash flags to see if there are any previously stored slot configs
  343. err_code = es_flash_access_flags(&flash_flags, ES_FLASH_ACCESS_READ);
  344. if (err_code == FDS_ERR_NOT_FOUND)
  345. {
  346. // Factory reset or initial boot, load default data
  347. memcpy(&m_reg.slots[0], p_default_slot, sizeof(*p_default_slot));
  348. es_slot_reg_update_slot_list_info_on_add(&m_reg, 0, p_default_slot->adv_frame.type, true);
  349. }
  350. else
  351. {
  352. APP_ERROR_CHECK(err_code);
  353. for (uint32_t i = 0; i < APP_MAX_ADV_SLOTS; ++i)
  354. {
  355. if (!flash_flags.slot_is_empty[i])
  356. {
  357. load_slot_from_flash(i);
  358. }
  359. }
  360. }
  361. }