iot_context_manager.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. /**
  2. * Copyright (c) 2014 - 2019, 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 "nordic_common.h"
  41. #include "sdk_common.h"
  42. #include "sdk_config.h"
  43. #include "iot_common.h"
  44. #include "iot_context_manager.h"
  45. #if IOT_CONTEXT_MANAGER_CONFIG_LOG_ENABLED
  46. #define NRF_LOG_MODULE_NAME context_manager
  47. #define NRF_LOG_LEVEL IOT_CONTEXT_MANAGER_CONFIG_LOG_LEVEL
  48. #define NRF_LOG_INFO_COLOR IOT_CONTEXT_MANAGER_CONFIG_INFO_COLOR
  49. #define NRF_LOG_DEBUG_COLOR IOT_CONTEXT_MANAGER_CONFIG_DEBUG_COLOR
  50. #include "nrf_log.h"
  51. NRF_LOG_MODULE_REGISTER();
  52. #define CM_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
  53. #define CM_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
  54. #define CM_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
  55. #define CM_ENTRY() CM_TRC(">> %s", __func__)
  56. #define CM_EXIT() CM_TRC("<< %s", __func__)
  57. #else // IOT_CONTEXT_MANAGER_CONFIG_LOG_ENABLED
  58. #define CM_TRC(...) /**< Disables traces. */
  59. #define CM_DUMP(...) /**< Disables dumping of octet streams. */
  60. #define CM_ERR(...) /**< Disables error logs. */
  61. #define CM_ENTRY(...)
  62. #define CM_EXIT(...)
  63. #endif // IOT_CONTEXT_MANAGER_CONFIG_LOG_ENABLED
  64. /**@brief Parameter maximum values. */
  65. #define CID_VALUE_MAX 15
  66. #define PREFIX_LENGTH_VALUE_MAX 128
  67. /**
  68. * @defgroup api_param_check API Parameters check macros.
  69. *
  70. * @details Macros that verify parameters passed to the module in the APIs. These macros
  71. * could be mapped to nothing in final versions of code to save execution and size.
  72. * IOT_CONTEXT_MANAGER_DISABLE_API_PARAM_CHECK should be defined to disable these checks.
  73. *
  74. * @{
  75. */
  76. #if (IOT_CONTEXT_MANAGER_DISABLE_API_PARAM_CHECK == 0)
  77. /**@brief Macro to check is module is initialized before requesting one of the module procedures. */
  78. #define VERIFY_MODULE_IS_INITIALIZED() \
  79. if (m_initialization_state == false) \
  80. { \
  81. return (SDK_ERR_MODULE_NOT_INITIALIZED | IOT_CONTEXT_MANAGER_ERR_BASE); \
  82. }
  83. /**@brief Macro to check is module is initialized before requesting one of the module procedures. */
  84. #define VERIFY_MODULE_IS_INITIALIZED_NULL() \
  85. if (m_initialization_state == false) \
  86. { \
  87. return NULL; \
  88. }
  89. /**
  90. * @brief Verify NULL parameters are not passed to API by application.
  91. */
  92. #define NULL_PARAM_CHECK(PARAM) \
  93. if ((PARAM) == NULL) \
  94. { \
  95. return (NRF_ERROR_NULL | IOT_CONTEXT_MANAGER_ERR_BASE); \
  96. }
  97. /**
  98. * @brief Verify CID has valid value.
  99. */
  100. #define VERIFY_CID_VALUE(CID) \
  101. if (!((CID) <= CID_VALUE_MAX)) \
  102. { \
  103. return (NRF_ERROR_INVALID_PARAM | IOT_CONTEXT_MANAGER_ERR_BASE); \
  104. }
  105. /**
  106. * @brief Verify prefix length value.
  107. */
  108. #define VERIFY_PREFIX_LEN_VALUE(PREFIX_LEN) \
  109. if (!(PREFIX_LEN <= PREFIX_LENGTH_VALUE_MAX)) \
  110. { \
  111. return (NRF_ERROR_INVALID_PARAM | IOT_CONTEXT_MANAGER_ERR_BASE); \
  112. }
  113. #else // IOT_IOT_CONTEXT_MANAGER_DISABLE_API_PARAM_CHECK
  114. #define VERIFY_MODULE_IS_INITIALIZED()
  115. #define VERIFY_MODULE_IS_INITIALIZED_NULL()
  116. #define NULL_PARAM_CHECK(PARAM)
  117. #define VERIFY_CID_VALUE(CID)
  118. #define VERIFY_PREFIX_LEN_VALUE(PREFIX_LEN)
  119. #endif //IOT_CONTEXT_MANAGER_DISABLE_API_PARAM_CHECK
  120. /** @} */
  121. /**
  122. * @defgroup iot_context_manager_mutex_lock_unlock Module's Mutex Lock/Unlock Macros.
  123. *
  124. * @details Macros used to lock and unlock modules. Currently, SDK does not use mutexes but
  125. * framework is provided in case need arises to use an alternative architecture.
  126. * @{
  127. */
  128. #define CM_MUTEX_LOCK() SDK_MUTEX_LOCK(m_iot_context_manager_mutex) /**< Lock module using mutex */
  129. #define CM_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_iot_context_manager_mutex) /**< Unlock module using mutex */
  130. /** @} */
  131. /**@brief Context table, managing by IPv6 stack. */
  132. typedef struct
  133. {
  134. iot_interface_t * p_interface; /**< IoT interface pointer. */
  135. uint8_t context_count; /**< Number of valid contexts in the table. */
  136. iot_context_t contexts[IOT_CONTEXT_MANAGER_MAX_CONTEXTS]; /**< Array of valid contexts. */
  137. }iot_context_table_t;
  138. SDK_MUTEX_DEFINE(m_iot_context_manager_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
  139. static bool m_initialization_state = false; /**< Variable to maintain module initialization state. */
  140. static iot_context_table_t m_context_table[IOT_CONTEXT_MANAGER_MAX_TABLES]; /**< Array of contexts table managed by the module. */
  141. /**@brief Initializes context entry. */
  142. static void context_init(iot_context_t * p_context)
  143. {
  144. p_context->context_id = IPV6_CONTEXT_IDENTIFIER_NONE;
  145. p_context->prefix_len = 0;
  146. p_context->compression_flag = false;
  147. memset(p_context->prefix.u8, 0, IPV6_ADDR_SIZE);
  148. }
  149. /**@brief Initializes context table. */
  150. static void context_table_init(uint32_t table_id)
  151. {
  152. uint32_t index;
  153. for (index = 0; index < IOT_CONTEXT_MANAGER_MAX_CONTEXTS; index++)
  154. {
  155. context_init(&m_context_table[table_id].contexts[index]);
  156. m_context_table[table_id].context_count = 0;
  157. m_context_table[table_id].p_interface = NULL;
  158. }
  159. }
  160. /**@brief Initializes context table. */
  161. static uint32_t context_table_find(const iot_interface_t * p_interface)
  162. {
  163. uint32_t index;
  164. for (index = 0; index < IOT_CONTEXT_MANAGER_MAX_TABLES; index++)
  165. {
  166. if (m_context_table[index].p_interface == p_interface)
  167. {
  168. break;
  169. }
  170. }
  171. return index;
  172. }
  173. /**@brief Looks up context table for specific context identifier. */
  174. static uint32_t context_find_by_cid(uint32_t table_id,
  175. uint8_t context_id,
  176. iot_context_t ** pp_context)
  177. {
  178. uint32_t index;
  179. for (index = 0; index < IOT_CONTEXT_MANAGER_MAX_CONTEXTS; index++)
  180. {
  181. if (m_context_table[table_id].contexts[index].context_id == context_id)
  182. {
  183. *pp_context = &m_context_table[table_id].contexts[index];
  184. return NRF_SUCCESS;
  185. }
  186. }
  187. return (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
  188. }
  189. static uint32_t context_find_by_prefix(uint32_t table_id,
  190. const ipv6_addr_t * p_prefix,
  191. iot_context_t ** pp_context)
  192. {
  193. uint32_t index;
  194. uint32_t context_left;
  195. uint16_t context_cmp_len;
  196. iot_context_t * p_best_match = NULL;
  197. context_left = m_context_table[table_id].context_count;
  198. for (index = 0; index < IOT_CONTEXT_MANAGER_MAX_CONTEXTS && context_left; index++)
  199. {
  200. if (m_context_table[table_id].contexts[index].context_id != IPV6_CONTEXT_IDENTIFIER_NONE &&
  201. m_context_table[table_id].contexts[index].compression_flag == true)
  202. {
  203. if ((context_cmp_len = m_context_table[table_id].contexts[index].prefix_len) < 64)
  204. {
  205. context_cmp_len = 64;
  206. }
  207. // Check if address have matched in CID table.
  208. if (IPV6_ADDRESS_PREFIX_CMP(m_context_table[table_id].contexts[index].prefix.u8,
  209. p_prefix->u8,
  210. context_cmp_len))
  211. {
  212. if (p_best_match == NULL || p_best_match->prefix_len <
  213. m_context_table[table_id].contexts[index].prefix_len)
  214. {
  215. p_best_match = &m_context_table[table_id].contexts[index];
  216. }
  217. }
  218. // Decrease left context in table, to avoid too many checking.
  219. context_left--;
  220. }
  221. }
  222. if (p_best_match)
  223. {
  224. *pp_context = p_best_match;
  225. return NRF_SUCCESS;
  226. }
  227. return (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
  228. }
  229. /**@brief Looks up for first empty entry in the table. */
  230. static uint32_t context_find_free(uint32_t table_id, iot_context_t ** pp_context)
  231. {
  232. uint32_t index;
  233. for (index = 0; index < IOT_CONTEXT_MANAGER_MAX_CONTEXTS; index++)
  234. {
  235. if (m_context_table[table_id].contexts[index].context_id == IPV6_CONTEXT_IDENTIFIER_NONE)
  236. {
  237. *pp_context = &m_context_table[table_id].contexts[index];
  238. return NRF_SUCCESS;
  239. }
  240. }
  241. return (NRF_ERROR_NO_MEM | IOT_CONTEXT_MANAGER_ERR_BASE);
  242. }
  243. uint32_t iot_context_manager_init(void)
  244. {
  245. uint32_t index;
  246. CM_ENTRY();
  247. SDK_MUTEX_INIT(m_iot_context_manager_mutex);
  248. CM_MUTEX_LOCK();
  249. for (index = 0; index < IOT_CONTEXT_MANAGER_MAX_TABLES; index++)
  250. {
  251. context_table_init(index);
  252. }
  253. m_initialization_state = true;
  254. CM_MUTEX_UNLOCK();
  255. CM_EXIT();
  256. return NRF_SUCCESS;
  257. }
  258. uint32_t iot_context_manager_table_alloc(const iot_interface_t * p_interface)
  259. {
  260. VERIFY_MODULE_IS_INITIALIZED();
  261. NULL_PARAM_CHECK(p_interface);
  262. uint32_t err_code = NRF_SUCCESS;
  263. CM_ENTRY();
  264. CM_MUTEX_LOCK();
  265. const uint32_t table_id = context_table_find(NULL);
  266. if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
  267. {
  268. // Found a free context table and assign to it.
  269. CM_TRC("Assigned new context table.");
  270. m_context_table[table_id].p_interface = (iot_interface_t *)p_interface;
  271. }
  272. else
  273. {
  274. // No free context table found.
  275. CM_ERR("No context table found.");
  276. err_code = (NRF_ERROR_NO_MEM | IOT_CONTEXT_MANAGER_ERR_BASE);
  277. }
  278. CM_MUTEX_UNLOCK();
  279. CM_EXIT();
  280. return err_code;
  281. }
  282. uint32_t iot_context_manager_table_free(const iot_interface_t * p_interface)
  283. {
  284. VERIFY_MODULE_IS_INITIALIZED();
  285. NULL_PARAM_CHECK(p_interface);
  286. uint32_t err_code = NRF_SUCCESS;
  287. CM_ENTRY();
  288. SDK_MUTEX_INIT(m_iot_context_manager_mutex);
  289. CM_MUTEX_LOCK();
  290. const uint32_t table_id = context_table_find(p_interface);
  291. if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
  292. {
  293. // Clear context table.
  294. CM_TRC("Found context table assigned to interface.");
  295. context_table_init(table_id);
  296. }
  297. else
  298. {
  299. // No free context table found.
  300. CM_ERR("No context table found.");
  301. err_code = (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
  302. }
  303. CM_MUTEX_UNLOCK();
  304. CM_EXIT();
  305. return err_code;
  306. }
  307. uint32_t iot_context_manager_update(const iot_interface_t * p_interface,
  308. iot_context_t * p_context)
  309. {
  310. VERIFY_MODULE_IS_INITIALIZED();
  311. NULL_PARAM_CHECK(p_context);
  312. VERIFY_CID_VALUE(p_context->context_id);
  313. VERIFY_PREFIX_LEN_VALUE(p_context->prefix_len);
  314. uint32_t retval = NRF_SUCCESS;
  315. uint32_t err_code = NRF_SUCCESS;
  316. iot_context_t * p_internal_context;
  317. CM_ENTRY();
  318. CM_MUTEX_LOCK();
  319. const uint32_t table_id = context_table_find(p_interface);
  320. if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
  321. {
  322. // Try to find context in context table.
  323. retval = context_find_by_cid(table_id, p_context->context_id, &p_internal_context);
  324. if (retval != NRF_SUCCESS)
  325. {
  326. err_code = context_find_free(table_id, &p_internal_context);
  327. // Increase context count.
  328. if (err_code == NRF_SUCCESS)
  329. {
  330. m_context_table[table_id].context_count++;
  331. }
  332. }
  333. if (err_code == NRF_SUCCESS)
  334. {
  335. // Update context table, with parameters from application.
  336. p_internal_context->context_id = p_context->context_id;
  337. p_internal_context->prefix_len = p_context->prefix_len;
  338. p_internal_context->compression_flag = p_context->compression_flag;
  339. memset(p_internal_context->prefix.u8, 0, IPV6_ADDR_SIZE);
  340. IPV6_ADDRESS_PREFIX_SET(p_internal_context->prefix.u8, p_context->prefix.u8, p_context->prefix_len);
  341. }
  342. else
  343. {
  344. CM_ERR("No place in context table.");
  345. }
  346. }
  347. else
  348. {
  349. // No free context table found.
  350. CM_ERR("No context table found.");
  351. err_code = (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
  352. }
  353. CM_MUTEX_UNLOCK();
  354. CM_EXIT();
  355. return err_code;
  356. }
  357. uint32_t iot_context_manager_remove(const iot_interface_t * p_interface,
  358. iot_context_t * p_context)
  359. {
  360. VERIFY_MODULE_IS_INITIALIZED();
  361. NULL_PARAM_CHECK(p_interface);
  362. NULL_PARAM_CHECK(p_context);
  363. uint32_t err_code = NRF_SUCCESS;
  364. CM_ENTRY();
  365. CM_MUTEX_LOCK();
  366. const uint32_t table_id = context_table_find(p_interface);
  367. if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
  368. {
  369. if (p_context->context_id != IPV6_CONTEXT_IDENTIFIER_NONE)
  370. {
  371. m_context_table[table_id].context_count--;
  372. }
  373. // Reinit context entry.
  374. context_init(p_context);
  375. }
  376. else
  377. {
  378. // No free context table found.
  379. CM_ERR("No context table found.");
  380. err_code = (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
  381. }
  382. CM_MUTEX_UNLOCK();
  383. CM_EXIT();
  384. return err_code;
  385. }
  386. uint32_t iot_context_manager_get_by_addr(const iot_interface_t * p_interface,
  387. const ipv6_addr_t * p_addr,
  388. iot_context_t ** pp_context)
  389. {
  390. VERIFY_MODULE_IS_INITIALIZED();
  391. NULL_PARAM_CHECK(p_interface);
  392. NULL_PARAM_CHECK(p_addr);
  393. NULL_PARAM_CHECK(pp_context);
  394. uint32_t err_code;
  395. CM_ENTRY();
  396. CM_MUTEX_LOCK();
  397. const uint32_t table_id = context_table_find(p_interface);
  398. if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
  399. {
  400. err_code = context_find_by_prefix(table_id, p_addr, pp_context);
  401. }
  402. else
  403. {
  404. // No free context table found.
  405. CM_ERR("No context table found.");
  406. err_code = (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
  407. }
  408. CM_MUTEX_UNLOCK();
  409. CM_EXIT();
  410. return err_code;
  411. }
  412. uint32_t iot_context_manager_get_by_cid(const iot_interface_t * p_interface,
  413. uint8_t context_id,
  414. iot_context_t ** pp_context)
  415. {
  416. VERIFY_MODULE_IS_INITIALIZED();
  417. NULL_PARAM_CHECK(p_interface);
  418. NULL_PARAM_CHECK(pp_context);
  419. VERIFY_CID_VALUE(context_id);
  420. uint32_t err_code;
  421. CM_ENTRY();
  422. CM_MUTEX_LOCK();
  423. const uint32_t table_id = context_table_find(p_interface);
  424. if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
  425. {
  426. err_code = context_find_by_cid(table_id, context_id, pp_context);
  427. }
  428. else
  429. {
  430. // No free context table found.
  431. CM_TRC("No context table found.");
  432. err_code = (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
  433. }
  434. CM_MUTEX_UNLOCK();
  435. CM_EXIT();
  436. return err_code;
  437. }