lwm2m.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885
  1. /**
  2. * Copyright (c) 2015 - 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 <string.h>
  41. #include <stdlib.h>
  42. #include <stdio.h>
  43. #include <ctype.h>
  44. #include "lwm2m_api.h"
  45. #include "lwm2m_register.h"
  46. #include "lwm2m_bootstrap.h"
  47. #include "sdk_os.h"
  48. #include "lwm2m.h"
  49. #include "sdk_config.h"
  50. #if LWM2M_CONFIG_LOG_ENABLED
  51. #define NRF_LOG_MODULE_NAME lwm2m
  52. #define NRF_LOG_LEVEL LWM2M_CONFIG_LOG_LEVEL
  53. #define NRF_LOG_INFO_COLOR LWM2M_CONFIG_INFO_COLOR
  54. #define NRF_LOG_DEBUG_COLOR LWM2M_CONFIG_DEBUG_COLOR
  55. #include "nrf_log.h"
  56. NRF_LOG_MODULE_REGISTER();
  57. #define LWM2M_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
  58. #define LWM2M_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
  59. #define LWM2M_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
  60. #define LWM2M_ENTRY() LWM2M_TRC(">> %s", __func__)
  61. #define LWM2M_EXIT() LWM2M_TRC("<< %s", __func__)
  62. #else // LWM2M_CONFIG_LOG_ENABLED
  63. #define LWM2M_TRC(...) /**< Disables traces. */
  64. #define LWM2M_DUMP(...) /**< Disables dumping of octet streams. */
  65. #define LWM2M_ERR(...) /**< Disables error logs. */
  66. #define LWM2M_ENTRY(...)
  67. #define LWM2M_EXIT(...)
  68. #endif // LWM2M_CONFIG_LOG_ENABLED
  69. #if (LWM2M_CONFIG_LOG_ENABLED != 0)
  70. static uint8_t op_desc_idx_lookup(uint8_t bitmask)
  71. {
  72. for (uint8_t i = 0; i < 8; i++)
  73. {
  74. if ((bitmask > i) == 0x1)
  75. {
  76. return i;
  77. }
  78. }
  79. // If no bits where set in the bitmask.
  80. return 0;
  81. }
  82. static const char m_operation_desc[8][9] = {
  83. "NONE",
  84. "READ",
  85. "WRITE",
  86. "EXECUTE",
  87. "DELETE",
  88. "CREATE",
  89. "DISCOVER",
  90. "OBSERVE"
  91. };
  92. #endif
  93. SDK_MUTEX_DEFINE(m_lwm2m_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
  94. static lwm2m_object_prototype_t * m_objects[LWM2M_COAP_HANDLER_MAX_OBJECTS];
  95. static lwm2m_instance_prototype_t * m_instances[LWM2M_COAP_HANDLER_MAX_INSTANCES];
  96. static uint16_t m_num_objects;
  97. static uint16_t m_num_instances;
  98. static void coap_error_handler(uint32_t error_code, coap_message_t * p_message)
  99. {
  100. LWM2M_ERR("[CoAP]: Unhandled coap message recieved. Error code: %lu", error_code);
  101. }
  102. static void internal_coap_handler_init(void)
  103. {
  104. memset(m_objects, 0, sizeof(m_objects));
  105. memset(m_instances, 0, sizeof(m_instances));
  106. m_num_objects = 0;
  107. m_num_instances = 0;
  108. }
  109. static bool numbers_only(const char * p_str, uint16_t str_len)
  110. {
  111. for (uint16_t i = 0; i < str_len; i++)
  112. {
  113. if (isdigit(p_str[i]) == 0)
  114. {
  115. return false;
  116. }
  117. }
  118. return true;
  119. }
  120. static uint32_t instance_resolve(lwm2m_instance_prototype_t ** p_instance,
  121. uint16_t object_id,
  122. uint16_t instance_id)
  123. {
  124. for (int i = 0; i < m_num_instances; ++i)
  125. {
  126. if (m_instances[i]->object_id == object_id &&
  127. m_instances[i]->instance_id == instance_id)
  128. {
  129. if (m_instances[i]->callback == NULL)
  130. {
  131. return NRF_ERROR_NULL;
  132. }
  133. *p_instance = m_instances[i];
  134. return NRF_SUCCESS;
  135. }
  136. }
  137. return NRF_ERROR_NOT_FOUND;
  138. }
  139. static uint32_t object_resolve(lwm2m_object_prototype_t ** p_instance,
  140. uint16_t object_id)
  141. {
  142. for (int i = 0; i < m_num_objects; ++i)
  143. {
  144. if (m_objects[i]->object_id == object_id)
  145. {
  146. if (m_objects[i]->callback == NULL)
  147. {
  148. return NRF_ERROR_NULL;
  149. }
  150. *p_instance = m_objects[i];
  151. return NRF_SUCCESS;
  152. }
  153. }
  154. return NRF_ERROR_NOT_FOUND;
  155. }
  156. static uint32_t op_code_resolve(lwm2m_instance_prototype_t * p_instance,
  157. uint16_t resource_id,
  158. uint8_t * operation)
  159. {
  160. uint8_t * operations = (uint8_t *) p_instance + p_instance->operations_offset;
  161. uint16_t * operations_ids = (uint16_t *)((uint8_t *) p_instance +
  162. p_instance->resource_ids_offset);
  163. for (int j = 0; j < p_instance->num_resources; ++j)
  164. {
  165. if (operations_ids[j] == resource_id)
  166. {
  167. *operation = operations[j];
  168. return NRF_SUCCESS;
  169. }
  170. }
  171. return NRF_ERROR_NOT_FOUND;
  172. }
  173. static uint32_t internal_request_handle(coap_message_t * p_request,
  174. uint16_t * p_path,
  175. uint8_t path_len)
  176. {
  177. uint32_t err_code;
  178. uint8_t operation = LWM2M_OPERATION_CODE_NONE;
  179. uint32_t content_type = 0;
  180. err_code = coap_message_ct_mask_get(p_request, &content_type);
  181. if (err_code != NRF_SUCCESS)
  182. {
  183. return err_code;
  184. }
  185. /**
  186. * TODO: the methods should check if we have read / write / execute rights
  187. * through ACL and resource operations
  188. */
  189. switch (p_request->header.code)
  190. {
  191. case COAP_CODE_GET:
  192. {
  193. LWM2M_TRC("[CoAP]: CoAP GET request");
  194. if (content_type == COAP_CT_APP_LINK_FORMAT) // Discover
  195. {
  196. operation = LWM2M_OPERATION_CODE_DISCOVER;
  197. }
  198. else // Read
  199. {
  200. operation = LWM2M_OPERATION_CODE_READ;
  201. }
  202. break;
  203. }
  204. case COAP_CODE_PUT:
  205. {
  206. operation = LWM2M_OPERATION_CODE_WRITE;
  207. break;
  208. }
  209. case COAP_CODE_POST:
  210. {
  211. operation = LWM2M_OPERATION_CODE_WRITE;
  212. break;
  213. }
  214. case COAP_CODE_DELETE:
  215. {
  216. operation = LWM2M_OPERATION_CODE_DELETE;
  217. break;
  218. }
  219. default:
  220. break; // Maybe send response with unsupported method not allowed?
  221. }
  222. err_code = NRF_ERROR_NOT_FOUND;
  223. switch (path_len)
  224. {
  225. case 0:
  226. {
  227. if (operation == LWM2M_OPERATION_CODE_DELETE)
  228. {
  229. LWM2M_TRC("[CoAP]: >> %s root /",
  230. m_operation_desc[op_desc_idx_lookup(operation)]);
  231. LWM2M_MUTEX_UNLOCK();
  232. err_code = lwm2m_coap_handler_root(LWM2M_OPERATION_CODE_DELETE, p_request);
  233. LWM2M_MUTEX_LOCK();
  234. LWM2M_TRC("[CoAP]: << %s root /",
  235. m_operation_desc[op_desc_idx_lookup(operation)]);
  236. }
  237. break;
  238. }
  239. case 1:
  240. {
  241. LWM2M_TRC("[CoAP]: >> %s object /%u/",
  242. m_operation_desc[op_desc_idx_lookup(operation)],
  243. p_path[0]);
  244. lwm2m_object_prototype_t * p_object;
  245. err_code = object_resolve(&p_object, p_path[0]);
  246. if (err_code != NRF_SUCCESS)
  247. {
  248. break;
  249. }
  250. LWM2M_MUTEX_UNLOCK();
  251. err_code = p_object->callback(p_object, LWM2M_INVALID_INSTANCE, operation, p_request);
  252. LWM2M_MUTEX_LOCK();
  253. LWM2M_TRC("[CoAP]: << %s object /%u/, result: %s",
  254. m_operation_desc[op_desc_idx_lookup(operation)],
  255. p_path[0],
  256. (err_code == NRF_SUCCESS) ? "SUCCESS" : "NOT_FOUND");
  257. break;
  258. }
  259. case 2:
  260. {
  261. LWM2M_TRC("[CoAP]: >> %s instance /%u/%u/",
  262. m_operation_desc[op_desc_idx_lookup(operation)],
  263. p_path[0],
  264. p_path[1]);
  265. lwm2m_instance_prototype_t * p_instance;
  266. err_code = instance_resolve(&p_instance, p_path[0], p_path[1]);
  267. if (err_code == NRF_SUCCESS)
  268. {
  269. LWM2M_MUTEX_UNLOCK();
  270. err_code = p_instance->callback(p_instance, LWM2M_INVALID_RESOURCE, operation, p_request);
  271. LWM2M_MUTEX_LOCK();
  272. LWM2M_TRC("[CoAP]: << %s instance /%u/%u/, result: %s",
  273. m_operation_desc[op_desc_idx_lookup(operation)],
  274. p_path[0],
  275. p_path[1],
  276. (err_code == NRF_SUCCESS) ? "SUCCESS" : "NOT_FOUND");
  277. break;
  278. }
  279. // Bootstrap can write to non-existing instances
  280. if (err_code == NRF_ERROR_NOT_FOUND &&
  281. operation == LWM2M_OPERATION_CODE_WRITE &&
  282. p_request->header.code == COAP_CODE_PUT)
  283. {
  284. LWM2M_TRC("[CoAP]: >> %s object /%u/%u/",
  285. m_operation_desc[op_desc_idx_lookup(operation)],
  286. p_path[0],
  287. p_path[1]);
  288. lwm2m_object_prototype_t * p_object;
  289. err_code = object_resolve(&p_object, p_path[0]);
  290. if (err_code != NRF_SUCCESS)
  291. {
  292. break;
  293. }
  294. LWM2M_MUTEX_UNLOCK();
  295. err_code = p_object->callback(p_object, p_path[1], operation, p_request);
  296. LWM2M_MUTEX_LOCK();
  297. LWM2M_TRC("[CoAP]: << %s object /%u/%u/, result: %s",
  298. m_operation_desc[op_desc_idx_lookup(operation)],
  299. p_path[0],
  300. p_path[1],
  301. (err_code == NRF_SUCCESS) ? "SUCCESS" : "NOT_FOUND");
  302. }
  303. if (err_code == NRF_ERROR_NOT_FOUND &&
  304. operation == LWM2M_OPERATION_CODE_WRITE &&
  305. p_request->header.code == COAP_CODE_POST)
  306. {
  307. LWM2M_TRC("[CoAP]: >> CREATE object /%u/%u/",
  308. p_path[0],
  309. p_path[1]);
  310. lwm2m_object_prototype_t * p_object;
  311. err_code = object_resolve(&p_object, p_path[0]);
  312. if (err_code != NRF_SUCCESS)
  313. {
  314. break;
  315. }
  316. LWM2M_MUTEX_UNLOCK();
  317. err_code = p_object->callback(p_object, p_path[1], LWM2M_OPERATION_CODE_CREATE, p_request);
  318. LWM2M_MUTEX_LOCK();
  319. LWM2M_TRC("[CoAP]: << CREATE object /%u/%u/, result: %s",
  320. p_path[0],
  321. p_path[1],
  322. (err_code == NRF_SUCCESS) ? "SUCCESS" : "NOT_FOUND");
  323. break;
  324. }
  325. break;
  326. }
  327. case 3:
  328. {
  329. if (operation == LWM2M_OPERATION_CODE_DELETE)
  330. {
  331. // Deleting resources within an instance not allowed.
  332. break;
  333. }
  334. if (p_request->header.code == COAP_CODE_POST)
  335. {
  336. for (int i = 0; i < m_num_instances; ++i)
  337. {
  338. if ((m_instances[i]->object_id == p_path[0]) &&
  339. (m_instances[i]->instance_id == p_path[1]))
  340. {
  341. if (m_instances[i]->callback == NULL)
  342. {
  343. err_code = NRF_ERROR_NULL;
  344. break;
  345. }
  346. uint8_t resource_operation = 0;
  347. err_code = op_code_resolve(m_instances[i], p_path[2], &resource_operation);
  348. if (err_code != NRF_SUCCESS)
  349. break;
  350. if ((resource_operation & LWM2M_OPERATION_CODE_EXECUTE) > 0)
  351. {
  352. operation = LWM2M_OPERATION_CODE_EXECUTE;
  353. }
  354. if ((resource_operation & LWM2M_OPERATION_CODE_WRITE) > 0)
  355. {
  356. operation = LWM2M_OPERATION_CODE_WRITE;
  357. }
  358. LWM2M_TRC("[CoAP]: >> %s instance /%u/%u/%u/",
  359. m_operation_desc[op_desc_idx_lookup(operation)],
  360. m_instances[i]->object_id,
  361. m_instances[i]->instance_id,
  362. p_path[2]);
  363. LWM2M_MUTEX_UNLOCK();
  364. (void)m_instances[i]->callback(m_instances[i],
  365. p_path[2],
  366. operation,
  367. p_request);
  368. LWM2M_MUTEX_LOCK();
  369. err_code = NRF_SUCCESS;
  370. LWM2M_TRC("[CoAP]: << %s instance /%u/%u/%u/",
  371. m_operation_desc[op_desc_idx_lookup(operation)],
  372. m_instances[i]->object_id,
  373. m_instances[i]->instance_id,
  374. p_path[2]);
  375. break;
  376. }
  377. }
  378. }
  379. else
  380. {
  381. LWM2M_TRC("[CoAP]: >> %s instance /%u/%u/%u/",
  382. m_operation_desc[op_desc_idx_lookup(operation)],
  383. p_path[0],
  384. p_path[1],
  385. p_path[2]);
  386. lwm2m_instance_prototype_t * p_instance;
  387. err_code = instance_resolve(&p_instance, p_path[0], p_path[1]);
  388. if (err_code != NRF_SUCCESS)
  389. {
  390. break;
  391. }
  392. LWM2M_MUTEX_UNLOCK();
  393. err_code = p_instance->callback(p_instance, p_path[2], operation, p_request);
  394. LWM2M_MUTEX_LOCK();
  395. LWM2M_TRC("[CoAP]: << %s instance /%u/%u/%u/, result: %s",
  396. m_operation_desc[op_desc_idx_lookup(operation)],
  397. p_path[0],
  398. p_path[1],
  399. p_path[2],
  400. (err_code == NRF_SUCCESS) ? "SUCCESS" : "NOT_FOUND");
  401. }
  402. break;
  403. }
  404. default:
  405. break;
  406. }
  407. return err_code;
  408. }
  409. static uint32_t lwm2m_coap_handler_handle_request(coap_message_t * p_request)
  410. {
  411. LWM2M_ENTRY();
  412. uint16_t index;
  413. uint16_t path[3];
  414. char * endptr;
  415. bool is_numbers_only = true;
  416. uint16_t path_index = 0;
  417. uint32_t err_code = NRF_SUCCESS;
  418. LWM2M_MUTEX_LOCK();
  419. for (index = 0; index < p_request->options_count; index++)
  420. {
  421. if (p_request->options[index].number == COAP_OPT_URI_PATH)
  422. {
  423. uint16_t option_len = p_request->options[index].length;
  424. bool numbers = numbers_only((char *)p_request->options[index].p_data,
  425. option_len);
  426. if (numbers)
  427. {
  428. // Declare a temporary array that is 1 byte longer than the
  429. // option data in order to leave space for a terminating character.
  430. uint8_t option_data[option_len + 1];
  431. // Set the temporary array to zero.
  432. memset(option_data, 0, sizeof(option_data));
  433. // Copy the option data string to the temporary array.
  434. memcpy(option_data, p_request->options[index].p_data, option_len);
  435. // Convert the zero-terminated string to a long int value.
  436. path[path_index] = strtol((char *)option_data, &endptr, 10);
  437. ++path_index;
  438. if (endptr == ((char *)option_data))
  439. {
  440. err_code = NRF_ERROR_NOT_FOUND;
  441. break;
  442. }
  443. if (endptr != ((char *)option_data + option_len))
  444. {
  445. err_code = NRF_ERROR_NOT_FOUND;
  446. break;
  447. }
  448. }
  449. else
  450. {
  451. is_numbers_only = false;
  452. break;
  453. }
  454. }
  455. }
  456. if (err_code == NRF_SUCCESS)
  457. {
  458. if (is_numbers_only == true)
  459. {
  460. err_code = internal_request_handle(p_request, path, path_index);
  461. }
  462. else
  463. {
  464. // If uri path did not consist of numbers only.
  465. char * requested_uri = NULL;
  466. for (index = 0; index < p_request->options_count; index++)
  467. {
  468. if (p_request->options[index].number == COAP_OPT_URI_PATH)
  469. {
  470. requested_uri = (char *)p_request->options[index].p_data;
  471. // Stop on first URI hit.
  472. break;
  473. }
  474. }
  475. if (requested_uri == NULL)
  476. {
  477. err_code = NRF_ERROR_NOT_FOUND;
  478. }
  479. else
  480. {
  481. // Try to look up if there is a match with object with an alias name.
  482. for (int i = 0; i < m_num_objects; ++i)
  483. {
  484. if (m_objects[i]->object_id == LWM2M_NAMED_OBJECT)
  485. {
  486. size_t size = strlen(m_objects[i]->p_alias_name);
  487. if ((strncmp(m_objects[i]->p_alias_name, requested_uri, size) == 0))
  488. {
  489. if (m_objects[i]->callback == NULL)
  490. {
  491. err_code = NRF_ERROR_NULL;
  492. break;
  493. }
  494. LWM2M_MUTEX_UNLOCK();
  495. err_code = m_objects[i]->callback(m_objects[i],
  496. LWM2M_INVALID_INSTANCE,
  497. LWM2M_OPERATION_CODE_NONE,
  498. p_request);
  499. LWM2M_MUTEX_LOCK();
  500. break;
  501. }
  502. }
  503. else
  504. {
  505. // This is not a name object, return error code.
  506. err_code = NRF_ERROR_NOT_FOUND;
  507. break;
  508. }
  509. }
  510. }
  511. }
  512. }
  513. LWM2M_MUTEX_UNLOCK();
  514. LWM2M_EXIT();
  515. return err_code;
  516. }
  517. uint32_t lwm2m_coap_handler_instance_add(lwm2m_instance_prototype_t * p_instance)
  518. {
  519. LWM2M_ENTRY();
  520. NULL_PARAM_CHECK(p_instance);
  521. LWM2M_MUTEX_LOCK();
  522. if (m_num_instances == LWM2M_COAP_HANDLER_MAX_INSTANCES)
  523. {
  524. LWM2M_MUTEX_UNLOCK();
  525. return NRF_ERROR_NO_MEM;
  526. }
  527. m_instances[m_num_instances] = p_instance;
  528. ++m_num_instances;
  529. LWM2M_MUTEX_UNLOCK();
  530. return NRF_SUCCESS;
  531. }
  532. uint32_t lwm2m_coap_handler_instance_delete(lwm2m_instance_prototype_t * p_instance)
  533. {
  534. LWM2M_ENTRY();
  535. NULL_PARAM_CHECK(p_instance);
  536. LWM2M_MUTEX_LOCK();
  537. for (int i = 0; i < m_num_instances; ++i)
  538. {
  539. if ((m_instances[i]->object_id == p_instance->object_id) &&
  540. (m_instances[i]->instance_id == p_instance->instance_id))
  541. {
  542. // Move current last entry into this index position, and trim down the length.
  543. // If this is the last element, it cannot be accessed because the m_num_instances
  544. // count is 0.
  545. m_instances[i] = m_instances[m_num_instances - 1];
  546. --m_num_instances;
  547. LWM2M_MUTEX_UNLOCK();
  548. return NRF_SUCCESS;
  549. }
  550. }
  551. LWM2M_MUTEX_UNLOCK();
  552. return NRF_ERROR_NOT_FOUND;
  553. }
  554. uint32_t lwm2m_coap_handler_object_add(lwm2m_object_prototype_t * p_object)
  555. {
  556. LWM2M_ENTRY();
  557. NULL_PARAM_CHECK(p_object);
  558. LWM2M_MUTEX_LOCK();
  559. if (m_num_objects == LWM2M_COAP_HANDLER_MAX_INSTANCES)
  560. {
  561. LWM2M_MUTEX_UNLOCK();
  562. return NRF_ERROR_NO_MEM;
  563. }
  564. m_objects[m_num_objects] = p_object;
  565. ++m_num_objects;
  566. LWM2M_MUTEX_UNLOCK();
  567. return NRF_SUCCESS;
  568. }
  569. uint32_t lwm2m_coap_handler_object_delete(lwm2m_object_prototype_t * p_object)
  570. {
  571. LWM2M_ENTRY();
  572. NULL_PARAM_CHECK(p_object);
  573. LWM2M_MUTEX_LOCK();
  574. for (int i = 0; i < m_num_objects; ++i)
  575. {
  576. if ( m_objects[i]->object_id == p_object->object_id)
  577. {
  578. // Move current last entry into this index position, and trim down the length.
  579. // If this is the last element, it cannot be accessed because the m_num_objects
  580. // count is 0.
  581. m_objects[i] = m_objects[m_num_objects - 1];
  582. --m_num_objects;
  583. LWM2M_MUTEX_UNLOCK();
  584. return NRF_SUCCESS;
  585. }
  586. }
  587. LWM2M_MUTEX_UNLOCK();
  588. return NRF_ERROR_NOT_FOUND;
  589. }
  590. uint32_t lwm2m_coap_handler_gen_link_format(uint8_t * p_buffer, uint16_t * p_buffer_len)
  591. {
  592. LWM2M_ENTRY();
  593. NULL_PARAM_CHECK(p_buffer_len);
  594. LWM2M_MUTEX_LOCK();
  595. uint16_t buffer_index = 0;
  596. uint8_t * p_string_buffer;
  597. uint16_t buffer_max_size;
  598. uint8_t dry_run_buffer[16];
  599. bool dry_run = false;
  600. uint16_t dry_run_size = 0;
  601. if (p_buffer == NULL)
  602. {
  603. // Dry-run only, in order to calculate the size of the needed buffer.
  604. dry_run = true;
  605. p_string_buffer = dry_run_buffer;
  606. buffer_max_size = sizeof(dry_run_buffer);
  607. }
  608. else
  609. {
  610. p_string_buffer = p_buffer;
  611. buffer_max_size = *p_buffer_len;
  612. }
  613. for (int i = 0; i < m_num_objects; ++i)
  614. {
  615. // We need more than 3 chars to write a new link
  616. if (buffer_max_size - buffer_index <= 3)
  617. {
  618. LWM2M_MUTEX_UNLOCK();
  619. return NRF_ERROR_NO_MEM;
  620. }
  621. uint16_t curr_object = m_objects[i]->object_id;
  622. if (curr_object == LWM2M_NAMED_OBJECT)
  623. {
  624. // Skip this object as it is a named object.
  625. continue;
  626. }
  627. bool instance_present = false;
  628. for (int j = 0; j < m_num_instances; ++j)
  629. {
  630. if (m_instances[j]->object_id == curr_object)
  631. {
  632. instance_present = true;
  633. buffer_index += snprintf((char *)&p_string_buffer[buffer_index],
  634. buffer_max_size - buffer_index,
  635. "</%u/%u>,",
  636. m_instances[j]->object_id,
  637. m_instances[j]->instance_id);
  638. if (dry_run == true)
  639. {
  640. dry_run_size += buffer_index;
  641. buffer_index = 0;
  642. }
  643. }
  644. }
  645. if (!instance_present)
  646. {
  647. buffer_index += snprintf((char *)&p_string_buffer[buffer_index],
  648. buffer_max_size - buffer_index,
  649. "</%u>,",
  650. curr_object);
  651. if (dry_run == true)
  652. {
  653. dry_run_size += buffer_index;
  654. buffer_index = 0;
  655. }
  656. }
  657. }
  658. if (dry_run == true)
  659. {
  660. *p_buffer_len = dry_run_size - 1;
  661. }
  662. else
  663. {
  664. *p_buffer_len = buffer_index - 1; // Remove the last comma
  665. }
  666. LWM2M_MUTEX_UNLOCK();
  667. return NRF_SUCCESS;
  668. }
  669. uint32_t lwm2m_init(void)
  670. {
  671. SDK_MUTEX_INIT(m_lwm2m_mutex);
  672. LWM2M_MUTEX_LOCK();
  673. uint32_t err_code;
  674. err_code = internal_lwm2m_register_init();
  675. if (err_code != NRF_SUCCESS)
  676. {
  677. LWM2M_MUTEX_UNLOCK();
  678. return err_code;
  679. }
  680. err_code = internal_lwm2m_bootstrap_init();
  681. if (err_code != NRF_SUCCESS)
  682. {
  683. LWM2M_MUTEX_UNLOCK();
  684. return err_code;
  685. }
  686. err_code = coap_error_handler_register(coap_error_handler);
  687. if (err_code != NRF_SUCCESS)
  688. {
  689. LWM2M_MUTEX_UNLOCK();
  690. return err_code;
  691. }
  692. internal_coap_handler_init();
  693. err_code = coap_request_handler_register(lwm2m_coap_handler_handle_request);
  694. LWM2M_MUTEX_UNLOCK();
  695. return err_code;
  696. }