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 /**
13  * @file nx_azure_iot.h
14  *
15  */
16 
17 #ifndef NX_AZURE_IOT_H
18 #define NX_AZURE_IOT_H
19 
20 #ifdef __cplusplus
21 extern   "C" {
22 #endif
23 
24 #include "azure/core/az_log.h"
25 #include "azure/iot/az_iot_common.h"
26 #include "nx_api.h"
27 #include "nx_cloud.h"
28 #include "nxd_dns.h"
29 #include "nxd_mqtt_client.h"
30 
31 #ifndef NXD_MQTT_CLOUD_ENABLE
32 #error "NXD_MQTT_CLOUD_ENABLE must be defined"
33 #endif /* NXD_MQTT_CLOUD_ENABLE */
34 
35 #ifndef NX_SECURE_ENABLE
36 #error "NX_SECURE_ENABLE must be defined"
37 #endif /* NX_SECURE_ENABLE */
38 
39 /* Defined, certificate date is not validated. By default, it is enabled. */
40 /*
41 #define NX_AZURE_IOT_DISABLE_CERTIFICATE_DATE
42 */
43 
44 /* Define the LOG LEVEL.  */
45 #ifndef NX_AZURE_IOT_LOG_LEVEL
46 #define NX_AZURE_IOT_LOG_LEVEL    2
47 #endif /* NX_AZURE_IOT_LOG_LEVEL */
48 
49 /* Define maximum trusted certificates count.  */
50 #ifndef NX_AZURE_IOT_MAX_NUM_OF_TRUSTED_CERTS
51 #define NX_AZURE_IOT_MAX_NUM_OF_TRUSTED_CERTS 3
52 #endif /* NX_AZURE_IOT_MAX_NUM_OF_TRUSTED_CERTS */
53 
54 /* Define maximum device certificates count.  */
55 #ifndef NX_AZURE_IOT_MAX_NUM_OF_DEVICE_CERTS
56 #define NX_AZURE_IOT_MAX_NUM_OF_DEVICE_CERTS 2
57 #endif /* NX_AZURE_IOT_MAX_NUM_OF_DEVICE_CERTS */
58 
59 #define NX_AZURE_IOT_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
60 
61 /* Define the az iot log function. */
62 #define LogError(...)
63 #define LogInfo(...)
64 #define LogDebug(...)
65 #define LogLiteralArgs(s) (UCHAR *)s, sizeof(s) - 1
66 
67 /**
68 * Supports logging of AZ_LOG_IOT_AZURERTOS classification message. In the logged
69 * message, at-most one format specifier can be specifed at the end of message.
70 * Currently only two format specifier are supported:
71 *   - %d for integer
72 *   - %s for string, where first argument is length and second is pointer to string
73 */
74 UINT nx_azure_iot_log(UCHAR *type_ptr, UINT type_len, UCHAR *msg_ptr, UINT msg_len, ...);
75 
76 #if NX_AZURE_IOT_LOG_LEVEL > 0
77 #undef LogError
78 #define LogError(...) nx_azure_iot_log(LogLiteralArgs("[ERROR] "), __VA_ARGS__)
79 #endif /* NX_AZURE_IOT_LOG_LEVEL > 0 */
80 #if NX_AZURE_IOT_LOG_LEVEL > 1
81 #undef LogInfo
82 #define LogInfo(...) nx_azure_iot_log(LogLiteralArgs("[INFO] "), __VA_ARGS__)
83 #endif /* NX_AZURE_IOT_LOG_LEVEL > 1 */
84 #if NX_AZURE_IOT_LOG_LEVEL > 2
85 #undef LogDebug
86 #define LogDebug(...) nx_azure_iot_log(LogLiteralArgs("[DEBUG] "), __VA_ARGS__)
87 #endif /* NX_AZURE_IOT_LOG_LEVEL > 2 */
88 
89 #define NX_AZURE_IOT_MQTT_QOS_0                           0
90 #define NX_AZURE_IOT_MQTT_QOS_1                           1
91 
92 /* Define AZ IoT SDK event flags. These events are processed by the Cloud thread.  */
93 
94 /* Provisioning Client Connect event */
95 #define NX_AZURE_IOT_PROVISIONING_CLIENT_CONNECT_EVENT    ((ULONG)0x00000001)
96 
97 /* Provisioning Client Subscribe event */
98 #define NX_AZURE_IOT_PROVISIONING_CLIENT_SUBSCRIBE_EVENT  ((ULONG)0x00000002)
99 
100 /* Provisioning Client Request event */
101 #define NX_AZURE_IOT_PROVISIONING_CLIENT_REQUEST_EVENT    ((ULONG)0x00000004)
102 
103 /* Provisioning Client Response event */
104 #define NX_AZURE_IOT_PROVISIONING_CLIENT_RESPONSE_EVENT   ((ULONG)0x00000008)
105 
106 /* Provisioning Client Disconnect event */
107 #define NX_AZURE_IOT_PROVISIONING_CLIENT_DISCONNECT_EVENT ((ULONG)0x00000010)
108 
109 /* API return values.  */
110 /**< The operation was successful. */
111 #define NX_AZURE_IOT_SUCCESS                              0x0
112 
113 /**< The operation was unsuccessful. */
114 #define NX_AZURE_IOT_FAILURE                              0x20000
115 #define NX_AZURE_IOT_SDK_CORE_ERROR                       0x20001
116 #define NX_AZURE_IOT_INVALID_PARAMETER                    0x20002
117 #define NX_AZURE_IOT_INSUFFICIENT_BUFFER_SPACE            0x20003
118 #define NX_AZURE_IOT_INVALID_PACKET                       0x20004
119 #define NX_AZURE_IOT_NO_PACKET                            0x20005
120 
121 /**< If the item requested was not found */
122 #define NX_AZURE_IOT_NOT_FOUND                            0x20006
123 #define NX_AZURE_IOT_NOT_ENABLED                          0x20007
124 #define NX_AZURE_IOT_NOT_INITIALIZED                      0x20008
125 #define NX_AZURE_IOT_NOT_SUPPORTED                        0x20009
126 #define NX_AZURE_IOT_ALREADY_CONNECTED                    0x2000A
127 #define NX_AZURE_IOT_CONNECTING                           0x2000B
128 #define NX_AZURE_IOT_DISCONNECTED                         0x2000C
129 
130 /**< The operation is pending. */
131 #define NX_AZURE_IOT_PENDING                              0x2000D
132 #define NX_AZURE_IOT_SERVER_RESPONSE_ERROR                0x2000E
133 #define NX_AZURE_IOT_TOPIC_TOO_LONG                       0x2000F
134 #define NX_AZURE_IOT_MESSAGE_TOO_LONG                     0x20010
135 #define NX_AZURE_IOT_NO_AVAILABLE_CIPHER                  0x20011
136 #define NX_AZURE_IOT_WRONG_STATE                          0x20012
137 #define NX_AZURE_IOT_DELETE_ERROR                         0x20013
138 #define NX_AZURE_IOT_NO_SUBSCRIBE_ACK                     0x20014
139 #define NX_AZURE_IOT_THROTTLED                            0x20015
140 
141 #define NX_AZURE_IOT_EMPTY_JSON                           0x20016
142 #define NX_AZURE_IOT_SAS_TOKEN_EXPIRED                    0x20017
143 #define NX_AZURE_IOT_NO_MORE_ENTRIES                      0x20018
144 
145 /* Resource type managed by AZ_IOT.  */
146 #define NX_AZURE_IOT_RESOURCE_IOT_HUB                     0x1
147 #define NX_AZURE_IOT_RESOURCE_IOT_PROVISIONING            0x2
148 
149 /* Define the packet buffer for THREADX TLS.  */
150 #ifndef NX_AZURE_IOT_TLS_PACKET_BUFFER_SIZE
151 #define NX_AZURE_IOT_TLS_PACKET_BUFFER_SIZE               (1024 * 7)
152 #endif /* NX_AZURE_IOT_TLS_PACKET_BUFFER_SIZE  */
153 
154 /* Define MQTT keep alive in seconds. 0 means the keep alive is disabled.
155    By default, keep alive is 4 minutes. */
156 #ifndef NX_AZURE_IOT_MQTT_KEEP_ALIVE
157 #define NX_AZURE_IOT_MQTT_KEEP_ALIVE                      (60 * 4)
158 #endif /* NX_AZURE_IOT_MQTT_KEEP_ALIVE */
159 
160 /* MQTT Subscribe topic offset.  */
161 #define NX_AZURE_IOT_MQTT_SUBSCRIBE_TOPIC_OFFSET          6
162 
163 /* MQTT Publish offset.  */
164 #define NX_AZURE_IOT_PUBLISH_PACKET_START_OFFSET          7
165 
166 /**
167  * @brief Resource struct
168  *
169  */
170 typedef struct NX_AZURE_IOT_RESOURCE_STRUCT
171 {
172     UINT                                   resource_type;
173     VOID                                  *resource_data_ptr;
174     NXD_MQTT_CLIENT                        resource_mqtt;
175     UCHAR                                 *resource_mqtt_client_id;
176     UINT                                   resource_mqtt_client_id_length;
177     UCHAR                                 *resource_mqtt_user_name;
178     UINT                                   resource_mqtt_user_name_length;
179     UCHAR                                 *resource_mqtt_sas_token;
180     UINT                                   resource_mqtt_sas_token_length;
181     VOID                                  *resource_mqtt_buffer_context;
182     UINT                                   resource_mqtt_buffer_size;
183     UCHAR                                  resource_tls_packet_buffer[NX_AZURE_IOT_TLS_PACKET_BUFFER_SIZE];
184     const NX_CRYPTO_METHOD               **resource_crypto_array;
185     UINT                                   resource_crypto_array_size;
186     const NX_CRYPTO_CIPHERSUITE          **resource_cipher_map;
187     UINT                                   resource_cipher_map_size;
188     UCHAR                                 *resource_metadata_ptr;
189     UINT                                   resource_metadata_size;
190     NX_SECURE_X509_CERT                   *resource_trusted_certificates[NX_AZURE_IOT_MAX_NUM_OF_TRUSTED_CERTS];
191     NX_SECURE_X509_CERT                   *resource_device_certificates[NX_AZURE_IOT_MAX_NUM_OF_DEVICE_CERTS];
192     const UCHAR                           *resource_hostname;
193     UINT                                   resource_hostname_length;
194     struct NX_AZURE_IOT_RESOURCE_STRUCT   *resource_next;
195 
196 } NX_AZURE_IOT_RESOURCE;
197 
198 /**
199  * @brief Azure IoT Struct
200  *
201  */
202 typedef struct NX_AZURE_IOT_STRUCT
203 {
204     const UCHAR                           *nx_azure_iot_name;
205     NX_IP                                 *nx_azure_iot_ip_ptr;
206     NX_PACKET_POOL                        *nx_azure_iot_pool_ptr;
207     NX_DNS                                *nx_azure_iot_dns_ptr;
208     NX_CLOUD                               nx_azure_iot_cloud;
209     NX_CLOUD_MODULE                        nx_azure_iot_cloud_module;
210     TX_MUTEX                              *nx_azure_iot_mutex_ptr;
211     VOID                                 (*nx_azure_iot_provisioning_client_event_process)(
212                                           struct NX_AZURE_IOT_STRUCT *nx_azure_iot_ptr,
213                                           ULONG common_events, ULONG module_own_events);
214     struct NX_AZURE_IOT_RESOURCE_STRUCT   *nx_azure_iot_resource_list_header;
215     UINT                                 (*nx_azure_iot_unix_time_get)(ULONG *unix_time);
216 } NX_AZURE_IOT;
217 
218 typedef struct NX_AZURE_IOT_THREAD_STRUCT
219 {
220     TX_THREAD                           *thread_ptr;
221     struct NX_AZURE_IOT_THREAD_STRUCT   *thread_next;
222     UINT                                 thread_message_type;
223     UINT                                 thread_expected_id;     /* Used by device twin. */
224     NX_PACKET                           *thread_received_message;
225 } NX_AZURE_IOT_THREAD;
226 
227 /**
228  * @brief Create the Azure IoT subsystem
229  *
230  * @details This routine creates the Azure IoT subsystem. An internal thread is created to
231  *          manage activities related to Azure IoT services. Only one NX_AZURE_IOT instance
232  *          is needed to manage instances for Azure IoT hub, IoT Central, Device Provisioning
233  *          Services (DPS), and Azure Security Center (ASC).
234  *
235  * @remarks This routine enables ASC by default. ASC provides a comprehensive security solution for
236  *          Azure RTOS devices in which it collects network information and send it to the IoTHub.
237  *          More details can be found https://docs.microsoft.com/en-us/azure/defender-for-iot/iot-security-azure-rtos.
238  *          To disable ASC from your application, we provide both compile time and runtime option:
239  *              - compile-time : NX_AZURE_DISABLE_IOT_SECURITY_MODULE in NetXDuo header file such as nx_port.h
240  *                               when building the middleware.
241  *              - runtime : Call UINT nx_azure_iot_security_module_disable(NX_AZURE_IOT *nx_azure_iot_ptr)
242  *                          in your application code.
243  *
244  * @param[in] nx_azure_iot_ptr A pointer to a #NX_AZURE_IOT
245  * @param[in] name_ptr A pointer to a NULL-terminated string indicating the name of the Azure IoT instance.
246  * @param[in] ip_ptr A pointer to a `NX_IP`, which is the IP stack used to connect to Azure IoT Services.
247  * @param[in] pool_ptr A pointer to a `NX_PACKET_POOL`, which is the packet pool used by Azure IoT Services.
248  * @param[in] dns_ptr A pointer to a `NX_DNS`.
249  * @param[in] stack_memory_ptr A pointer to memory to be used as a stack space for the internal thread.
250  * @param[in] stack_memory_size Size of stack memory area.
251  * @param[in] priority Priority of the internal thread.
252  * @param[in] unix_time_callback Callback to fetch unix time from platform.
253  * @return A `UINT` with the result of the API.
254  *   @retval #NX_AZURE_IOT_SUCCESS Successfully created the Azure IoT instance.
255  *   @retval #NX_AZURE_IOT_INVALID_PARAMETER Fail to create the Azure IoT instance due to invalid parameter.
256  *   @retval NX_OPTION_ERROR Fail to create the Azure IoT instance due to invalid priority.
257  *   @retval NX_PTR_ERROR Fail to create the Azure IoT instance due to invalid parameter.
258  *   @retval NX_SIZE_ERROR Fail to create the Azure IoT instance due to insufficient size of stack memory.
259  */
260 UINT nx_azure_iot_create(NX_AZURE_IOT *nx_azure_iot_ptr, const UCHAR *name_ptr,
261                          NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, NX_DNS *dns_ptr,
262                          VOID *stack_memory_ptr, UINT stack_memory_size,
263                          UINT priority, UINT (*unix_time_callback)(ULONG *unix_time));
264 
265 /**
266  * @brief Shutdown and cleanup the Azure IoT subsystem.
267  * @details This routine stops all Azure services managed by this instance, and cleans up internal resources.
268  *
269  * @param[in] nx_azure_iot_ptr A pointer to a #NX_AZURE_IOT.
270  * @return A `UINT` with the result of the API.
271  *   @retval #NX_AZURE_IOT_SUCCESS Successfully stopped Azure IoT services and cleaned up internal
272  *                                    resources instance.
273  *   @retval #NX_AZURE_IOT_INVALID_PARAMETER Fail to delete the Azure IoT instance due to invalid parameter.
274  *   @retval #NX_AZURE_IOT_DELETE_ERROR Fail to delete the Azure IoT instance due to resource is still in use.
275  */
276 UINT nx_azure_iot_delete(NX_AZURE_IOT *nx_azure_iot_ptr);
277 
278 /**
279  * @brief Get unixtime
280  *
281  * @param[in] nx_azure_iot_ptr A pointer to a #NX_AZURE_IOT.
282  * @param[out] unix_time Pointer to `ULONG` where unixtime is returned.
283  * @return A `UINT` with the result of the API.
284  *   @retval #NX_AZURE_IOT_SUCCESS Successfully return unix time.
285  *   @retval #NX_AZURE_IOT_INVALID_PARAMETER Fail to get unix time due to invalid parameter.
286  */
287 UINT nx_azure_iot_unix_time_get(NX_AZURE_IOT *nx_azure_iot_ptr, ULONG *unix_time);
288 
289 /**
290  * @brief Initialize logging
291  *
292  * @details This routine initialized the logging with customer specific callback to output the logs for different
293  *          classifications:
294  *          - AZ_LOG_IOT_AZURERTOS,
295  *          - AZ_LOG_MQTT_RECEIVED_TOPIC,
296  *          - AZ_LOG_MQTT_RECEIVED_PAYLOAD,
297  *          - AZ_LOG_IOT_RETRY,
298  *          - AZ_LOG_IOT_SAS_TOKEN
299  *
300  * @param[in] log_callback A pointer to a callback.
301  *
302  */
303 VOID nx_azure_iot_log_init(VOID(*log_callback)(az_log_classification classification, UCHAR *msg, UINT msg_len));
304 
305 /* Internal APIs. */
306 UINT nx_azure_iot_buffer_allocate(NX_AZURE_IOT *nx_azure_iot_ptr, UCHAR **buffer_pptr,
307                                   UINT *buffer_size, VOID **buffer_context);
308 UINT nx_azure_iot_buffer_free(VOID *buffer_context);
309 UINT nx_azure_iot_resource_add(NX_AZURE_IOT *nx_azure_iot_ptr, NX_AZURE_IOT_RESOURCE *resource);
310 UINT nx_azure_iot_resource_remove(NX_AZURE_IOT *nx_azure_iot_ptr, NX_AZURE_IOT_RESOURCE *resource);
311 NX_AZURE_IOT_RESOURCE *nx_azure_iot_resource_search(NXD_MQTT_CLIENT *client_ptr);
312 UINT nx_azure_iot_publish_mqtt_packet(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr,
313                                       UINT topic_len, UCHAR *packet_id, UINT qos, UINT wait_option);
314 UINT nx_azure_iot_publish_packet_get(NX_AZURE_IOT *nx_azure_iot_ptr, NXD_MQTT_CLIENT *client_ptr,
315                                      NX_PACKET **packet_pptr, UINT wait_option);
316 UINT nx_azure_iot_mqtt_packet_id_get(NXD_MQTT_CLIENT *client_ptr, UCHAR *packet_id);
317 VOID nx_azure_iot_mqtt_packet_adjust(NX_PACKET *packet_ptr);
318 UINT nx_azure_iot_mqtt_tls_setup(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *tls_session,
319                                  NX_SECURE_X509_CERT *certificate,
320                                  NX_SECURE_X509_CERT *trusted_certificate);
321 UINT nx_azure_iot_base64_hmac_sha256_calculate(NX_AZURE_IOT_RESOURCE *resource_ptr,
322                                                const UCHAR *key_ptr, UINT key_size,
323                                                const UCHAR *message_ptr, UINT message_size,
324                                                UCHAR *buffer_ptr, UINT buffer_len,
325                                                UCHAR **output_ptr, UINT *output_len_ptr);
326 
327 #ifdef __cplusplus
328 }
329 #endif
330 #endif /* NX_AZURE_IOT_H */
331