coap_transport_dtls.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  1. /**
  2. * Copyright (c) 2014 - 2018, 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 "nrf_error.h"
  41. #include "nrf_drv_rng.h"
  42. #include "sdk_config.h"
  43. #include "iot_common.h"
  44. #include "iot_pbuffer.h"
  45. #include "coap_transport.h"
  46. #include "coap.h"
  47. #include "udp_api.h"
  48. #include "nrf_tls.h"
  49. #include "mem_manager.h"
  50. #include "iot_errors.h"
  51. #if IOT_COAP_CONFIG_LOG_ENABLED
  52. #define NRF_LOG_MODULE_NAME coap_dtls
  53. #define NRF_LOG_LEVEL IOT_COAP_CONFIG_LOG_LEVEL
  54. #define NRF_LOG_INFO_COLOR IOT_COAP_CONFIG_INFO_COLOR
  55. #define NRF_LOG_DEBUG_COLOR IOT_COAP_CONFIG_DEBUG_COLOR
  56. #include "nrf_log.h"
  57. NRF_LOG_MODULE_REGISTER();
  58. #define COAPT_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
  59. #define COAPT_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
  60. #define COAPT_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
  61. #define COAPT_ENTRY() COAPT_TRC(">> %s", __func__)
  62. #define COAPT_EXIT() COAPT_TRC("<< %s", __func__)
  63. #define COAPT_ENTRY_WITH_READLEN(read_len) COAPT_TRC(">> %s, readlen %d", __func__, read_len)
  64. #define COAPT_EXIT_WITH_RESULT(result) COAPT_TRC("<< %s, result 0x%08lX", __func__, result)
  65. #else // IOT_COAP_CONFIG_LOG_ENABLED
  66. #define COAPT_TRC(...) /**< Disables traces. */
  67. #define COAPT_DUMP(...) /**< Disables dumping of octet streams. */
  68. #define COAPT_ERR(...) /**< Disables error logs. */
  69. #define COAPT_ENTRY(...)
  70. #define COAPT_EXIT(...)
  71. #define COAPT_ENTRY_WITH_READLEN(...)
  72. #define COAPT_EXIT_WITH_RESULT(...)
  73. #endif // IOT_COAP_CONFIG_LOG_ENABLED
  74. /**@brief Max size to be requested from the DTLS library when polling for decoded CoAP data. */
  75. #define MAX_BUFFER_SIZE 1024
  76. /**@brief UDP port information. */
  77. typedef struct
  78. {
  79. uint32_t socket_id; /**< Socket information provided by UDP. */
  80. uint16_t port_number; /**< Associated port number. */
  81. nrf_tls_key_settings_t * p_settings; /**< Key preferences. */
  82. } udp_port_t;
  83. /**@brief CoAP remote session. Encapsulates information needed for DTLS. */
  84. typedef struct
  85. {
  86. nrf_tls_instance_t dtls_instance; /**< DTLS instance identifier. */
  87. coap_remote_t remote_endpoint; /**< Remote endoint indentification. */
  88. uint16_t local_port_index; /**< Identifies local endpoint assoicated with the session. */
  89. } coap_remote_session_t;
  90. /**@brief Possible CoAP transport types. Needed for internal handling of events and data. */
  91. typedef enum
  92. {
  93. COAP_TRANSPORT_NON_SECURE_DATAGRAM = 0, /**< Non-secure transport, no DTLS procedures apply. */
  94. COAP_TRANSPORT_SECURE_DATAGRAM = 1, /**< Secure transport, DTLS procedures apply. */
  95. COAP_TRANSPORT_MAX_TYPES = 2 /**< Maximum transport types. Not a valid transport identifer used as max count. */
  96. } coap_transport_type_t;
  97. /**
  98. * @brief Transport write handler signature.
  99. *
  100. * @param[in] p_remote Remote endpoint on which data is to be written.
  101. * @param[in] local_port_index Local endpoint identifier writing the data.
  102. * @param[in] p_data Data to be written.
  103. * @param[in] datalen Length of data to be written.
  104. *
  105. * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for
  106. * failure.
  107. */
  108. typedef uint32_t (* port_write_t) (const coap_remote_t * const p_remote,
  109. uint32_t local_port_index,
  110. const uint8_t * p_data,
  111. uint16_t datalen);
  112. /**
  113. * @brief Transport read handler signature.
  114. *
  115. * @param[in] p_remote Remote endpoint which sent data.
  116. * @param[in] local_port_index Local endpoint identifier to which the data was sent.
  117. * @param[in] p_data Data read on the transport.
  118. * @param[in] datalen Length of data read on the transport.
  119. *
  120. * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for
  121. * failure.
  122. */
  123. typedef uint32_t (* port_read_t) (const coap_remote_t * const p_remote,
  124. uint32_t local_port_index,
  125. uint32_t read_result,
  126. const uint8_t * p_data,
  127. uint16_t datalen);
  128. /** Forward declaration. */
  129. uint32_t non_secure_datagram_write (const coap_remote_t * const p_remote,
  130. uint32_t local_port_index,
  131. const uint8_t * p_data,
  132. uint16_t datalen);
  133. /** Forward declaration. */
  134. uint32_t secure_datagram_write (const coap_remote_t * const p_remote,
  135. uint32_t local_port_index,
  136. const uint8_t * p_data,
  137. uint16_t datalen);
  138. /** Forward declaration. */
  139. uint32_t non_secure_datagram_read (const coap_remote_t * const p_remote,
  140. uint32_t local_port_index,
  141. uint32_t read_result,
  142. const uint8_t * p_data,
  143. uint16_t datalen);
  144. /** Forward declaration. */
  145. uint32_t secure_datagram_read(const coap_remote_t * const p_remote,
  146. uint32_t local_port_index,
  147. uint32_t read_result,
  148. const uint8_t * p_data,
  149. uint16_t datalen);
  150. /** Forward declaration. */
  151. uint32_t dtls_output_handler(nrf_tls_instance_t const * p_instance,
  152. uint8_t const * p_data,
  153. uint32_t datalen);
  154. static udp_port_t m_port_table[COAP_PORT_COUNT]; /**< Table maintaining association between CoAP ports and corresponding UDP socket identifiers. */
  155. static coap_remote_session_t m_remote_session[COAP_DTLS_MAX_REMOTE_SESSION]; /**< Table for managing security sessions with remote endpoints. */
  156. /**@brief Table of transport write handlers. */
  157. const port_write_t port_write_fn[COAP_TRANSPORT_MAX_TYPES] =
  158. {
  159. non_secure_datagram_write,
  160. secure_datagram_write
  161. };
  162. /**@brief Table of transport read handlers. */
  163. const port_read_t port_read_fn[COAP_TRANSPORT_MAX_TYPES] =
  164. {
  165. non_secure_datagram_read,
  166. secure_datagram_read
  167. };
  168. /**
  169. * @brief Searches the local port reference based on the port number.
  170. *
  171. * @param[out] p_index Pointer where local port refernce should be provided (if found).
  172. * @param[in] port_query Port number for which local port reference is requested.
  173. *
  174. * @retval NRF_SUCCESS if procedure succeeded else NRF_ERROR_NOT_FOUND.
  175. */
  176. static uint32_t local_port_index_get(uint32_t * p_index, uint16_t port_query)
  177. {
  178. uint32_t local_port_index;
  179. // Find local port index.
  180. for (local_port_index = 0; local_port_index < COAP_PORT_COUNT; local_port_index++)
  181. {
  182. if (m_port_table[local_port_index].port_number == port_query)
  183. {
  184. break;
  185. }
  186. }
  187. // If we could not find the local port requested in the port table.
  188. if (local_port_index >= COAP_PORT_COUNT)
  189. {
  190. return NRF_ERROR_NOT_FOUND;
  191. }
  192. *p_index = local_port_index;
  193. return NRF_SUCCESS;
  194. }
  195. /**
  196. * @brief Session to be initialized/freed.
  197. *
  198. * @param[in] p_session Session
  199. */
  200. static void remote_session_init(coap_remote_session_t * p_session)
  201. {
  202. memset(p_session, 0, sizeof(coap_remote_session_t));
  203. NRF_TLS_INTSANCE_INIT(&p_session->dtls_instance);
  204. }
  205. /**
  206. * @brief Creates DTLS session between remote and local endpoint.
  207. *
  208. * @param[in] local_port_index Identifies local endpoint.
  209. * @param[in] role Identifies DTLS role to be played (server or client).
  210. * @param[in] p_remote Identifies remote endpoint.
  211. * @param[in] p_settings Security settings to be used for the session.
  212. * @param[out] pp_session Pointer to the session created (if any).
  213. *
  214. * @retval NRF_SUCCESS is procedure succeeded else an error code indicating reason for failure.
  215. */
  216. static uint32_t session_create(uint32_t local_port_index,
  217. nrf_tls_role_t role,
  218. const coap_remote_t * const p_remote,
  219. nrf_tls_key_settings_t * const p_settings,
  220. coap_remote_session_t ** pp_session)
  221. {
  222. uint32_t err_code = NRF_ERROR_NO_MEM;
  223. for (uint32_t index = 0; index < COAP_DTLS_MAX_REMOTE_SESSION; index++)
  224. {
  225. if (m_remote_session[index].remote_endpoint.port_number == 0)
  226. {
  227. // Found free session.
  228. m_remote_session[index].remote_endpoint.port_number = p_remote->port_number;
  229. memcpy(m_remote_session[index].remote_endpoint.addr, p_remote->addr, IPV6_ADDR_SIZE);
  230. m_remote_session[index].local_port_index = local_port_index;
  231. // Attempt Allocate TLS session.
  232. const nrf_tls_options_t dtls_options =
  233. {
  234. .output_fn = dtls_output_handler,
  235. .transport_type = NRF_TLS_TYPE_DATAGRAM,
  236. .role = role,
  237. .p_key_settings = p_settings
  238. };
  239. m_remote_session[index].dtls_instance.transport_id = index;
  240. COAP_MUTEX_UNLOCK();
  241. err_code = nrf_tls_alloc(&m_remote_session[index].dtls_instance, &dtls_options);
  242. COAP_MUTEX_LOCK();
  243. COAPT_TRC("[%p]: nrf_tls_alloc result %08x",
  244. &m_remote_session[index],
  245. err_code);
  246. // TLS allocation succeeded, book keep information for endpoint.
  247. if (err_code == NRF_SUCCESS)
  248. {
  249. (*pp_session) = &m_remote_session[index];
  250. break;
  251. }
  252. else
  253. {
  254. // If free the session and notify failure.
  255. remote_session_init(&m_remote_session[index]);
  256. }
  257. }
  258. }
  259. return err_code;
  260. }
  261. /**
  262. * @brief API to free TLS session.
  263. *
  264. * @param[in] p_session Identifies the session to be freed.
  265. */
  266. static __INLINE void session_free (coap_remote_session_t * p_session)
  267. {
  268. // Free TLS session.
  269. UNUSED_VARIABLE(nrf_tls_free(&p_session->dtls_instance));
  270. // Free the session.
  271. remote_session_init(p_session);
  272. }
  273. /**
  274. * @brief Searches for DTLS session between remote and local endpoint.
  275. *
  276. * @param[in] local_port_index Identifies local endpoint.
  277. * @param[in] p_remote Identifies remote endpoint.
  278. * @param[out] pp_session Pointer to the session found (if any).
  279. *
  280. * @retval NRF_SUCCESS is procedure succeeded else NRF_ERROR_NOT_FOUND.
  281. */
  282. uint32_t remote_session_search(uint32_t local_port_index,
  283. const coap_remote_t * p_remote,
  284. coap_remote_session_t ** pp_session)
  285. {
  286. uint32_t err_code = NRF_ERROR_NOT_FOUND;
  287. uint32_t index = 0;
  288. for (index = 0; index < COAP_DTLS_MAX_REMOTE_SESSION; index++)
  289. {
  290. const coap_remote_session_t * session = &m_remote_session[index];
  291. if ((session->local_port_index == local_port_index) &&
  292. (session->remote_endpoint.port_number == p_remote->port_number) &&
  293. ((memcmp(session->remote_endpoint.addr, p_remote->addr, IPV6_ADDR_SIZE) == 0)))
  294. {
  295. // Entry exists.
  296. (*pp_session) = (coap_remote_session_t *)session;
  297. err_code = NRF_SUCCESS;
  298. break;
  299. }
  300. }
  301. return err_code;
  302. }
  303. /**
  304. * @brief Provides transport type to be used between remote and local endpoint.
  305. *
  306. * @param[in] local_port_index Identifies local endpoint.
  307. * @param[in] p_remote Identifies remote endpoint.
  308. *
  309. * @retval COAP_TRANSPORT_SECURE_DATAGRAM if transport type to be used is secure.
  310. * @retval COAP_TRANSPORT_NON_SECURE_DATAGRAM if transport type to be used is non-secure.
  311. */
  312. uint8_t get_transport_type(uint32_t local_port_index, const coap_remote_t * p_remote)
  313. {
  314. coap_remote_session_t * p_session;
  315. uint8_t transport_type = COAP_TRANSPORT_NON_SECURE_DATAGRAM;
  316. uint32_t err_code = remote_session_search(local_port_index, p_remote, &p_session);
  317. if (err_code == NRF_SUCCESS)
  318. {
  319. COAPT_TRC("Transport type = SECURE");
  320. transport_type = COAP_TRANSPORT_SECURE_DATAGRAM;
  321. }
  322. else if (m_port_table[local_port_index].p_settings != NULL)
  323. {
  324. COAPT_TRC("Transport type = SECURE");
  325. transport_type = COAP_TRANSPORT_SECURE_DATAGRAM;
  326. }
  327. else
  328. {
  329. COAPT_TRC("Transport type = NON-SECURE");
  330. }
  331. return transport_type;
  332. }
  333. /**@brief Callback handler to receive data on the UDP port.
  334. *
  335. * @details Callback handler to receive data on the UDP port.
  336. *
  337. * @param[in] p_socket Socket identifier.
  338. * @param[in] p_ip_header IPv6 header containing source and destination addresses.
  339. * @param[in] p_udp_header UDP header identifying local and remote endpoints.
  340. * @param[in] process_result Result of data reception, there could be possible errors like
  341. * invalid checksum etc.
  342. * @param[in] iot_pbuffer_t Packet buffer containing the received data packet.
  343. *
  344. * @retval NRF_SUCCESS Indicates received data was handled successfully, else an an
  345. * error code indicating reason for failure..
  346. */
  347. static uint32_t port_data_callback(const udp6_socket_t * p_socket,
  348. const ipv6_header_t * p_ip_header,
  349. const udp6_header_t * p_udp_header,
  350. uint32_t process_result,
  351. iot_pbuffer_t * p_rx_packet)
  352. {
  353. uint32_t index;
  354. uint32_t retval = NRF_ERROR_NOT_FOUND;
  355. COAPT_TRC("port_data_callback: Src Port %d Dest Port %d. Len %08lx",
  356. p_udp_header->srcport, p_udp_header->destport, p_rx_packet->length);
  357. COAP_MUTEX_LOCK();
  358. //Search for the port.
  359. for (index = 0; index < COAP_PORT_COUNT; index++)
  360. {
  361. if (m_port_table[index].socket_id == p_socket->socket_id)
  362. {
  363. COAPT_TRC("port_data_callback->coap_transport_read");
  364. //Matching port found.
  365. coap_remote_t remote_endpoint;
  366. memcpy(remote_endpoint.addr, p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE);
  367. remote_endpoint.port_number = p_udp_header->srcport;
  368. uint8_t transport_type = get_transport_type(index, &remote_endpoint);
  369. // Handle read data on scoket based on nature of transport.
  370. retval = port_read_fn[transport_type](&remote_endpoint,
  371. index,
  372. process_result,
  373. p_rx_packet->p_payload,
  374. p_rx_packet->length);
  375. break;
  376. }
  377. }
  378. COAP_MUTEX_UNLOCK();
  379. return retval;
  380. }
  381. /**
  382. * @brief Transport read handler for non secure transport type.
  383. *
  384. * @param[in] p_remote Remote endpoint which sent data.
  385. * @param[in] local_port_index Local endpoint identifier to which the data was sent.
  386. * @param[in] read_result Indicator result of data read on the transport.
  387. * Likely failures include UDP checksum failure, truncated packet etc.
  388. * @param[in] p_data Data read on the transport.
  389. * @param[in] datalen Length of data read on the transport.
  390. *
  391. * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for
  392. * failure.
  393. */
  394. uint32_t non_secure_datagram_read (const coap_remote_t * const p_remote,
  395. uint32_t local_port_index,
  396. uint32_t read_result,
  397. const uint8_t * p_data,
  398. uint16_t datalen)
  399. {
  400. const coap_port_t port =
  401. {
  402. .port_number = m_port_table[local_port_index].port_number
  403. };
  404. return coap_transport_read(&port,
  405. p_remote,
  406. NULL,
  407. read_result,
  408. p_data,
  409. datalen);
  410. }
  411. /**
  412. * @brief Transport write handler for non secure transport type.
  413. *
  414. * @param[in] p_remote Remote endpoint on which data is to be written.
  415. * @param[in] local_port_index Local endpoint identifier writing the data.
  416. * @param[in] p_data Data to be written.
  417. * @param[in] datalen Length of data to be written.
  418. *
  419. * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for
  420. * failure.
  421. */
  422. uint32_t non_secure_datagram_write(const coap_remote_t * p_remote,
  423. uint32_t index,
  424. const uint8_t * p_data,
  425. uint16_t datalen)
  426. {
  427. uint32_t err_code;
  428. udp6_socket_t socket;
  429. ipv6_addr_t remote_addr;
  430. iot_pbuffer_t * p_buffer;
  431. iot_pbuffer_alloc_param_t buffer_param;
  432. buffer_param.type = UDP6_PACKET_TYPE;
  433. buffer_param.flags = PBUFFER_FLAG_DEFAULT;
  434. buffer_param.length = datalen;
  435. COAPT_TRC("[LP %04X]:[RP %04X]: port_write, datalen %d",
  436. m_port_table[index].port_number,
  437. p_remote->port_number,
  438. datalen);
  439. memcpy(remote_addr.u8, p_remote->addr, IPV6_ADDR_SIZE);
  440. // Allocate buffer to send the data on port.
  441. err_code = iot_pbuffer_allocate(&buffer_param, &p_buffer);
  442. COAPT_TRC("port_write->iot_pbuffer_allocate result 0x%08X", err_code);
  443. if (err_code == NRF_SUCCESS)
  444. {
  445. socket.socket_id = m_port_table[index].socket_id;
  446. // Make a copy of the data onto the buffer.
  447. memcpy(p_buffer->p_payload, p_data, datalen);
  448. // Send on UDP port.
  449. err_code = udp6_socket_sendto(&socket,
  450. &remote_addr,
  451. p_remote->port_number,
  452. p_buffer);
  453. COAPT_TRC("port_write->udp6_socket_sendto result 0x%08X", err_code);
  454. if (err_code != NRF_SUCCESS)
  455. {
  456. // Free the allocated buffer as send procedure has failed.
  457. UNUSED_VARIABLE(iot_pbuffer_free(p_buffer, true));
  458. }
  459. }
  460. return err_code;
  461. }
  462. /**
  463. * @brief Transport read handler for secure transport type.
  464. *
  465. * @param[in] p_remote Remote endpoint which sent data.
  466. * @param[in] local_port_index Local endpoint identifier to which the data was sent.
  467. * @param[in] read_result Indicator result of data read on the transport.
  468. * Likely failures include UDP checksum failure, truncated packet etc.
  469. * @param[in] p_data Data read on the transport.
  470. * @param[in] datalen Length of data read on the transport.
  471. *
  472. * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for
  473. * failure.
  474. */
  475. uint32_t secure_datagram_read(const coap_remote_t * const p_remote,
  476. uint32_t local_port_index,
  477. uint32_t read_result,
  478. const uint8_t * p_data,
  479. uint16_t datalen)
  480. {
  481. const uint32_t read_len = datalen;
  482. uint32_t err_code;
  483. coap_remote_session_t * p_session = NULL;
  484. COAPT_ENTRY_WITH_READLEN(read_len);
  485. // Search is a session exists.
  486. err_code = remote_session_search(local_port_index, p_remote, &p_session);
  487. if (err_code == NRF_SUCCESS)
  488. {
  489. COAPT_TRC("Remote session found, processing.");
  490. COAP_MUTEX_UNLOCK();
  491. // Session exists, send data to DTLS for decryption.
  492. err_code = nrf_tls_input(&p_session->dtls_instance, p_data, read_len);
  493. COAP_MUTEX_LOCK();
  494. }
  495. else
  496. {
  497. COAPT_TRC("Remote session not found, look for server security settings.");
  498. if (m_port_table[local_port_index].p_settings != NULL)
  499. {
  500. // Allocate a session for incoming client.
  501. err_code = session_create(local_port_index,
  502. NRF_TLS_ROLE_SERVER,
  503. p_remote,
  504. m_port_table[local_port_index].p_settings,
  505. &p_session);
  506. if (err_code == NRF_SUCCESS)
  507. {
  508. COAP_MUTEX_UNLOCK();
  509. COAPT_TRC("[%p]: New session created as DTLS server.", p_session);
  510. err_code = nrf_tls_input(&p_session->dtls_instance, p_data, read_len);
  511. COAP_MUTEX_LOCK();
  512. }
  513. else
  514. {
  515. COAPT_TRC("New session creation failed, reason 0x%08x.", err_code);
  516. }
  517. }
  518. else
  519. {
  520. COAPT_TRC("No remote session, no server settings, processing as raw");
  521. err_code = non_secure_datagram_read(p_remote,
  522. local_port_index,
  523. read_result,
  524. p_data,
  525. datalen);
  526. }
  527. }
  528. COAPT_EXIT_WITH_RESULT(err_code);
  529. return err_code;
  530. }
  531. /**
  532. * @brief Transport write handler for secure transport type.
  533. *
  534. * @param[in] p_remote Remote endpoint on which data is to be written.
  535. * @param[in] local_port_index Local endpoint identifier writing the data.
  536. * @param[in] p_data Data to be written.
  537. * @param[in] datalen Length of data to be written.
  538. *
  539. * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for
  540. * failure.
  541. */
  542. uint32_t secure_datagram_write(const coap_remote_t * const p_remote,
  543. uint32_t local_port_index,
  544. const uint8_t * p_data,
  545. uint16_t datalen)
  546. {
  547. uint32_t err_code;
  548. coap_remote_session_t * p_session;
  549. // Search is a session exists.
  550. err_code = remote_session_search(local_port_index, p_remote, &p_session);
  551. if (err_code == NRF_ERROR_NOT_FOUND)
  552. {
  553. // No session found, return error.
  554. err_code = COAP_TRANSPORT_SECURITY_MISSING;
  555. }
  556. else
  557. {
  558. // Session exists, attempt a secure write.
  559. uint32_t actual_len = datalen;
  560. err_code = nrf_tls_write(&p_session->dtls_instance, p_data, &actual_len);
  561. }
  562. return err_code;
  563. }
  564. /**
  565. * @brief Handles DTLS output to be sent on the underlying UDP transport.
  566. *
  567. * @param[in] p_instance Identifies the TLS instance associated with the output.
  568. * @param[in] p_data DTLS library output data to be written on the transport.
  569. * @param[in] datalen Length of data.
  570. *
  571. * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for
  572. * failure.
  573. */
  574. uint32_t dtls_output_handler(nrf_tls_instance_t const * p_instance,
  575. uint8_t const * p_data,
  576. uint32_t datalen)
  577. {
  578. const uint16_t transport_write_len = datalen;
  579. if (p_instance->transport_id >= COAP_DTLS_MAX_REMOTE_SESSION)
  580. {
  581. return NRF_ERROR_NOT_FOUND;
  582. }
  583. COAP_MUTEX_LOCK();
  584. coap_remote_session_t * p_session = &m_remote_session[p_instance->transport_id];
  585. uint32_t err_code = NRF_ERROR_NOT_FOUND;
  586. if (p_session->remote_endpoint.port_number != 0)
  587. {
  588. // Search for instance in remote sessions.
  589. err_code = non_secure_datagram_write(&p_session->remote_endpoint,
  590. p_session->local_port_index,
  591. p_data,
  592. transport_write_len);
  593. }
  594. COAP_MUTEX_UNLOCK();
  595. return err_code;
  596. }
  597. /**@brief Creates port as requested in p_port.
  598. *
  599. * @details Creates port as requested in p_port.
  600. *
  601. * @param[in] index Index to the m_port_table where entry of the port created is to be made.
  602. * @param[in] p_port Port information to be created.
  603. *
  604. * @retval NRF_SUCCESS Indicates if port was created successfully, else an an error code
  605. * indicating reason for failure.
  606. */
  607. static uint32_t port_create(uint32_t index, coap_port_t * p_port)
  608. {
  609. uint32_t err_code;
  610. udp6_socket_t socket;
  611. // Request new socket creation.
  612. err_code = udp6_socket_allocate(&socket);
  613. if (err_code == NRF_SUCCESS)
  614. {
  615. // Bind the socket to the local port.
  616. err_code = udp6_socket_bind(&socket, IPV6_ADDR_ANY, p_port->port_number);
  617. if (err_code == NRF_SUCCESS)
  618. {
  619. // Register data receive callback.
  620. err_code = udp6_socket_recv(&socket, port_data_callback);
  621. if (err_code == NRF_SUCCESS)
  622. {
  623. // All procedure with respect to port creation succeeded, make entry in the table.
  624. m_port_table[index].socket_id = socket.socket_id;
  625. m_port_table[index].port_number = p_port->port_number;
  626. m_port_table[index].p_settings = NULL;
  627. socket.p_app_data = &m_port_table[index];
  628. UNUSED_VARIABLE(udp6_socket_app_data_set(&socket));
  629. }
  630. }
  631. if (err_code != NRF_SUCCESS)
  632. {
  633. // Not all procedures succeeded with allocated socket, hence free it.
  634. UNUSED_VARIABLE(udp6_socket_free(&socket));
  635. }
  636. }
  637. return err_code;
  638. }
  639. uint32_t coap_transport_init(const coap_transport_init_t * p_param)
  640. {
  641. uint32_t err_code = NRF_ERROR_NO_MEM;
  642. uint32_t index;
  643. NULL_PARAM_CHECK(p_param);
  644. NULL_PARAM_CHECK(p_param->p_port_table);
  645. err_code = nrf_tls_init();
  646. if (err_code == NRF_SUCCESS)
  647. {
  648. for (index = 0; index < COAP_PORT_COUNT; index++)
  649. {
  650. // Create end point for each of the CoAP ports.
  651. err_code = port_create(index, &p_param->p_port_table[index]);
  652. if (err_code != NRF_SUCCESS)
  653. {
  654. break;
  655. }
  656. }
  657. for (index = 0; index < COAP_DTLS_MAX_REMOTE_SESSION; index++)
  658. {
  659. remote_session_init(&m_remote_session[index]);
  660. }
  661. }
  662. return err_code;
  663. }
  664. uint32_t coap_transport_write(const coap_port_t * p_port,
  665. const coap_remote_t * p_remote,
  666. const uint8_t * p_data,
  667. uint16_t datalen)
  668. {
  669. uint32_t err_code = NRF_ERROR_NOT_FOUND;
  670. uint32_t index;
  671. NULL_PARAM_CHECK(p_port);
  672. NULL_PARAM_CHECK(p_remote);
  673. NULL_PARAM_CHECK(p_data);
  674. COAP_MUTEX_LOCK();
  675. //Search for the corresponding port.
  676. for (index = 0; index < COAP_PORT_COUNT; index++)
  677. {
  678. if (m_port_table[index].port_number == p_port->port_number)
  679. {
  680. // Get transport type for remote and local.
  681. uint8_t transport_type = get_transport_type(index, p_remote);
  682. err_code = port_write_fn[transport_type](p_remote,
  683. index,
  684. p_data,
  685. datalen);
  686. break;
  687. }
  688. }
  689. COAP_MUTEX_UNLOCK();
  690. return err_code;
  691. }
  692. void coap_transport_process(void)
  693. {
  694. nrf_tls_process();
  695. for (uint32_t index = 0; index < COAP_DTLS_MAX_REMOTE_SESSION; index++)
  696. {
  697. coap_remote_session_t * p_session = &m_remote_session[index];
  698. if (p_session->remote_endpoint.port_number != 0x0000)
  699. {
  700. uint32_t datalen = MAX_BUFFER_SIZE;
  701. COAP_MUTEX_UNLOCK();
  702. // Check if there is data to be processed/read.
  703. uint32_t err_code = nrf_tls_read(&p_session->dtls_instance, NULL, &datalen);
  704. COAP_MUTEX_LOCK();
  705. COAPT_TRC("nrf_tls_read result %d", err_code);
  706. if ((err_code == NRF_SUCCESS) && (datalen > 0))
  707. {
  708. COAPT_TRC("nrf_tls_read datalen %d", datalen);
  709. // Allocate memory and fecth data from DTLS layer.
  710. uint8_t * p_data = NULL;
  711. uint32_t buffer_size = datalen;
  712. err_code = nrf_mem_reserve(&p_data, &buffer_size);
  713. if (p_data != NULL)
  714. {
  715. COAP_MUTEX_UNLOCK();
  716. err_code = nrf_tls_read(&p_session->dtls_instance, p_data, &datalen);
  717. COAP_MUTEX_LOCK();
  718. if ((err_code == NRF_SUCCESS) && (datalen > 0))
  719. {
  720. UNUSED_VARIABLE(non_secure_datagram_read(&p_session->remote_endpoint,
  721. p_session->local_port_index,
  722. NRF_SUCCESS,
  723. p_data,
  724. datalen));
  725. }
  726. // Free the memory reserved for the incoming packet.
  727. nrf_free(p_data);
  728. }
  729. }
  730. }
  731. }
  732. }
  733. uint32_t coap_security_setup(uint16_t local_port,
  734. nrf_tls_role_t role,
  735. coap_remote_t * const p_remote,
  736. nrf_tls_key_settings_t * const p_settings)
  737. {
  738. uint32_t err_code = NRF_ERROR_NO_MEM;
  739. uint32_t local_port_index;
  740. coap_remote_session_t * p_session;
  741. COAP_MUTEX_LOCK();
  742. // Find local port index.
  743. err_code = local_port_index_get(&local_port_index, local_port);
  744. if (err_code == NRF_SUCCESS)
  745. {
  746. if (role == NRF_TLS_ROLE_CLIENT)
  747. {
  748. if (p_remote == NULL)
  749. {
  750. // Clients can never register session with wildcard remote.
  751. err_code = NRF_ERROR_NULL;
  752. }
  753. else
  754. {
  755. // Search is a session exists.
  756. err_code = remote_session_search(local_port_index, p_remote, &p_session);
  757. if (err_code != NRF_SUCCESS)
  758. {
  759. // Session does not already exist, create one.
  760. err_code = session_create(local_port_index,
  761. role, p_remote,
  762. p_settings,
  763. &p_session);
  764. }
  765. }
  766. }
  767. else
  768. {
  769. // For server role, disallow client specific settings.
  770. // This may not always be desired. But a constraint added in current design.
  771. if (p_remote != NULL)
  772. {
  773. err_code = NRF_ERROR_INVALID_PARAM;
  774. }
  775. else
  776. {
  777. // Cannot overwrite settings.
  778. if (m_port_table[local_port_index].p_settings != NULL)
  779. {
  780. err_code = NRF_ERROR_FORBIDDEN;
  781. }
  782. else
  783. {
  784. COAPT_TRC("[0x%08lx]: Server security setup successful",
  785. local_port_index);
  786. m_port_table[local_port_index].p_settings = p_settings;
  787. }
  788. }
  789. }
  790. }
  791. COAP_MUTEX_UNLOCK();
  792. return err_code;
  793. }
  794. uint32_t coap_security_destroy(uint16_t local_port,
  795. coap_remote_t * const p_remote)
  796. {
  797. uint32_t err_code;
  798. coap_remote_session_t * p_session;
  799. uint32_t local_port_index;
  800. COAP_MUTEX_LOCK();
  801. // Find local port index.
  802. err_code = local_port_index_get(&local_port_index, local_port);
  803. if (err_code == NRF_SUCCESS)
  804. {
  805. if (p_remote != NULL)
  806. {
  807. // Search is a session exists.
  808. err_code = remote_session_search(local_port_index, p_remote, &p_session);
  809. if (err_code == NRF_SUCCESS)
  810. {
  811. session_free(p_session);
  812. }
  813. }
  814. else
  815. {
  816. // Remove all session associated with the local port if p_remote is NULL.
  817. for (uint32_t index = 0; index < COAP_DTLS_MAX_REMOTE_SESSION ; index++)
  818. {
  819. if (m_remote_session[index].local_port_index == local_port_index)
  820. {
  821. session_free(&m_remote_session[index]);
  822. }
  823. }
  824. }
  825. }
  826. COAP_MUTEX_UNLOCK();
  827. return err_code;
  828. }