lwm2m_tlv.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  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 <stdint.h>
  41. #include <string.h>
  42. #include "lwm2m_tlv.h"
  43. #include "lwm2m_objects.h"
  44. #include "iot_errors.h"
  45. #include "iot_defines.h"
  46. // Used for encoding
  47. // TODO: Remove this temp_buffer in order to allow to users to use the API at the same time.
  48. // Current implementation might fail if two different interrupt levels are executing
  49. // encode at the same time. The temp_buffer will be overwritten by the last user.
  50. static uint8_t temp_buffer[4];
  51. uint32_t lwm2m_tlv_bytebuffer_to_uint32(uint8_t * p_buffer, uint8_t val_len, uint32_t * p_result)
  52. {
  53. uint32_t res;
  54. switch (val_len)
  55. {
  56. case 0:
  57. {
  58. res = 0;
  59. break;
  60. }
  61. case 1:
  62. {
  63. res = p_buffer[0];
  64. break;
  65. }
  66. case 2:
  67. {
  68. res = ((uint32_t)p_buffer[0] << 8) |
  69. p_buffer[1];
  70. break;
  71. }
  72. case 3:
  73. {
  74. res = ((uint32_t)p_buffer[0] << 16) |
  75. ((uint32_t)p_buffer[1] << 8) |
  76. p_buffer[2];
  77. break;
  78. }
  79. case 4:
  80. {
  81. res = ((uint32_t)p_buffer[0] << 24) |
  82. ((uint32_t)p_buffer[1] << 16) |
  83. ((uint32_t)p_buffer[2] << 8) |
  84. p_buffer[3];
  85. break;
  86. }
  87. default:
  88. return NRF_ERROR_DATA_SIZE;
  89. }
  90. *p_result = res;
  91. return NRF_SUCCESS;
  92. }
  93. uint32_t lwm2m_tlv_bytebuffer_to_uint16(uint8_t * p_buffer, uint8_t val_len, uint16_t * p_result)
  94. {
  95. uint16_t res;
  96. switch (val_len)
  97. {
  98. case 0:
  99. {
  100. res = 0;
  101. break;
  102. }
  103. case 1:
  104. {
  105. res = p_buffer[0];
  106. break;
  107. }
  108. case 2:
  109. {
  110. res = ((uint16_t)p_buffer[0] << 8) | p_buffer[1];
  111. break;
  112. }
  113. default:
  114. return NRF_ERROR_DATA_SIZE;
  115. }
  116. *p_result = res;
  117. return NRF_SUCCESS;
  118. }
  119. void lwm2m_tlv_uint16_to_bytebuffer(uint8_t * p_buffer, uint8_t * p_len, uint16_t value)
  120. {
  121. if (value == 0)
  122. {
  123. *p_len = 0;
  124. }
  125. else if (value <= UINT8_MAX)
  126. {
  127. p_buffer[0] = value;
  128. *p_len = 1;
  129. }
  130. else
  131. {
  132. p_buffer[1] = value;
  133. p_buffer[0] = value >> 8;
  134. *p_len = 2;
  135. }
  136. }
  137. void lwm2m_tlv_uint32_to_bytebuffer(uint8_t * p_buffer, uint8_t * p_len, uint32_t value)
  138. {
  139. if (value == 0)
  140. {
  141. *p_len = 0;
  142. }
  143. else if (value <= UINT8_MAX)
  144. {
  145. p_buffer[0] = value;
  146. *p_len = 1;
  147. }
  148. else if (value <= UINT16_MAX)
  149. {
  150. p_buffer[1] = value;
  151. p_buffer[0] = value >> 8;
  152. *p_len = 2;
  153. }
  154. else if (value <= 0xFFFFFF) // 24 bit
  155. {
  156. p_buffer[2] = value;
  157. p_buffer[1] = value >> 8;
  158. p_buffer[0] = value >> 16;
  159. *p_len = 3;
  160. }
  161. else
  162. {
  163. p_buffer[3] = value;
  164. p_buffer[2] = value >> 8;
  165. p_buffer[1] = value >> 16;
  166. p_buffer[0] = value >> 24;
  167. *p_len = 4;
  168. }
  169. }
  170. void lwm2m_tlv_uint16_set(lwm2m_tlv_t * p_tlv, uint16_t value, uint16_t id)
  171. {
  172. uint8_t val_len;
  173. lwm2m_tlv_uint16_to_bytebuffer(temp_buffer, &val_len, value);
  174. p_tlv->length = val_len;
  175. p_tlv->value = temp_buffer;
  176. p_tlv->id = id;
  177. }
  178. void lwm2m_tlv_uint32_set(lwm2m_tlv_t * p_tlv, uint32_t value, uint16_t id)
  179. {
  180. uint8_t val_len;
  181. lwm2m_tlv_uint32_to_bytebuffer(temp_buffer, &val_len, value);
  182. p_tlv->length = val_len;
  183. p_tlv->value = temp_buffer;
  184. p_tlv->id = id;
  185. }
  186. void lwm2m_tlv_bool_set(lwm2m_tlv_t * p_tlv, bool value, uint16_t id)
  187. {
  188. if (value == true)
  189. {
  190. temp_buffer[0] = 1;
  191. }
  192. else
  193. {
  194. temp_buffer[0] = 0;
  195. }
  196. p_tlv->length = 1;
  197. p_tlv->value = temp_buffer;
  198. p_tlv->id = id;
  199. }
  200. void lwm2m_tlv_string_set(lwm2m_tlv_t * p_tlv, lwm2m_string_t string, uint16_t id)
  201. {
  202. p_tlv->length = string.len;
  203. p_tlv->value = (uint8_t *)string.p_val;
  204. p_tlv->id = id;
  205. }
  206. void lwm2m_tlv_opaque_set(lwm2m_tlv_t * p_tlv, lwm2m_opaque_t opaque, uint16_t id)
  207. {
  208. p_tlv->length = opaque.len;
  209. p_tlv->value = opaque.p_val;
  210. p_tlv->id = id;
  211. }
  212. uint32_t lwm2m_tlv_decode(lwm2m_tlv_t * p_tlv,
  213. uint32_t * p_index,
  214. uint8_t * p_buffer,
  215. uint16_t buffer_len)
  216. {
  217. uint32_t err_code;
  218. uint16_t index = *p_index;
  219. uint8_t type = (p_buffer[index] & TLV_TYPE_MASK) >> TLV_TYPE_BIT_POS;
  220. uint8_t id_len = (p_buffer[index] & TLV_ID_LEN_MASK) >> TLV_ID_LEN_BIT_POS;
  221. uint8_t length_len = (p_buffer[index] & TLV_LEN_TYPE_MASK) >> TLV_LEN_TYPE_BIT_POS;
  222. uint32_t length = (p_buffer[index] & TLV_LEN_VAL_MASK) >> TLV_VAL_LEN_BIT_POS;
  223. p_tlv->id_type = type;
  224. p_tlv->length = 0;
  225. // Jump to the byte following the "Type" at index 0.
  226. ++index;
  227. // Extract the Identifier based on the number of bytes indicated in id_len (bit 5).
  228. // Adding one to the id_len will give the number of bytes used.
  229. uint8_t id_len_size = id_len + 1;
  230. err_code = lwm2m_tlv_bytebuffer_to_uint16(&p_buffer[index], id_len_size, &p_tlv->id);
  231. if (err_code != NRF_SUCCESS)
  232. {
  233. return err_code;
  234. }
  235. index += id_len_size;
  236. // Extract the value length.
  237. // The length_len tells how many bytes are being used.
  238. if (length_len == TLV_LEN_TYPE_3BIT)
  239. {
  240. p_tlv->length = length;
  241. }
  242. else
  243. {
  244. err_code = lwm2m_tlv_bytebuffer_to_uint32(&p_buffer[index], length_len, &length);
  245. if (err_code != NRF_SUCCESS)
  246. {
  247. return err_code;
  248. }
  249. p_tlv->length = length;
  250. index += length_len;
  251. }
  252. if (p_tlv->length > buffer_len)
  253. {
  254. return (IOT_LWM2M_ERR_BASE | NRF_ERROR_INVALID_DATA);
  255. }
  256. p_tlv->value = &p_buffer[index];
  257. *p_index = index + p_tlv->length;
  258. return NRF_SUCCESS;
  259. }
  260. uint32_t lwm2m_tlv_encode(uint8_t * p_buffer, uint32_t * buffer_len, lwm2m_tlv_t * p_tlv)
  261. {
  262. uint8_t length_len;
  263. uint8_t id_len;
  264. uint8_t id[2] = {0,};
  265. uint8_t len[3] = {0,};
  266. uint16_t index = 0;
  267. uint8_t type = 0;
  268. // Set Identifier type by copying the lwm2m_tlv_t->id_type into bit 7-6.
  269. type = (p_tlv->id_type << TLV_TYPE_BIT_POS);
  270. // Set length of Identifier in bit 5 in the TLV type byte.
  271. if (p_tlv->id > UINT8_MAX)
  272. {
  273. type |= (TLV_ID_LEN_16BIT << TLV_ID_LEN_BIT_POS);
  274. id[0] = p_tlv->id >> 8;
  275. id[1] = p_tlv->id;
  276. id_len = 2;
  277. }
  278. else
  279. {
  280. type |= (TLV_ID_LEN_8BIT << TLV_ID_LEN_BIT_POS);
  281. id[0] = p_tlv->id;
  282. id_len = 1;
  283. }
  284. // Set type of Length bit 4-3 in the TLV type byte.
  285. // If the Length can fit into 3 bits.
  286. if ((p_tlv->length & TLV_LEN_VAL_MASK) == p_tlv->length)
  287. {
  288. type |= (TLV_LEN_TYPE_3BIT << TLV_LEN_TYPE_BIT_POS);
  289. length_len = 0;
  290. // As Length type field is set to "No Length", set bit 2-0.
  291. type |= (p_tlv->length & TLV_LEN_VAL_MASK);
  292. }
  293. else
  294. {
  295. lwm2m_tlv_uint32_to_bytebuffer(&len[0], &length_len, p_tlv->length);
  296. // Length can not be larger than 24-bit.
  297. if (length_len > TLV_LEN_TYPE_24BIT)
  298. {
  299. return (IOT_LWM2M_ERR_BASE | NRF_ERROR_INVALID_PARAM);
  300. }
  301. type |= (length_len << TLV_LEN_TYPE_BIT_POS);
  302. }
  303. // Check if the buffer is large enough.
  304. if (*buffer_len < (p_tlv->length + id_len + length_len + 1)) // + 1 for the type byte
  305. {
  306. return (IOT_LWM2M_ERR_BASE | NRF_ERROR_DATA_SIZE);
  307. }
  308. // Copy the type to the buffer.
  309. memcpy(p_buffer + index, &type, 1);
  310. ++index;
  311. // Copy the Identifier to the buffer.
  312. memcpy(p_buffer + index, id, id_len);
  313. index += id_len;
  314. // Copy length to the buffer.
  315. if (length_len != 0)
  316. {
  317. memcpy(p_buffer + index, len, length_len);
  318. index += length_len;
  319. }
  320. // Copy the value to buffer, memcpy of 0 length is undefined behavior so lets avoid it.
  321. if (p_tlv->length > 0)
  322. {
  323. memcpy(p_buffer + index, p_tlv->value, p_tlv->length);
  324. }
  325. // Set length of the output buffer.
  326. *buffer_len = p_tlv->length + index;
  327. return NRF_SUCCESS;
  328. }