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