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