coap_message.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  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 <stdlib.h>
  41. #include <string.h>
  42. #include "nordic_common.h"
  43. #include "coap_message.h"
  44. #include "coap_api.h"
  45. #include "iot_common.h"
  46. #include "sdk_config.h"
  47. #include "app_util.h"
  48. #define COAP_PAYLOAD_MARKER_SIZE 1
  49. /**@brief Verify that there is a index available for a new option. */
  50. #define OPTION_INDEX_AVAIL_CHECK(COUNT) \
  51. if ((COUNT) >= COAP_MAX_NUMBER_OF_OPTIONS) \
  52. { \
  53. return (NRF_ERROR_NO_MEM | IOT_COAP_ERR_BASE); \
  54. }
  55. #if (COAP_DISABLE_API_PARAM_CHECK == 0)
  56. /**@brief Verify NULL parameters are not passed to API by application. */
  57. #define NULL_PARAM_CHECK(PARAM) \
  58. if ((PARAM) == NULL) \
  59. { \
  60. return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); \
  61. }
  62. #else
  63. #define NULL_PARAM_CHECK(PARAM)
  64. #define OPTION_INDEX_AVAIL_CHECK(COUNT)
  65. #endif // COAP_DISABLE_API_PARAM_CHECK
  66. uint32_t coap_message_create(coap_message_t * p_message, coap_message_conf_t * p_init_config)
  67. {
  68. NULL_PARAM_CHECK(p_message);
  69. NULL_PARAM_CHECK(p_init_config);
  70. // Setting default value for version.
  71. p_message->header.version = COAP_VERSION;
  72. // Copy values from the init config.
  73. p_message->header.type = p_init_config->type;
  74. p_message->header.token_len = p_init_config->token_len;
  75. p_message->header.code = p_init_config->code;
  76. p_message->header.id = p_init_config->id;
  77. p_message->response_callback = p_init_config->response_callback;
  78. p_message->p_arg = NULL;
  79. if (p_init_config->port.port_number == 0)
  80. {
  81. return (NRF_ERROR_INVALID_PARAM | IOT_COAP_ERR_BASE);
  82. }
  83. memcpy(&p_message->port, &p_init_config->port, sizeof(coap_port_t));
  84. memcpy(p_message->token, p_init_config->token, sizeof(p_init_config->token));
  85. return NRF_SUCCESS;
  86. }
  87. /**@brief Decode CoAP option
  88. *
  89. * @param[in] p_raw_option Pointer to the memory buffer where the raw option is located.
  90. * @param[inout] p_message Pointer to the current message. Used to retrieve information about
  91. * where current option delta and the size of free memory to add the
  92. * values of the option. Used as a container where to put
  93. * the parsed option.
  94. * @param[out] byte_count Number of bytes parsed. Used to indicate where the next option
  95. * might be located (if any left) in the raw message buffer.
  96. *
  97. * @retval NRF_SUCCESS If the option parsing went successful.
  98. * @retval NRF_ERROR_DATA_SIZE If there is no more space left in the free memory to add the
  99. * option value to the p_message.
  100. */
  101. static uint32_t decode_option(const uint8_t * p_raw_option, coap_message_t * p_message, uint16_t * byte_count)
  102. {
  103. uint16_t byte_index = 0;
  104. uint8_t option_num = p_message->options_count;
  105. // Calculate the option number.
  106. uint16_t option_delta = (p_raw_option[byte_index] & 0xF0) >> 4;
  107. // Calculate the option length.
  108. uint16_t option_length = (p_raw_option[byte_index] & 0x0F);
  109. byte_index++;
  110. uint16_t acc_option_delta = p_message->options_delta;
  111. if (option_delta == 13)
  112. {
  113. // read one additional byte to get the extended delta.
  114. acc_option_delta += 13 + p_raw_option[byte_index++];
  115. }
  116. else if (option_delta == 14)
  117. {
  118. // read one additional byte to get the extended delta.
  119. acc_option_delta += 269;
  120. acc_option_delta += (p_raw_option[byte_index++] << 8);
  121. acc_option_delta += (p_raw_option[byte_index++]);
  122. }
  123. else
  124. {
  125. acc_option_delta += option_delta;
  126. }
  127. // Set the accumlated delta as the option number.
  128. p_message->options[option_num].number = acc_option_delta;
  129. if (option_length == 13)
  130. {
  131. option_length = 13 + p_raw_option[byte_index++];
  132. }
  133. else if (option_length == 14)
  134. {
  135. option_length = 269;
  136. option_length += (p_raw_option[byte_index++] << 8);
  137. option_length += p_raw_option[byte_index++];
  138. }
  139. // Set the option length including extended bytes.
  140. p_message->options[option_num].length = option_length;
  141. // Point p_data to the memory where to find the option value.
  142. p_message->options[option_num].p_data = (uint8_t *)&p_raw_option[byte_index];
  143. // Update the delta counter with latest option number.
  144. p_message->options_delta = p_message->options[option_num].number;
  145. byte_index += p_message->options[option_num].length;
  146. *byte_count = byte_index;
  147. return NRF_SUCCESS;
  148. }
  149. /**@brief Encode CoAP option delta and length bytes.
  150. *
  151. * @param[inout] encoded_value Value to encode. In return the value after encoding.
  152. * @param[out] encoded_value_ext The value of the encoded extended bytes.
  153. *
  154. * @return The size of the extended byte field.
  155. */
  156. static inline uint8_t encode_extended_bytes(uint16_t * value,
  157. uint16_t * value_ext)
  158. {
  159. uint16_t raw_value = *value;
  160. uint8_t ext_size = 0;
  161. if (raw_value >= 269)
  162. {
  163. *value = 14;
  164. *value_ext = raw_value - 269;
  165. ext_size = 2;
  166. }
  167. else if (raw_value >= 13)
  168. {
  169. *value = 13;
  170. *value_ext = raw_value - 13;
  171. ext_size = 1;
  172. }
  173. else
  174. {
  175. *value = raw_value;
  176. *value_ext = 0;
  177. }
  178. return ext_size;
  179. }
  180. static uint32_t encode_option(uint8_t * p_buffer, coap_option_t * p_option, uint16_t * byte_count)
  181. {
  182. uint16_t delta_ext = 0;
  183. uint16_t delta = p_option->number;
  184. uint8_t delta_ext_size = encode_extended_bytes(&delta,
  185. &delta_ext);
  186. uint16_t length = p_option->length;
  187. uint16_t length_ext = 0;
  188. uint8_t length_ext_size = encode_extended_bytes(&length,
  189. &length_ext);
  190. if (p_buffer == NULL)
  191. {
  192. uint16_t header_size = 1;
  193. *byte_count = header_size + delta_ext_size + length_ext_size + p_option->length;
  194. return NRF_SUCCESS;
  195. }
  196. uint16_t byte_index = 0;
  197. // Add the option header.
  198. p_buffer[byte_index++] = ((delta & 0x0F) << 4) | (length & 0x0F);
  199. // Add option delta extended bytes to the buffer.
  200. if (delta_ext_size == 1)
  201. {
  202. // Add first byte of delta_ext to the option header.
  203. p_buffer[byte_index++] = (uint8_t)delta_ext;
  204. }
  205. else if (delta_ext_size == 2)
  206. {
  207. // uint16 in Network Byte Order.
  208. p_buffer[byte_index++] = (uint8_t)((delta_ext & 0xFF00) >> 8);
  209. p_buffer[byte_index++] = (uint8_t)((delta_ext & 0x00FF));
  210. }
  211. if (length_ext_size == 1)
  212. {
  213. // Add first byte of length_ext to the option header.
  214. p_buffer[byte_index++] = (uint8_t)length_ext;
  215. }
  216. else if (length_ext_size == 2)
  217. {
  218. // uint16 in Network Byte Order.
  219. p_buffer[byte_index++] = (uint8_t)((length_ext & 0xFF00) >> 8);
  220. p_buffer[byte_index++] = (uint8_t)((length_ext & 0x00FF));
  221. }
  222. memcpy(&p_buffer[byte_index], p_option->p_data, p_option->length);
  223. *byte_count = byte_index + p_option->length;
  224. return NRF_SUCCESS;
  225. }
  226. uint32_t coap_message_decode(coap_message_t * p_message,
  227. const uint8_t * p_raw_message,
  228. uint16_t message_len)
  229. {
  230. NULL_PARAM_CHECK(p_message);
  231. NULL_PARAM_CHECK(p_raw_message);
  232. // Check that the raw message contains the mandatory header.
  233. if (message_len < 4)
  234. {
  235. return (NRF_ERROR_INVALID_LENGTH | IOT_COAP_ERR_BASE);
  236. }
  237. // Parse the content of the raw message buffer.
  238. uint16_t byte_index = 0;
  239. // Parse the 4 byte CoAP header.
  240. p_message->header.version = (p_raw_message[byte_index] >> 6);
  241. p_message->header.type = (coap_msg_type_t)((p_raw_message[byte_index] >> 4) & 0x03);
  242. p_message->header.token_len = (p_raw_message[byte_index] & 0x0F);
  243. byte_index++;
  244. p_message->header.code = (coap_msg_code_t)p_raw_message[byte_index];
  245. byte_index++;
  246. p_message->header.id = p_raw_message[byte_index++] << 8;
  247. p_message->header.id += p_raw_message[byte_index++];
  248. // Parse the token, if any.
  249. for (uint8_t index = 0; (byte_index < message_len) && (index < p_message->header.token_len); index++)
  250. {
  251. p_message->token[index] = p_raw_message[byte_index++];
  252. }
  253. p_message->options_count = 0;
  254. p_message->options_delta = 0;
  255. // Parse the options if any.
  256. while ((byte_index < message_len) && (p_raw_message[byte_index] != COAP_PAYLOAD_MARKER))
  257. {
  258. uint32_t err_code;
  259. uint16_t byte_count = 0;
  260. err_code = decode_option(&p_raw_message[byte_index], p_message, &byte_count);
  261. if (err_code != NRF_SUCCESS)
  262. {
  263. return err_code;
  264. }
  265. p_message->options_count += 1;
  266. byte_index += byte_count;
  267. }
  268. // If there any more bytes to parse this would be the payload.
  269. if (byte_index < message_len)
  270. {
  271. // Verify that we have a payload marker.
  272. if (p_raw_message[byte_index] == COAP_PAYLOAD_MARKER)
  273. {
  274. byte_index++;
  275. }
  276. else
  277. {
  278. return COAP_MESSAGE_INVALID_CONTENT;
  279. }
  280. p_message->payload_len = message_len - byte_index;
  281. p_message->p_payload = (uint8_t *)&p_raw_message[byte_index];
  282. }
  283. return NRF_SUCCESS;
  284. }
  285. uint32_t coap_message_encode(coap_message_t * p_message,
  286. uint8_t * p_buffer,
  287. uint16_t * p_length)
  288. {
  289. NULL_PARAM_CHECK(p_length);
  290. NULL_PARAM_CHECK(p_message);
  291. // calculated size
  292. uint16_t total_packet_size = 4;
  293. if (p_message->payload_len > 0)
  294. {
  295. total_packet_size += p_message->payload_len;
  296. total_packet_size += COAP_PAYLOAD_MARKER_SIZE;
  297. }
  298. if (p_message->header.token_len > 8)
  299. {
  300. return (NRF_ERROR_INVALID_DATA | IOT_COAP_ERR_BASE);
  301. }
  302. total_packet_size += p_message->header.token_len;
  303. total_packet_size += p_message->options_len;
  304. // If this was a length check, return after setting the length in the output parameter.
  305. if (*p_length == 0)
  306. {
  307. *p_length = total_packet_size;
  308. return NRF_SUCCESS;
  309. }
  310. // Check that the buffer provided is sufficient.
  311. if (*p_length < total_packet_size)
  312. {
  313. return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE);
  314. }
  315. if (((p_message->payload_len > 0 && p_message->p_payload == NULL)) ||
  316. (p_buffer == NULL))
  317. {
  318. return COAP_MESSAGE_ERROR_NULL;
  319. }
  320. // Start filling the bytes.
  321. uint16_t byte_index = 0;
  322. // TODO: Verify the values of the header fields.
  323. // if (version > 1)
  324. // if (p_message->type > COAP_TYPE_RST)
  325. // if (p_message->token_len > 8)
  326. p_buffer[byte_index] = (((p_message->header.version & 0x3) << 6) | ((p_message->header.type & 0x3) << 4)) | (p_message->header.token_len & 0x0F);
  327. byte_index++;
  328. p_buffer[byte_index] = p_message->header.code;
  329. byte_index++;
  330. p_buffer[byte_index++] = (p_message->header.id & 0xFF00) >> 8;
  331. p_buffer[byte_index++] = (p_message->header.id & 0x00FF);
  332. memcpy(&p_buffer[byte_index], p_message->token, p_message->header.token_len);
  333. byte_index += p_message->header.token_len;
  334. //memcpy(&p_buffer[byte_index], &p_message->p_data[0], p_message->options_len);
  335. for (uint8_t i = 0; i < p_message->options_count; i++)
  336. {
  337. uint32_t err_code;
  338. uint16_t byte_count = 0;
  339. err_code = encode_option(&p_buffer[byte_index], &p_message->options[i], &byte_count);
  340. if (err_code == NRF_SUCCESS)
  341. {
  342. byte_index += byte_count;
  343. }
  344. else
  345. {
  346. // Throw an error.
  347. }
  348. }
  349. if (p_message->payload_len > 0 && p_message->p_payload != NULL)
  350. {
  351. p_buffer[byte_index++] = 0xFF;
  352. memcpy(&p_buffer[byte_index], p_message->p_payload, p_message->payload_len);
  353. }
  354. *p_length = total_packet_size;
  355. return NRF_SUCCESS;
  356. }
  357. uint32_t coap_message_opt_empty_add(coap_message_t * p_message, uint16_t option_num)
  358. {
  359. OPTION_INDEX_AVAIL_CHECK(p_message->options_count);
  360. uint32_t err_code;
  361. uint16_t encoded_len = 0;
  362. uint8_t current_option_index = p_message->options_count;
  363. p_message->options[current_option_index].number = option_num - p_message->options_delta;
  364. p_message->options[current_option_index].length = encoded_len;
  365. // Set accumulated option delta for next option.
  366. p_message->options_delta = option_num;
  367. // Calculate option size
  368. uint16_t option_byte_count = 0;
  369. // do a length check to encode_option to get the header length.
  370. err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count);
  371. // Accumulate expected size of all options with headers.
  372. p_message->options_len += option_byte_count;
  373. p_message->options_count += 1;
  374. return err_code;
  375. }
  376. uint32_t coap_message_opt_uint_add(coap_message_t * p_message,
  377. uint16_t option_num,
  378. uint32_t data)
  379. {
  380. OPTION_INDEX_AVAIL_CHECK(p_message->options_count);
  381. uint32_t err_code;
  382. uint16_t encoded_len = p_message->data_len - p_message->options_offset;
  383. uint8_t current_option_index = p_message->options_count;
  384. uint8_t * p_next_option_data = &p_message->p_data[p_message->options_offset];
  385. // If the value of the option is 0, do not encode the 0, as this can be omitted. (RFC7252 3.2)
  386. if (data == 0)
  387. {
  388. encoded_len = 0;
  389. }
  390. else
  391. {
  392. err_code = coap_opt_uint_encode(p_next_option_data, &encoded_len, data);
  393. if (err_code != NRF_SUCCESS)
  394. {
  395. return err_code;
  396. }
  397. }
  398. p_message->options[current_option_index].p_data = p_next_option_data;
  399. p_message->options[current_option_index].number = option_num - p_message->options_delta;
  400. p_message->options[current_option_index].length = encoded_len;
  401. // Set accumulated option delta for next option.
  402. p_message->options_delta = option_num;
  403. // Calculate option size.
  404. uint16_t option_byte_count = 0;
  405. // Do a length check to encode_option to get the header length.
  406. err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count);
  407. // Accumulate expected size of all options with headers.
  408. p_message->options_len += option_byte_count;
  409. p_message->options_count += 1;
  410. // Increase the pointer offset for the next option data in the scratch buffer.
  411. p_message->options_offset += encoded_len;
  412. return err_code;
  413. }
  414. uint32_t coap_message_opt_str_add(coap_message_t * p_message, uint16_t option_num, uint8_t * p_data, uint16_t length)
  415. {
  416. OPTION_INDEX_AVAIL_CHECK(p_message->options_count);
  417. uint32_t err_code;
  418. uint16_t encoded_len = length;
  419. uint8_t current_option_index = p_message->options_count;
  420. uint8_t * p_next_option_data = &p_message->p_data[p_message->options_offset];
  421. err_code = coap_opt_string_encode(p_next_option_data, &encoded_len, p_data, length);
  422. if (err_code != NRF_SUCCESS)
  423. {
  424. return err_code;
  425. }
  426. p_message->options[current_option_index].p_data = p_next_option_data;
  427. p_message->options[current_option_index].number = option_num - p_message->options_delta;
  428. p_message->options[current_option_index].length = encoded_len;
  429. // Set accumulated option delta for next option.
  430. p_message->options_delta = option_num;
  431. // Calculate option size
  432. uint16_t option_byte_count = 0;
  433. // do a length check to encode_option to get the header length.
  434. err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count);
  435. // Accumulate expected size of all options with headers.
  436. p_message->options_len += option_byte_count;
  437. p_message->options_count += 1;
  438. p_message->options_offset += encoded_len;
  439. return err_code;
  440. }
  441. uint32_t coap_message_opt_opaque_add(coap_message_t * p_message, uint16_t option_num, uint8_t * p_data, uint16_t length)
  442. {
  443. OPTION_INDEX_AVAIL_CHECK(p_message->options_count);
  444. // Check if it is possible to add a new option of this length.
  445. if ((p_message->data_len - p_message->options_offset) < length)
  446. {
  447. return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE);
  448. }
  449. uint32_t err_code = NRF_SUCCESS;
  450. uint16_t encoded_len = length;
  451. uint8_t current_option_index = p_message->options_count;
  452. uint8_t * p_next_option_data = &p_message->p_data[p_message->options_offset];
  453. memcpy(p_next_option_data, p_data, encoded_len);
  454. p_message->options[current_option_index].p_data = p_next_option_data;
  455. p_message->options[current_option_index].number = option_num - p_message->options_delta;
  456. p_message->options[current_option_index].length = encoded_len;
  457. // Set accumulated option delta for next option.
  458. p_message->options_delta = option_num;
  459. // Calculate option size
  460. uint16_t option_byte_count = 0;
  461. // do a length check to encode_option to get the header length.
  462. err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count);
  463. // Accumulate expected size of all options with headers.
  464. p_message->options_len += option_byte_count;
  465. p_message->options_count += 1;
  466. p_message->options_offset += encoded_len;
  467. return err_code;
  468. }
  469. uint32_t coap_message_payload_set(coap_message_t * p_message,
  470. void * p_payload,
  471. uint16_t payload_len)
  472. {
  473. // Check that there is available memory in the p_message->p_data scratch buffer.
  474. if (payload_len > (COAP_MESSAGE_DATA_MAX_SIZE - p_message->options_offset))
  475. {
  476. return (NRF_ERROR_NO_MEM | IOT_COAP_ERR_BASE);
  477. }
  478. p_message->p_payload = &p_message->p_data[p_message->options_offset];
  479. p_message->payload_len = payload_len;
  480. memcpy(p_message->p_payload, p_payload, payload_len);
  481. return NRF_SUCCESS;
  482. }
  483. uint32_t coap_message_remote_addr_set(coap_message_t * p_message, coap_remote_t * p_address)
  484. {
  485. memcpy(&p_message->remote, p_address, sizeof(coap_remote_t));
  486. return NRF_SUCCESS;
  487. }
  488. uint32_t coap_message_opt_index_get(uint8_t * p_index, coap_message_t * p_message, uint16_t option)
  489. {
  490. NULL_PARAM_CHECK(p_index);
  491. NULL_PARAM_CHECK(p_message);
  492. uint8_t index;
  493. for (index = 0; index < p_message->options_count; index++)
  494. {
  495. if (p_message->options[index].number == option)
  496. {
  497. *p_index = index;
  498. return NRF_SUCCESS;
  499. }
  500. }
  501. return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
  502. }
  503. uint32_t coap_message_opt_present(coap_message_t * p_message, uint16_t option)
  504. {
  505. NULL_PARAM_CHECK(p_message);
  506. uint8_t index;
  507. for (index = 0; index < p_message->options_count; index++)
  508. {
  509. if (p_message->options[index].number == option)
  510. {
  511. return NRF_SUCCESS;
  512. }
  513. }
  514. return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
  515. }
  516. static uint32_t bit_to_content_format(coap_content_type_t * p_ct, uint32_t bit)
  517. {
  518. switch (bit)
  519. {
  520. case COAP_CT_MASK_PLAIN_TEXT:
  521. *p_ct = COAP_CT_PLAIN_TEXT;
  522. break;
  523. case COAP_CT_MASK_APP_LINK_FORMAT:
  524. *p_ct = COAP_CT_APP_LINK_FORMAT;
  525. break;
  526. case COAP_CT_MASK_APP_XML:
  527. *p_ct = COAP_CT_APP_XML;
  528. break;
  529. case COAP_CT_MASK_APP_OCTET_STREAM:
  530. *p_ct = COAP_CT_APP_OCTET_STREAM;
  531. break;
  532. case COAP_CT_MASK_APP_EXI:
  533. *p_ct = COAP_CT_APP_EXI;
  534. break;
  535. case COAP_CT_MASK_APP_JSON:
  536. *p_ct = COAP_CT_APP_JSON;
  537. break;
  538. default:
  539. return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE);
  540. }
  541. return NRF_SUCCESS;
  542. }
  543. static uint32_t content_format_to_bit(coap_content_type_t ct)
  544. {
  545. uint32_t mask = 0;
  546. switch (ct)
  547. {
  548. case COAP_CT_PLAIN_TEXT:
  549. mask = COAP_CT_MASK_PLAIN_TEXT;
  550. break;
  551. case COAP_CT_APP_LINK_FORMAT:
  552. mask = COAP_CT_MASK_APP_LINK_FORMAT;
  553. break;
  554. case COAP_CT_APP_XML:
  555. mask = COAP_CT_MASK_APP_XML;
  556. break;
  557. case COAP_CT_APP_OCTET_STREAM:
  558. mask = COAP_CT_MASK_APP_OCTET_STREAM;
  559. break;
  560. case COAP_CT_APP_EXI:
  561. mask = COAP_CT_MASK_APP_EXI;
  562. break;
  563. case COAP_CT_APP_JSON:
  564. mask = COAP_CT_MASK_APP_JSON;
  565. break;
  566. default:
  567. break;
  568. }
  569. return mask;
  570. }
  571. uint32_t coap_message_ct_mask_get(coap_message_t * p_message, uint32_t * p_mask)
  572. {
  573. NULL_PARAM_CHECK(p_message);
  574. NULL_PARAM_CHECK(p_mask);
  575. (*p_mask) = 0;
  576. for (uint8_t index = 0; index < p_message->options_count; index++)
  577. {
  578. if (p_message->options[index].number == COAP_OPT_CONTENT_FORMAT)
  579. {
  580. uint32_t value;
  581. uint32_t err_code = coap_opt_uint_decode(&value,
  582. p_message->options[index].length,
  583. p_message->options[index].p_data);
  584. if (err_code == NRF_SUCCESS)
  585. {
  586. coap_content_type_t ct = (coap_content_type_t)value;
  587. *p_mask |= content_format_to_bit(ct);
  588. }
  589. else
  590. {
  591. return err_code;
  592. }
  593. }
  594. }
  595. return NRF_SUCCESS;
  596. }
  597. uint32_t coap_message_accept_mask_get(coap_message_t * p_message, uint32_t * p_mask)
  598. {
  599. NULL_PARAM_CHECK(p_message);
  600. NULL_PARAM_CHECK(p_mask);
  601. (*p_mask) = 0;
  602. for (uint8_t index = 0; index < p_message->options_count; index++)
  603. {
  604. if (p_message->options[index].number == COAP_OPT_ACCEPT)
  605. {
  606. uint32_t value;
  607. uint32_t err_code = coap_opt_uint_decode(&value,
  608. p_message->options[index].length,
  609. p_message->options[index].p_data);
  610. if (err_code == NRF_SUCCESS)
  611. {
  612. coap_content_type_t ct = (coap_content_type_t)value;
  613. (*p_mask) |= content_format_to_bit(ct);
  614. }
  615. else
  616. {
  617. return err_code;
  618. }
  619. }
  620. }
  621. return NRF_SUCCESS;
  622. }
  623. uint32_t coap_message_ct_match_select(coap_content_type_t * p_ct, coap_message_t * p_message, coap_resource_t * p_resource)
  624. {
  625. // Check ACCEPT options
  626. uint32_t accept_mask = 0;
  627. (void)coap_message_accept_mask_get(p_message, &accept_mask);
  628. if (accept_mask == 0)
  629. {
  630. // Default to plain text if option not set.
  631. accept_mask = COAP_CT_MASK_PLAIN_TEXT;
  632. }
  633. // Select the first common content-type between the resource and the CoAP client.
  634. uint32_t common_ct = p_resource->ct_support_mask & accept_mask;
  635. uint32_t bit_index;
  636. for (bit_index = 0; bit_index < 32; bit_index++)
  637. {
  638. if (((common_ct >> bit_index) & 0x1 ) == 1)
  639. {
  640. break;
  641. }
  642. }
  643. uint32_t err_code = bit_to_content_format(p_ct, 1 << bit_index);
  644. return err_code;
  645. }