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 #include <stdio.h>
12 #include <setjmp.h>
13 #include <cmocka.h>  /* macros: https://api.cmocka.org/group__cmocka__asserts.html */
14 
15 #include "nx_api.h"
16 #include "nx_azure_iot_hub_client.h"
17 #include "nx_azure_iot_cert.h"
18 #include "nx_azure_iot_ciphersuites.h"
19 
20 
21 #define DEMO_DHCP_DISABLE
22 #define DEMO_IPV4_ADDRESS         IP_ADDRESS(192, 168, 100, 33)
23 #define DEMO_IPV4_MASK            0xFFFFFF00UL
24 #define DEMO_GATEWAY_ADDRESS      IP_ADDRESS(192, 168, 100, 1)
25 #define DEMO_DNS_SERVER_ADDRESS   IP_ADDRESS(192, 168, 100, 1)
26 #define NETWORK_DRIVER            _nx_ram_network_driver
27 
28 /* Include main.c in the test case since we need to disable DHCP in this test. */
29 #include "main.c"
30 
31 
32 #define STRING_UNSIGNED_ARGS(s) (UCHAR *)s, strlen(s)
33 
34 #ifndef DEMO_CLOUD_STACK_SIZE
35 #define DEMO_CLOUD_STACK_SIZE   2048
36 #endif /* DEMO_CLOUD_STACK_SIZE */
37 
38 #ifndef DEMO_CLOUD_THREAD_PRIORITY
39 #define DEMO_CLOUD_THREAD_PRIORITY  (4)
40 #endif /* DEMO_CLOUD_THREAD_PRIORITY */
41 
42 static UINT interface_type_check(ULONG interface_type);
43 static UINT deplete_packets(NX_PACKET_POOL *pool_ptr, UINT remaining_packets);
44 static VOID release_packets(NX_PACKET_POOL *pool_ptr, UINT count);
45 
46 static NX_AZURE_IOT iot;
47 static NX_AZURE_IOT_HUB_CLIENT iot_client;
48 static NX_SECURE_X509_CERT root_ca_cert;
49 static UCHAR metadata_buffer[NX_AZURE_IOT_TLS_METADATA_BUFFER_SIZE];
50 static ULONG demo_cloud_thread_stack[DEMO_CLOUD_STACK_SIZE / sizeof(ULONG)];
51 static NX_PACKET *allocated_packets[256];
52 static UCHAR large_property_name[2048];
53 static ULONG small_pool_stack[1024 >> 2];
54 static NX_PACKET_POOL small_pool;
55 extern int g_argc;
56 extern char **g_argv;
57 
58 ULONG g_interface_type = 0;
59 
demo_entry(NX_IP * ip_ptr,NX_PACKET_POOL * pool_ptr,NX_DNS * dns_ptr,UINT (* unix_time_callback)(ULONG * unix_time))60 VOID demo_entry(NX_IP* ip_ptr, NX_PACKET_POOL* pool_ptr, NX_DNS* dns_ptr, UINT (*unix_time_callback)(ULONG *unix_time))
61 {
62 CHAR *host_name = "host_name";
63 CHAR *device_id = "device_id";
64 CHAR *module_id = "module_id";
65 CHAR *symmetric_key = "symmetric_key";
66 CHAR property_name[] = "property_name";
67 CHAR property_value[] = "property_value";
68 NX_PACKET *packet_ptr;
69 UINT count;
70 ULONG pool_ptr_available_packet;
71 ULONG small_pool_available_packet;
72 
73     assert_int_equal(nx_packet_pool_create(&small_pool, "Small Packet Pool", 4,
74                                            (UCHAR *)small_pool_stack , sizeof(small_pool_stack)),
75                      NX_AZURE_IOT_SUCCESS);
76 
77     /* Initialize root certificate.  */
78     assert_int_equal(nx_secure_x509_certificate_initialize(&root_ca_cert, (UCHAR *)_nx_azure_iot_root_cert, (USHORT)_nx_azure_iot_root_cert_size,
79                                                            NX_NULL, 0, NULL, 0, NX_SECURE_X509_KEY_TYPE_NONE),
80                      NX_AZURE_IOT_SUCCESS);
81 
82     assert_int_equal(nx_azure_iot_create(&iot, (UCHAR *)"Azure IoT", ip_ptr, pool_ptr, dns_ptr, (UCHAR *)demo_cloud_thread_stack,
83                                          sizeof(demo_cloud_thread_stack), DEMO_CLOUD_THREAD_PRIORITY, unix_time_callback),
84                      NX_AZURE_IOT_SUCCESS);
85 
86     /* Record number of available packet before test */
87     pool_ptr_available_packet = pool_ptr -> nx_packet_pool_available;
88     small_pool_available_packet = small_pool.nx_packet_pool_available;
89 
90     assert_int_equal(nx_azure_iot_hub_client_initialize(&iot_client, &iot,
91                                                         STRING_UNSIGNED_ARGS(host_name),
92                                                         STRING_UNSIGNED_ARGS(device_id),
93                                                         STRING_UNSIGNED_ARGS(""),
94                                                         _nx_azure_iot_tls_supported_crypto,
95                                                         _nx_azure_iot_tls_supported_crypto_size,
96                                                         _nx_azure_iot_tls_ciphersuite_map,
97                                                         _nx_azure_iot_tls_ciphersuite_map_size,
98                                                         metadata_buffer, sizeof(metadata_buffer),
99                                                         &root_ca_cert),
100                      NX_AZURE_IOT_SUCCESS);
101 
102     /* Fail to set the type.  */
103     g_interface_type = NX_INTERFACE_TYPE_UNKNOWN;
104     will_return(__wrap__nxe_ip_driver_interface_direct_command, NX_NOT_SUCCESSFUL);
105 
106     assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_TRUE, NX_IP_PERIODIC_RATE),
107                      NX_AZURE_IOT_SUCCESS);
108 
109     /* The interface type should not be updated.  */
110     assert_int_equal(interface_type_check(NX_INTERFACE_TYPE_UNKNOWN), NX_AZURE_IOT_SUCCESS);
111 
112     nx_azure_iot_hub_client_disconnect(&iot_client);
113 
114     /* Set the type as NX_INTERFACE_TYPE_OTHER.  */
115     g_interface_type = NX_INTERFACE_TYPE_OTHER;
116     will_return(__wrap__nxe_ip_driver_interface_direct_command, NX_SUCCESS);
117 
118     assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_TRUE, NX_IP_PERIODIC_RATE),
119                      NX_AZURE_IOT_SUCCESS);
120 
121     /* The interface type should be updated as NX_INTERFACE_TYPE_OTHER.  */
122     assert_int_equal(interface_type_check(NX_INTERFACE_TYPE_OTHER), NX_AZURE_IOT_SUCCESS);
123 
124     nx_azure_iot_hub_client_disconnect(&iot_client);
125 
126     /* Set the type as NX_INTERFACE_TYPE_ETHERNET.  */
127     g_interface_type = NX_INTERFACE_TYPE_ETHERNET;
128     will_return(__wrap__nxe_ip_driver_interface_direct_command, NX_SUCCESS);
129 
130     assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_TRUE, NX_IP_PERIODIC_RATE),
131                      NX_AZURE_IOT_SUCCESS);
132 
133     /* The interface type should be updated as NX_INTERFACE_TYPE_ETHERNET.  */
134     assert_int_equal(interface_type_check(NX_INTERFACE_TYPE_ETHERNET), NX_AZURE_IOT_SUCCESS);
135 
136     nx_azure_iot_hub_client_disconnect(&iot_client);
137 
138     /* Set the type as NX_INTERFACE_TYPE_LORAWAN.  */
139     g_interface_type = NX_INTERFACE_TYPE_LORAWAN;
140     will_return(__wrap__nxe_ip_driver_interface_direct_command, NX_SUCCESS);
141 
142     assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_TRUE, NX_IP_PERIODIC_RATE),
143                      NX_AZURE_IOT_SUCCESS);
144 
145     /* The interface type should be updated as NX_INTERFACE_TYPE_LORAWAN.  */
146     assert_int_equal(interface_type_check(NX_INTERFACE_TYPE_LORAWAN), NX_AZURE_IOT_SUCCESS);
147 
148     nx_azure_iot_hub_client_disconnect(&iot_client);
149 
150     /* Set the type as NX_INTERFACE_TYPE_MAX - 1.  */
151     g_interface_type = NX_INTERFACE_TYPE_MAX - 1;
152     will_return(__wrap__nxe_ip_driver_interface_direct_command, NX_SUCCESS);
153 
154     assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_TRUE, NX_IP_PERIODIC_RATE),
155                      NX_AZURE_IOT_SUCCESS);
156 
157     /* The interface type should be updated as NX_INTERFACE_TYPE_MAX - 1.  */
158     assert_int_equal(interface_type_check(NX_INTERFACE_TYPE_MAX - 1), NX_AZURE_IOT_SUCCESS);
159 
160     nx_azure_iot_hub_client_disconnect(&iot_client);
161 
162     /* Set the type as NX_INTERFACE_TYPE_MAX.  */
163     g_interface_type = NX_INTERFACE_TYPE_MAX;
164     will_return(__wrap__nxe_ip_driver_interface_direct_command, NX_SUCCESS);
165 
166     assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_TRUE, NX_IP_PERIODIC_RATE),
167                      NX_AZURE_IOT_SUCCESS);
168 
169     /* The interface type should be updated as NX_INTERFACE_TYPE_OTHER.  */
170     assert_int_equal(interface_type_check(NX_INTERFACE_TYPE_OTHER), NX_AZURE_IOT_SUCCESS);
171 
172     nx_azure_iot_hub_client_disconnect(&iot_client);
173 
174     iot_client.nx_azure_iot_hub_client_resource.resource_mqtt.nxd_mqtt_client_socket.nx_tcp_socket_state = NX_TCP_CLOSED;
175     assert_int_equal(nx_azure_iot_hub_client_deinitialize(&iot_client),
176                      NX_AZURE_IOT_SUCCESS);
177 
178     /* Check if all the packet are released */
179     assert_int_equal(pool_ptr -> nx_packet_pool_available, pool_ptr_available_packet);
180     assert_int_equal(small_pool.nx_packet_pool_available, small_pool_available_packet);
181 
182     /* SUCCESS: iot is created. */
183     assert_int_equal(nx_azure_iot_delete(&iot), NX_AZURE_IOT_SUCCESS);
184 }
185 
interface_type_check(ULONG interface_type)186 static UINT interface_type_check(ULONG interface_type)
187 {
188 UINT index;
189 UCHAR type;
190 
191     /* Decode the interface type.  */
192     for (index = 0; index < (iot_client.iot_hub_client_core._internal.options.user_agent._internal.size - 3); index++)
193     {
194 
195         /* The interface type is after the first semicolon.  */
196         if ((*(iot_client.iot_hub_client_core._internal.options.user_agent._internal.ptr + index) == '%') &&
197             (*(iot_client.iot_hub_client_core._internal.options.user_agent._internal.ptr + index + 1) == '3') &&
198             (*(iot_client.iot_hub_client_core._internal.options.user_agent._internal.ptr + index + 2) == 'B'))
199         {
200             type = *(iot_client.iot_hub_client_core._internal.options.user_agent._internal.ptr + index + 3) - '0';
201             if (type == interface_type)
202             {
203                 return(NX_AZURE_IOT_SUCCESS);
204             }
205             else
206             {
207                 return(NX_AZURE_IOT_FAILURE);
208             }
209         }
210     }
211 
212     return(NX_AZURE_IOT_FAILURE);
213 }
214 
deplete_packets(NX_PACKET_POOL * pool_ptr,UINT remaining_packets)215 static UINT deplete_packets(NX_PACKET_POOL *pool_ptr, UINT remaining_packets)
216 {
217 UINT count = 0;
218 
219     while (pool_ptr -> nx_packet_pool_available > remaining_packets)
220     {
221         nx_packet_allocate(pool_ptr, &allocated_packets[count++], 0, NX_WAIT_FOREVER);
222     }
223     return(count);
224 }
225 
release_packets(NX_PACKET_POOL * pool_ptr,UINT count)226 static VOID release_packets(NX_PACKET_POOL *pool_ptr, UINT count)
227 {
228     while (count != 0)
229     {
230         nx_packet_release(allocated_packets[--count]);
231     }
232 }
233 
__wrap__nxe_ip_driver_interface_direct_command(NX_IP * ip_ptr,UINT command,UINT interface_index,ULONG * return_value_ptr)234 UINT __wrap__nxe_ip_driver_interface_direct_command(NX_IP *ip_ptr, UINT command, UINT interface_index, ULONG *return_value_ptr)
235 {
236     printf("HIJACKED: %s\n", __func__);
237     *return_value_ptr = g_interface_type;
238     return((UINT)mock());
239 }
240 
__wrap__nxde_mqtt_client_secure_connect(NXD_MQTT_CLIENT * client_ptr,NXD_ADDRESS * server_ip,UINT server_port,UINT (* tls_setup)(NXD_MQTT_CLIENT * client_ptr,NX_SECURE_TLS_SESSION *,NX_SECURE_X509_CERT *,NX_SECURE_X509_CERT *),UINT keepalive,UINT clean_session,ULONG timeout)241 UINT __wrap__nxde_mqtt_client_secure_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port,
242                                              UINT (*tls_setup)(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *,
243                                                                NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *),
244                                              UINT keepalive, UINT clean_session, ULONG timeout)
245 {
246     printf("HIJACKED: %s\n", __func__);
247     tx_thread_suspend(&(iot.nx_azure_iot_ip_ptr -> nx_ip_thread));
248     client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_CONNECTED;
249     client_ptr -> nxd_mqtt_client_packet_identifier = 1;
250     client_ptr -> nxd_mqtt_tls_session.nx_secure_tls_id = NX_SECURE_TLS_ID;
251     client_ptr -> nxd_mqtt_tls_session.nx_secure_tls_local_session_active = NX_FALSE;
252     client_ptr -> nxd_mqtt_tls_session.nx_secure_tls_tcp_socket = &client_ptr -> nxd_mqtt_client_socket;
253     client_ptr -> nxd_mqtt_client_socket.nx_tcp_socket_connect_ip.nxd_ip_version = NX_IP_VERSION_V4;
254     client_ptr -> nxd_mqtt_client_socket.nx_tcp_socket_state = NX_TCP_ESTABLISHED;
255     return(NXD_MQTT_SUCCESS);
256 }
257 
__wrap__nxde_mqtt_client_disconnect(NXD_MQTT_CLIENT * client_ptr)258 UINT __wrap__nxde_mqtt_client_disconnect(NXD_MQTT_CLIENT *client_ptr)
259 {
260     printf("HIJACKED: %s\n", __func__);
261     client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_IDLE;
262     client_ptr -> nxd_mqtt_client_socket.nx_tcp_socket_state = NX_TCP_CLOSED;
263     return(NXD_MQTT_SUCCESS);
264 }
265 
__wrap__nxde_dns_host_by_name_get(NX_DNS * dns_ptr,UCHAR * host_name,NXD_ADDRESS * host_address_ptr,ULONG wait_option,UINT lookup_type)266 UINT __wrap__nxde_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, NXD_ADDRESS *host_address_ptr,
267                                        ULONG wait_option, UINT lookup_type)
268 {
269     printf("HIJACKED: %s\n", __func__);
270     host_address_ptr -> nxd_ip_version = NX_IP_VERSION_V4;
271     host_address_ptr -> nxd_ip_address.v4 = IP_ADDRESS(127, 0, 0, 1);
272     return(NX_DNS_SUCCESS);
273 }
274 
__wrap__nxd_mqtt_client_publish_packet_send(NXD_MQTT_CLIENT * client_ptr,NX_PACKET * packet_ptr,USHORT packet_id,UINT QoS,ULONG wait_option)275 UINT __wrap__nxd_mqtt_client_publish_packet_send(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr,
276                                                  USHORT packet_id, UINT QoS, ULONG wait_option)
277 {
278 UINT topic_name_length;
279 UINT message_length;
280 UCHAR *buffer_ptr;
281 UINT status = (UINT)mock();
282 
283     printf("HIJACKED: %s\n", __func__);
284     tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr);
285 
286     if (status)
287     {
288         return(status);
289     }
290 
291     /* packet ownership taken and released */
292     nx_packet_release(packet_ptr);
293 
294     return(status);
295 }
296 
__wrap_nx_azure_iot_security_module_enable(NX_AZURE_IOT * nx_azure_iot_ptr)297 UINT __wrap_nx_azure_iot_security_module_enable(NX_AZURE_IOT *nx_azure_iot_ptr)
298 {
299     printf("HIJACKED: %s\n", __func__);
300     return(NX_AZURE_IOT_SUCCESS);
301 }
302 
__wrap_nx_azure_iot_security_module_disable(NX_AZURE_IOT * nx_azure_iot_ptr)303 UINT __wrap_nx_azure_iot_security_module_disable(NX_AZURE_IOT *nx_azure_iot_ptr)
304 {
305     printf("HIJACKED: %s\n", __func__);
306     return(NX_AZURE_IOT_SUCCESS);
307 }
308