1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12 #include <stdio.h>
13 #include <stdarg.h>
14
15 #include "nx_azure_iot.h"
16 #include "azure/core/internal/az_log_internal.h"
17
18 #ifndef NX_AZURE_DISABLE_IOT_SECURITY_MODULE
19 #include "nx_azure_iot_security_module.h"
20 #endif /* NX_AZURE_DISABLE_IOT_SECURITY_MODULE */
21
22 #ifndef NX_AZURE_IOT_WAIT_OPTION
23 #define NX_AZURE_IOT_WAIT_OPTION NX_WAIT_FOREVER
24 #endif /* NX_AZURE_IOT_WAIT_OPTION */
25
26 /* Convert number to upper hex. */
27 #define NX_AZURE_IOT_NUMBER_TO_UPPER_HEX(number) (CHAR)(number + (number < 10 ? '0' : 'A' - 10))
28
29 /* Define the prototypes for Azure RTOS IoT. */
30 NX_AZURE_IOT *_nx_azure_iot_created_ptr;
31
32 /* Define the callback for logging. */
33 static VOID(*_nx_azure_iot_log_callback)(az_log_classification classification, UCHAR *msg, UINT msg_len);
34
35 extern UINT _nxd_mqtt_client_packet_allocate(NXD_MQTT_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option);
36 extern UINT _nxd_mqtt_client_publish_packet_send(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr,
37 USHORT packet_id, UINT QoS, ULONG wait_option);
38
nx_azure_iot_event_process(VOID * nx_azure_iot,ULONG common_events,ULONG module_own_events)39 static VOID nx_azure_iot_event_process(VOID *nx_azure_iot, ULONG common_events, ULONG module_own_events)
40 {
41
42 NX_AZURE_IOT *nx_azure_iot_ptr = (NX_AZURE_IOT *)nx_azure_iot;
43
44 /* Process DPS events. */
45 if (nx_azure_iot_ptr -> nx_azure_iot_provisioning_client_event_process)
46 {
47 nx_azure_iot_ptr -> nx_azure_iot_provisioning_client_event_process(nx_azure_iot_ptr, common_events,
48 module_own_events);
49 }
50 }
51
nx_azure_iot_publish_packet_header_add(NX_PACKET * packet_ptr,UINT topic_len,UINT qos)52 static UINT nx_azure_iot_publish_packet_header_add(NX_PACKET* packet_ptr, UINT topic_len, UINT qos)
53 {
54 UCHAR *buffer_ptr;
55 UINT length;
56
57 /* Check if packet has enough space to write MQTT header. */
58 if (NX_AZURE_IOT_PUBLISH_PACKET_START_OFFSET >
59 (packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start))
60 {
61 return(NX_AZURE_IOT_INVALID_PACKET);
62 }
63
64 /* Start to fill MQTT header. */
65 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr - NX_AZURE_IOT_PUBLISH_PACKET_START_OFFSET;
66
67 /* Set flags. */
68 buffer_ptr[0] = (UCHAR)(MQTT_CONTROL_PACKET_TYPE_PUBLISH << 4);
69 if (qos == NX_AZURE_IOT_MQTT_QOS_1)
70 {
71 buffer_ptr[0] |= MQTT_PUBLISH_QOS_LEVEL_1;
72 }
73
74 /* Set topic length. */
75 buffer_ptr[5] = (UCHAR)(topic_len >> 8);
76 buffer_ptr[6] = (UCHAR)(topic_len & 0xFF);
77
78 /* Set total length.
79 * 2 bytes for topic length.
80 * 2 bytes for packet id.
81 * data_size for payload.
82 *
83 * packet already contains topic length, packet id (optional) and data payload
84 */
85 length = packet_ptr -> nx_packet_length + 2;
86
87 /* Total length is encoded in fixed four bytes format. */
88 buffer_ptr[1] = (UCHAR)((length & 0x7F) | 0x80);
89 length >>= 7;
90 buffer_ptr[2] = (UCHAR)((length & 0x7F) | 0x80);
91 length >>= 7;
92 buffer_ptr[3] = (UCHAR)((length & 0x7F) | 0x80);
93 length >>= 7;
94 buffer_ptr[4] = (UCHAR)(length & 0x7F);
95
96 /* Update packet. */
97 packet_ptr -> nx_packet_prepend_ptr = buffer_ptr;
98 packet_ptr -> nx_packet_length += NX_AZURE_IOT_PUBLISH_PACKET_START_OFFSET;
99
100 return(NX_AZURE_IOT_SUCCESS);
101 }
102
nx_azure_iot_log(UCHAR * type_ptr,UINT type_len,UCHAR * msg_ptr,UINT msg_len,...)103 UINT nx_azure_iot_log(UCHAR *type_ptr, UINT type_len, UCHAR *msg_ptr, UINT msg_len, ...)
104 {
105 va_list ap;
106 UCHAR buffer[10] = { 0 };
107 az_span span;
108 az_span num_span;
109
110 span = az_span_create(type_ptr, (INT)type_len);
111 _az_LOG_WRITE(AZ_LOG_IOT_AZURERTOS, span);
112
113 if (msg_len >= 2 && (msg_ptr[msg_len - 2] == '%') &&
114 ((msg_ptr[msg_len - 1] == 'd') || (msg_ptr[msg_len - 1] == 's')))
115 {
116 span = az_span_create((UCHAR *)msg_ptr, (INT)(msg_len - 2));
117 _az_LOG_WRITE(AZ_LOG_IOT_AZURERTOS, span);
118
119 va_start(ap, msg_len);
120
121 /* Handles %d */
122 if (msg_ptr[msg_len - 1] == 'd')
123 {
124 num_span = az_span_create(buffer, sizeof(buffer));
125 if (!az_result_failed(az_span_u32toa(num_span, va_arg(ap, UINT), &span)))
126 {
127 num_span = az_span_slice(num_span, 0, (INT)sizeof(buffer) - az_span_size(span));
128 _az_LOG_WRITE(AZ_LOG_IOT_AZURERTOS, num_span);
129 }
130 }
131
132 /* Handles %s */
133 if (msg_ptr[msg_len - 1] == 's')
134 {
135 msg_ptr = va_arg(ap, UCHAR*);
136 msg_len = va_arg(ap, UINT);
137 span = az_span_create((UCHAR *)msg_ptr, (INT)msg_len);
138 _az_LOG_WRITE(AZ_LOG_IOT_AZURERTOS, span);
139 }
140
141 va_end(ap);
142 }
143 else
144 {
145 span = az_span_create((UCHAR *)msg_ptr, (INT)msg_len);
146 _az_LOG_WRITE(AZ_LOG_IOT_AZURERTOS, span);
147 }
148
149 _az_LOG_WRITE(AZ_LOG_IOT_AZURERTOS, AZ_SPAN_FROM_STR("\r\n"));
150
151 return(NX_AZURE_IOT_SUCCESS);
152 }
153
nx_azure_iot_log_listener(az_log_classification classification,az_span message)154 static VOID nx_azure_iot_log_listener(az_log_classification classification, az_span message)
155 {
156 NX_PARAMETER_NOT_USED(classification);
157
158 if (_nx_azure_iot_log_callback != NX_NULL)
159 {
160 _nx_azure_iot_log_callback(classification, az_span_ptr(message), (UINT)az_span_size(message));
161 }
162 }
163
nx_azure_iot_log_init(VOID (* log_callback)(az_log_classification classification,UCHAR * msg,UINT msg_len))164 VOID nx_azure_iot_log_init(VOID(*log_callback)(az_log_classification classification, UCHAR *msg, UINT msg_len))
165 {
166 _nx_azure_iot_log_callback = log_callback;
167 az_log_set_message_callback(nx_azure_iot_log_listener);
168 }
169
nx_azure_iot_resource_search(NXD_MQTT_CLIENT * client_ptr)170 NX_AZURE_IOT_RESOURCE *nx_azure_iot_resource_search(NXD_MQTT_CLIENT *client_ptr)
171 {
172 NX_AZURE_IOT_RESOURCE *resource_ptr;
173
174 /* Check if created Azure RTOS IoT. */
175 if ((_nx_azure_iot_created_ptr == NX_NULL) || (client_ptr == NX_NULL))
176 {
177 return(NX_NULL);
178 }
179
180 /* Loop to find the resource associated with current MQTT client. */
181 for (resource_ptr = _nx_azure_iot_created_ptr -> nx_azure_iot_resource_list_header;
182 resource_ptr; resource_ptr = resource_ptr -> resource_next)
183 {
184
185 if (&(resource_ptr -> resource_mqtt) == client_ptr)
186 {
187 return(resource_ptr);
188 }
189 }
190
191 return(NX_NULL);
192 }
193
nx_azure_iot_resource_add(NX_AZURE_IOT * nx_azure_iot_ptr,NX_AZURE_IOT_RESOURCE * resource_ptr)194 UINT nx_azure_iot_resource_add(NX_AZURE_IOT *nx_azure_iot_ptr, NX_AZURE_IOT_RESOURCE *resource_ptr)
195 {
196
197 resource_ptr -> resource_next = nx_azure_iot_ptr -> nx_azure_iot_resource_list_header;
198 nx_azure_iot_ptr -> nx_azure_iot_resource_list_header = resource_ptr;
199
200 return(NX_AZURE_IOT_SUCCESS);
201 }
202
nx_azure_iot_resource_remove(NX_AZURE_IOT * nx_azure_iot_ptr,NX_AZURE_IOT_RESOURCE * resource_ptr)203 UINT nx_azure_iot_resource_remove(NX_AZURE_IOT *nx_azure_iot_ptr, NX_AZURE_IOT_RESOURCE *resource_ptr)
204 {
205
206 NX_AZURE_IOT_RESOURCE *resource_previous;
207
208 if (nx_azure_iot_ptr -> nx_azure_iot_resource_list_header == NX_NULL)
209 {
210 return(NX_AZURE_IOT_NOT_FOUND);
211 }
212
213 if (nx_azure_iot_ptr -> nx_azure_iot_resource_list_header == resource_ptr)
214 {
215 nx_azure_iot_ptr -> nx_azure_iot_resource_list_header = nx_azure_iot_ptr -> nx_azure_iot_resource_list_header -> resource_next;
216 return(NX_AZURE_IOT_SUCCESS);
217 }
218
219 for (resource_previous = nx_azure_iot_ptr -> nx_azure_iot_resource_list_header;
220 resource_previous -> resource_next;
221 resource_previous = resource_previous -> resource_next)
222 {
223 if (resource_previous -> resource_next == resource_ptr)
224 {
225 resource_previous -> resource_next = resource_previous -> resource_next -> resource_next;
226 return(NX_AZURE_IOT_SUCCESS);
227 }
228 }
229
230 return(NX_AZURE_IOT_NOT_FOUND);
231 }
232
nx_azure_iot_create(NX_AZURE_IOT * nx_azure_iot_ptr,const UCHAR * name_ptr,NX_IP * ip_ptr,NX_PACKET_POOL * pool_ptr,NX_DNS * dns_ptr,VOID * stack_memory_ptr,UINT stack_memory_size,UINT priority,UINT (* unix_time_callback)(ULONG * unix_time))233 UINT nx_azure_iot_create(NX_AZURE_IOT *nx_azure_iot_ptr, const UCHAR *name_ptr,
234 NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, NX_DNS *dns_ptr,
235 VOID *stack_memory_ptr, UINT stack_memory_size,
236 UINT priority, UINT (*unix_time_callback)(ULONG *unix_time))
237 {
238 UINT status;
239
240 if ((nx_azure_iot_ptr == NX_NULL) || (ip_ptr == NX_NULL) ||
241 (pool_ptr == NX_NULL) || (dns_ptr == NX_NULL))
242 {
243 LogError(LogLiteralArgs("IoT create fail: INVALID POINTER"));
244 return(NX_AZURE_IOT_INVALID_PARAMETER);
245 }
246
247 nx_azure_iot_ptr -> nx_azure_iot_name = name_ptr;
248 nx_azure_iot_ptr -> nx_azure_iot_ip_ptr = ip_ptr;
249 nx_azure_iot_ptr -> nx_azure_iot_dns_ptr = dns_ptr;
250 nx_azure_iot_ptr -> nx_azure_iot_pool_ptr = pool_ptr;
251 nx_azure_iot_ptr -> nx_azure_iot_unix_time_get = unix_time_callback;
252
253 status = nx_cloud_create(&nx_azure_iot_ptr -> nx_azure_iot_cloud, (CHAR *)name_ptr, stack_memory_ptr,
254 stack_memory_size, priority);
255 if (status)
256 {
257 LogError(LogLiteralArgs("IoT create fail status: %d"), status);
258 return(status);
259 }
260
261 /* Register SDK module on cloud helper. */
262 status = nx_cloud_module_register(&(nx_azure_iot_ptr -> nx_azure_iot_cloud), &(nx_azure_iot_ptr -> nx_azure_iot_cloud_module),
263 "Azure SDK Module", NX_CLOUD_MODULE_AZURE_SDK_EVENT | NX_CLOUD_COMMON_PERIODIC_EVENT,
264 nx_azure_iot_event_process, nx_azure_iot_ptr);
265 if (status)
266 {
267 LogError(LogLiteralArgs("IoT module register fail status: %d"), status);
268 return(status);
269 }
270
271 /* Set the mutex. */
272 nx_azure_iot_ptr -> nx_azure_iot_mutex_ptr = &(nx_azure_iot_ptr -> nx_azure_iot_cloud.nx_cloud_mutex);
273
274 /* Set created IoT pointer. */
275 _nx_azure_iot_created_ptr = nx_azure_iot_ptr;
276
277 #ifndef NX_AZURE_DISABLE_IOT_SECURITY_MODULE
278 /* Enable Azure IoT Security Module. */
279 status = nx_azure_iot_security_module_enable(nx_azure_iot_ptr);
280 if (status)
281 {
282 LogError(LogLiteralArgs("IoT failed to enable IoT Security Module, status: %d"), status);
283 nx_azure_iot_delete(nx_azure_iot_ptr);
284 return(status);
285 }
286 #endif /* NX_AZURE_DISABLE_IOT_SECURITY_MODULE */
287
288 return(NX_AZURE_IOT_SUCCESS);
289 }
290
nx_azure_iot_delete(NX_AZURE_IOT * nx_azure_iot_ptr)291 UINT nx_azure_iot_delete(NX_AZURE_IOT *nx_azure_iot_ptr)
292 {
293 UINT status;
294
295 if (nx_azure_iot_ptr == NX_NULL)
296 {
297 LogError(LogLiteralArgs("IoT delete fail: INVALID POINTER"));
298 return(NX_AZURE_IOT_INVALID_PARAMETER);
299 }
300
301 if (nx_azure_iot_ptr -> nx_azure_iot_resource_list_header)
302 {
303 LogError(LogLiteralArgs("IoT delete fail: Resource NOT DELETED"));
304 return(NX_AZURE_IOT_DELETE_ERROR);
305 }
306
307 #ifndef NX_AZURE_DISABLE_IOT_SECURITY_MODULE
308 /* Disable IoT Security Module. */
309 status = nx_azure_iot_security_module_disable(nx_azure_iot_ptr);
310 if (status != NX_AZURE_IOT_SUCCESS)
311 {
312 LogError(LogLiteralArgs("IoT failed to disable IoT Security Module, status: %d"), status);
313 return(status);
314 }
315 #endif /* NX_AZURE_DISABLE_IOT_SECURITY_MODULE */
316
317 /* Deregister SDK module on cloud helper. */
318 nx_cloud_module_deregister(&(nx_azure_iot_ptr -> nx_azure_iot_cloud), &(nx_azure_iot_ptr -> nx_azure_iot_cloud_module));
319
320 /* Delete cloud. */
321 status = nx_cloud_delete(&nx_azure_iot_ptr -> nx_azure_iot_cloud);
322 if (status)
323 {
324 LogError(LogLiteralArgs("IoT delete fail status: %d"), status);
325 return(status);
326 }
327
328 _nx_azure_iot_created_ptr = NX_NULL;
329
330 return(NX_AZURE_IOT_SUCCESS);
331 }
332
nx_azure_iot_buffer_allocate(NX_AZURE_IOT * nx_azure_iot_ptr,UCHAR ** buffer_pptr,UINT * buffer_size,VOID ** buffer_context)333 UINT nx_azure_iot_buffer_allocate(NX_AZURE_IOT *nx_azure_iot_ptr, UCHAR **buffer_pptr,
334 UINT *buffer_size, VOID **buffer_context)
335 {
336 NX_PACKET *packet_ptr;
337 UINT status;
338
339 status = nx_packet_allocate(nx_azure_iot_ptr -> nx_azure_iot_pool_ptr,
340 &packet_ptr, 0, NX_AZURE_IOT_WAIT_OPTION);
341 if (status)
342 {
343 return(status);
344 }
345
346 *buffer_pptr = packet_ptr -> nx_packet_data_start;
347 *buffer_size = (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_data_start);
348 *buffer_context = (VOID *)packet_ptr;
349 return(NX_AZURE_IOT_SUCCESS);
350 }
351
nx_azure_iot_buffer_free(VOID * buffer_context)352 UINT nx_azure_iot_buffer_free(VOID *buffer_context)
353 {
354 NX_PACKET *packet_ptr = (NX_PACKET *)buffer_context;
355
356 return(nx_packet_release(packet_ptr));
357 }
358
nx_azure_iot_publish_packet_get(NX_AZURE_IOT * nx_azure_iot_ptr,NXD_MQTT_CLIENT * client_ptr,NX_PACKET ** packet_pptr,UINT wait_option)359 UINT nx_azure_iot_publish_packet_get(NX_AZURE_IOT *nx_azure_iot_ptr, NXD_MQTT_CLIENT *client_ptr,
360 NX_PACKET **packet_pptr, UINT wait_option)
361 {
362 UINT status;
363
364 NX_PARAMETER_NOT_USED(nx_azure_iot_ptr);
365
366 status = _nxd_mqtt_client_packet_allocate(client_ptr, packet_pptr, wait_option);
367 if (status)
368 {
369 LogError(LogLiteralArgs("Create publish packet failed"));
370 return(status);
371 }
372
373 /* Preserve room for fixed MQTT header. */
374 (*packet_pptr) -> nx_packet_prepend_ptr += NX_AZURE_IOT_PUBLISH_PACKET_START_OFFSET;
375
376 return(NX_AZURE_IOT_SUCCESS);
377 }
378
nx_azure_iot_publish_mqtt_packet(NXD_MQTT_CLIENT * client_ptr,NX_PACKET * packet_ptr,UINT topic_len,UCHAR * packet_id,UINT qos,UINT wait_option)379 UINT nx_azure_iot_publish_mqtt_packet(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr,
380 UINT topic_len, UCHAR *packet_id, UINT qos, UINT wait_option)
381 {
382 UINT status;
383 USHORT id = 0;
384
385 status = nx_azure_iot_publish_packet_header_add(packet_ptr, topic_len, qos);
386 if (status)
387 {
388 LogError(LogLiteralArgs("failed to add mqtt header"));
389 return(status);
390 }
391
392 if (qos != 0)
393 {
394 id = (USHORT)((packet_id[0] << 8) | packet_id[1]);
395 }
396
397 /* Note, mutex will be released by this function. */
398 status = _nxd_mqtt_client_publish_packet_send(client_ptr, packet_ptr,
399 id, qos, wait_option);
400 if (status)
401 {
402 LogError(LogLiteralArgs("Mqtt client send fail: PUBLISH FAIL status: %d"), status);
403 return(status);
404 }
405
406 return(NX_AZURE_IOT_SUCCESS);
407 }
408
nx_azure_iot_mqtt_packet_id_get(NXD_MQTT_CLIENT * client_ptr,UCHAR * packet_id)409 UINT nx_azure_iot_mqtt_packet_id_get(NXD_MQTT_CLIENT *client_ptr, UCHAR *packet_id)
410 {
411 UINT status;
412
413 /* Get packet id under mutex */
414 status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER);
415 if (status)
416 {
417 return(status);
418 }
419
420 /* Do nothing if the client is not connected. */
421 if (client_ptr -> nxd_mqtt_client_state != NXD_MQTT_CLIENT_STATE_CONNECTED)
422 {
423 LogError(LogLiteralArgs("MQTT NOT CONNECTED"));
424 return(NX_AZURE_IOT_DISCONNECTED);
425 }
426
427 /* Internal API assuming it to be 2 Byte buffer */
428 packet_id[0] = (UCHAR)(client_ptr -> nxd_mqtt_client_packet_identifier >> 8);
429 packet_id[1] = (UCHAR)(client_ptr -> nxd_mqtt_client_packet_identifier & 0xFF);
430
431 /* Update packet id. */
432 client_ptr -> nxd_mqtt_client_packet_identifier = (client_ptr -> nxd_mqtt_client_packet_identifier + 1) & 0xFFFF;
433
434 /* Prevent packet identifier from being zero. MQTT-2.3.1-1. */
435 if(client_ptr -> nxd_mqtt_client_packet_identifier == 0)
436 {
437 client_ptr -> nxd_mqtt_client_packet_identifier = 1;
438 }
439
440 tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr);
441
442 return(NX_AZURE_IOT_SUCCESS);
443 }
444
nx_azure_iot_mqtt_packet_adjust(NX_PACKET * packet_ptr)445 VOID nx_azure_iot_mqtt_packet_adjust(NX_PACKET *packet_ptr)
446 {
447 UINT size;
448 UINT copy_size;
449 NX_PACKET *current_packet_ptr;
450
451 /* Adjust the packet to make sure,
452 * 1. nx_packet_prepend_ptr does not pointer to nx_packet_data_start.
453 * 2. The first packet is full if it is chained with multiple packets. */
454
455 if (packet_ptr -> nx_packet_prepend_ptr != packet_ptr -> nx_packet_data_start)
456 {
457
458 /* Move data to the nx_packet_data_start. */
459 size = (UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr);
460 memmove(packet_ptr -> nx_packet_data_start, packet_ptr -> nx_packet_prepend_ptr, size); /* Use case of memmove is verified. */
461 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_data_start;
462 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_data_start + size;
463 }
464
465 if (packet_ptr -> nx_packet_next == NX_NULL)
466 {
467
468 /* All data are in the first packet. */
469 return;
470 }
471
472 /* Move data in the chained packet into first one until it is full. */
473 for (current_packet_ptr = packet_ptr -> nx_packet_next;
474 current_packet_ptr;
475 current_packet_ptr = packet_ptr -> nx_packet_next)
476 {
477
478 /* Calculate remaining buffer size in the first packet. */
479 size = (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr);
480
481 /* Calculate copy size from current packet. */
482 copy_size = (UINT)(current_packet_ptr -> nx_packet_append_ptr - current_packet_ptr -> nx_packet_prepend_ptr);
483
484 if (size >= copy_size)
485 {
486
487 /* Copy all data from current packet. */
488 memcpy((VOID *)packet_ptr -> nx_packet_append_ptr, (VOID *)current_packet_ptr -> nx_packet_prepend_ptr, copy_size); /* Use case of memcpy is verified. */
489 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr + copy_size;
490 }
491 else
492 {
493
494 /* Copy partial data from current packet. */
495 memcpy(packet_ptr -> nx_packet_append_ptr, current_packet_ptr -> nx_packet_prepend_ptr, size); /* Use case of memcpy is verified. */
496 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_data_end;
497
498 /* Move data in current packet to nx_packet_data_start. */
499 memmove((VOID *)current_packet_ptr -> nx_packet_data_start, /* Use case of memmove is verified. */
500 (VOID *)(current_packet_ptr -> nx_packet_prepend_ptr + size),
501 (copy_size - size));
502 current_packet_ptr -> nx_packet_prepend_ptr = current_packet_ptr -> nx_packet_data_start;
503 current_packet_ptr -> nx_packet_append_ptr = current_packet_ptr -> nx_packet_data_start + (copy_size - size);
504
505 /* First packet is full. */
506 break;
507 }
508
509 /* Remove current packet from packet chain. */
510 packet_ptr -> nx_packet_next = current_packet_ptr -> nx_packet_next;
511
512 /* Release current packet. */
513 current_packet_ptr -> nx_packet_next = NX_NULL;
514 nx_packet_release(current_packet_ptr);
515 }
516 }
517
nx_azure_iot_certificate_verify(NX_SECURE_TLS_SESSION * session,NX_SECURE_X509_CERT * certificate)518 static ULONG nx_azure_iot_certificate_verify(NX_SECURE_TLS_SESSION *session, NX_SECURE_X509_CERT* certificate)
519 {
520 NX_AZURE_IOT_RESOURCE *resource_ptr;
521 UINT old_threshold;
522 UINT status = NX_AZURE_IOT_SUCCESS;
523
524 /* Disable preemption. */
525 tx_thread_preemption_change(tx_thread_identify(), 0, &old_threshold);
526
527 /* Check if created Azure RTOS IoT. */
528 if (_nx_azure_iot_created_ptr == NX_NULL)
529 {
530
531 /* Restore preemption. */
532 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
533 return(NX_AZURE_IOT_NOT_INITIALIZED);
534 }
535
536 /* Get mutex */
537 status = tx_mutex_get(_nx_azure_iot_created_ptr -> nx_azure_iot_mutex_ptr, NX_WAIT_FOREVER);
538
539 /* Restore preemption. */
540 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
541 if (status)
542 {
543 return(status);
544 }
545
546 /* Loop to find the resource associated with current TLS session. */
547 for (resource_ptr = _nx_azure_iot_created_ptr -> nx_azure_iot_resource_list_header;
548 resource_ptr; resource_ptr = resource_ptr -> resource_next)
549 {
550
551 if (&(resource_ptr -> resource_mqtt.nxd_mqtt_tls_session) == session)
552 {
553 break;
554 }
555 }
556
557 if (resource_ptr)
558 {
559
560 /* Check DNS entry string. */
561 status = nx_secure_x509_common_name_dns_check(certificate,
562 resource_ptr -> resource_hostname,
563 resource_ptr -> resource_hostname_length);
564 if (status)
565 {
566 LogError(LogLiteralArgs("Error in certificate verification: DNS name did not match CN"));
567 }
568 }
569 else
570 {
571
572 /* TLS session not match. */
573 status = NX_AZURE_IOT_NOT_FOUND;
574 }
575
576 /* Release mutex. */
577 tx_mutex_put(_nx_azure_iot_created_ptr -> nx_azure_iot_mutex_ptr);
578
579 return(status);
580 }
581
582 #ifndef NX_AZURE_IOT_DISABLE_CERTIFICATE_DATE
nx_azure_iot_tls_time_function(VOID)583 static ULONG nx_azure_iot_tls_time_function(VOID)
584 {
585 ULONG unix_time = 0;
586 UINT old_threshold;
587
588 /* Disable preemption. */
589 tx_thread_preemption_change(tx_thread_identify(), 0, &old_threshold);
590
591 if (nx_azure_iot_unix_time_get(_nx_azure_iot_created_ptr, &unix_time))
592 {
593
594 /* Unable to get Unix time. */
595 LogError(LogLiteralArgs("Unable to get Unix time"));
596 unix_time = 0;
597 }
598
599 /* Restore preemption. */
600 tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
601 return(unix_time);
602 }
603 #endif /* NX_AZURE_IOT_DISABLE_CERTIFICATE_DATE */
604
nx_azure_iot_mqtt_tls_setup(NXD_MQTT_CLIENT * client_ptr,NX_SECURE_TLS_SESSION * tls_session,NX_SECURE_X509_CERT * certificate,NX_SECURE_X509_CERT * trusted_certificate)605 UINT nx_azure_iot_mqtt_tls_setup(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *tls_session,
606 NX_SECURE_X509_CERT *certificate,
607 NX_SECURE_X509_CERT *trusted_certificate)
608 {
609 UINT status;
610 UINT i;
611 NX_AZURE_IOT_RESOURCE *resource_ptr;
612
613 NX_PARAMETER_NOT_USED(certificate);
614 NX_PARAMETER_NOT_USED(trusted_certificate);
615
616 /* Obtain the mutex. */
617 tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, TX_WAIT_FOREVER);
618
619 resource_ptr = nx_azure_iot_resource_search(client_ptr);
620
621 /* Release the mutex. */
622 tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr);
623
624 if (resource_ptr == NX_NULL)
625 {
626 LogError(LogLiteralArgs("Failed to find associated resource"));
627 return(NX_AZURE_IOT_INVALID_PARAMETER);
628 }
629
630 /* Create TLS session. */
631 status = _nx_secure_tls_session_create_ext(tls_session,
632 resource_ptr -> resource_crypto_array,
633 resource_ptr -> resource_crypto_array_size,
634 resource_ptr -> resource_cipher_map,
635 resource_ptr -> resource_cipher_map_size,
636 resource_ptr -> resource_metadata_ptr,
637 resource_ptr -> resource_metadata_size);
638 if (status)
639 {
640 LogError(LogLiteralArgs("Failed to create TLS session status: %d"), status);
641 return(status);
642 }
643
644 for (i = 0; i < NX_AZURE_IOT_ARRAY_SIZE(resource_ptr -> resource_trusted_certificates); i++)
645 {
646 if (resource_ptr -> resource_trusted_certificates[i])
647 {
648 status = nx_secure_tls_trusted_certificate_add(tls_session, resource_ptr -> resource_trusted_certificates[i]);
649 if (status)
650 {
651 LogError(LogLiteralArgs("Failed to add trusted CA certificate to session status: %d"), status);
652 return(status);
653 }
654 }
655 }
656
657 for (i = 0; i < NX_AZURE_IOT_ARRAY_SIZE(resource_ptr -> resource_device_certificates); i++)
658 {
659 if (resource_ptr -> resource_device_certificates[i])
660 {
661 status = nx_secure_tls_local_certificate_add(tls_session, resource_ptr -> resource_device_certificates[i]);
662 if (status)
663 {
664 LogError(LogLiteralArgs("Failed to add device certificate to session status: %d"), status);
665 return(status);
666 }
667 }
668 }
669
670 status = nx_secure_tls_session_packet_buffer_set(tls_session,
671 resource_ptr -> resource_tls_packet_buffer,
672 sizeof(resource_ptr -> resource_tls_packet_buffer));
673 if (status)
674 {
675 LogError(LogLiteralArgs("Failed to set the session packet buffer: status: %d"), status);
676 return(status);
677 }
678
679 /* Setup the callback invoked when TLS has a certificate it wants to verify so we can
680 do additional checks not done automatically by TLS. */
681 status = nx_secure_tls_session_certificate_callback_set(tls_session,
682 nx_azure_iot_certificate_verify);
683 if (status)
684 {
685 LogError(LogLiteralArgs("Failed to set the session certificate callback: status: %d"), status);
686 return(status);
687 }
688
689 #ifndef NX_AZURE_IOT_DISABLE_CERTIFICATE_DATE
690 /* Setup the callback function used by checking certificate valid date. */
691 nx_secure_tls_session_time_function_set(tls_session, nx_azure_iot_tls_time_function);
692 #endif /* NX_AZURE_IOT_DISABLE_CERTIFICATE_DATE */
693
694 return(NX_AZURE_IOT_SUCCESS);
695 }
696
nx_azure_iot_unix_time_get(NX_AZURE_IOT * nx_azure_iot_ptr,ULONG * unix_time)697 UINT nx_azure_iot_unix_time_get(NX_AZURE_IOT *nx_azure_iot_ptr, ULONG *unix_time)
698 {
699
700 if ((nx_azure_iot_ptr == NX_NULL) ||
701 (nx_azure_iot_ptr -> nx_azure_iot_unix_time_get == NX_NULL) ||
702 (unix_time == NX_NULL))
703 {
704 LogError(LogLiteralArgs("Unix time callback not set"));
705 return(NX_AZURE_IOT_INVALID_PARAMETER);
706 }
707
708 return(nx_azure_iot_ptr -> nx_azure_iot_unix_time_get(unix_time));
709 }
710
711 /* HMAC-SHA256(master key, message ) */
nx_azure_iot_hmac_sha256_calculate(NX_AZURE_IOT_RESOURCE * resource_ptr,UCHAR * key,UINT key_size,const UCHAR * message,UINT message_size,UCHAR * output)712 static UINT nx_azure_iot_hmac_sha256_calculate(NX_AZURE_IOT_RESOURCE *resource_ptr, UCHAR *key, UINT key_size,
713 const UCHAR *message, UINT message_size, UCHAR *output)
714 {
715 UINT i;
716 UINT status;
717 VOID *handler;
718 UCHAR *metadata_ptr = resource_ptr -> resource_metadata_ptr;
719 UINT metadata_size = resource_ptr -> resource_metadata_size;
720 const NX_CRYPTO_METHOD *hmac_sha_256_crypto_method = NX_NULL;
721
722
723 /* Find hmac sha256 crypto method. */
724 for(i = 0; i < resource_ptr -> resource_crypto_array_size; i++)
725 {
726 if(resource_ptr -> resource_crypto_array[i] -> nx_crypto_algorithm == NX_CRYPTO_AUTHENTICATION_HMAC_SHA2_256)
727 {
728 hmac_sha_256_crypto_method = resource_ptr -> resource_crypto_array[i];
729 break;
730 }
731 }
732
733 /* Check if find the crypto method. */
734 if (hmac_sha_256_crypto_method == NX_NULL)
735 {
736 return(NX_AZURE_IOT_NO_AVAILABLE_CIPHER);
737 }
738
739 /* Initialize. */
740 status = hmac_sha_256_crypto_method -> nx_crypto_init((NX_CRYPTO_METHOD *)hmac_sha_256_crypto_method,
741 key, (key_size << 3),
742 &handler,
743 metadata_ptr,
744 metadata_size);
745 if (status)
746 {
747 return(status);
748 }
749
750 /* Authenticate. */
751 status = hmac_sha_256_crypto_method -> nx_crypto_operation(NX_CRYPTO_AUTHENTICATE,
752 handler,
753 (NX_CRYPTO_METHOD *)hmac_sha_256_crypto_method,
754 key,
755 (key_size << 3),
756 (VOID *)message,
757 message_size,
758 NX_CRYPTO_NULL,
759 output,
760 32,
761 metadata_ptr,
762 metadata_size,
763 NX_CRYPTO_NULL,
764 NX_CRYPTO_NULL);
765 if (status)
766 {
767 return(status);
768 }
769
770 /* Cleanup. */
771 status = hmac_sha_256_crypto_method -> nx_crypto_cleanup(metadata_ptr);
772
773 return(status);
774 }
775
nx_azure_iot_base64_hmac_sha256_calculate(NX_AZURE_IOT_RESOURCE * resource_ptr,const UCHAR * key_ptr,UINT key_size,const UCHAR * message_ptr,UINT message_size,UCHAR * buffer_ptr,UINT buffer_len,UCHAR ** output_pptr,UINT * output_len_ptr)776 UINT nx_azure_iot_base64_hmac_sha256_calculate(NX_AZURE_IOT_RESOURCE *resource_ptr,
777 const UCHAR *key_ptr, UINT key_size,
778 const UCHAR *message_ptr, UINT message_size,
779 UCHAR *buffer_ptr, UINT buffer_len,
780 UCHAR **output_pptr, UINT *output_len_ptr)
781 {
782 UINT status;
783 UCHAR *hash_buf;
784 UINT hash_buf_size = 33;
785 UCHAR *encoded_hash_buf;
786 UINT encoded_hash_buf_size = 48;
787 UINT encoded_hash_size;
788 UINT binary_key_buf_size;
789
790 binary_key_buf_size = buffer_len;
791 status = _nx_utility_base64_decode((UCHAR *)key_ptr, key_size,
792 buffer_ptr, binary_key_buf_size, &binary_key_buf_size);
793 if (status)
794 {
795 LogError(LogLiteralArgs("Failed to base64 decode"));
796 return(status);
797 }
798
799 buffer_len -= binary_key_buf_size;
800 if ((hash_buf_size + encoded_hash_buf_size) > buffer_len)
801 {
802 LogError(LogLiteralArgs("Failed to not enough memory"));
803 return(NX_AZURE_IOT_INSUFFICIENT_BUFFER_SPACE);
804 }
805
806 hash_buf = buffer_ptr + binary_key_buf_size;
807 status = nx_azure_iot_hmac_sha256_calculate(resource_ptr, buffer_ptr, binary_key_buf_size,
808 message_ptr, (UINT)message_size, hash_buf);
809 if (status)
810 {
811 LogError(LogLiteralArgs("Failed to get hash256"));
812 return(status);
813 }
814
815 buffer_len -= hash_buf_size;
816 encoded_hash_buf = hash_buf + hash_buf_size;
817
818 /* Additional space is required by encoder. */
819 hash_buf[hash_buf_size - 1] = 0;
820 status = _nx_utility_base64_encode(hash_buf, hash_buf_size - 1,
821 encoded_hash_buf, encoded_hash_buf_size, &encoded_hash_size);
822 if (status)
823 {
824 LogError(LogLiteralArgs("Failed to base64 encode"));
825 return(status);
826 }
827
828 *output_pptr = encoded_hash_buf;
829 *output_len_ptr = encoded_hash_size;
830
831 return(NX_AZURE_IOT_SUCCESS);
832 }
833