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 "nx_api.h"
12 #include "nx_azure_iot.h"
13 #ifndef DEMO_DHCP_DISABLE
14 #include "nxd_dhcp_client.h"
15 #endif /* DEMO_DHCP_DISABLE */
16 #include "nxd_dns.h"
17 #include "nx_secure_tls_api.h"
18 #include <setjmp.h>
19 #include <cmocka.h>  /* macros: https://api.cmocka.org/group__cmocka__asserts.html */
20 
21 /* Include the demo.  */
22 extern VOID demo_entry(NX_IP* ip_ptr, NX_PACKET_POOL* pool_ptr, NX_DNS* dns_ptr, UINT (*unix_time_callback)(ULONG *unix_time));
23 
24 /* Define the helper thread for running Azure SDK on ThreadX (THREADX IoT Platform).  */
25 #ifndef DEMO_HELPER_STACK_SIZE
26 #define DEMO_HELPER_STACK_SIZE      (2048)
27 #endif /* DEMO_HELPER_STACK_SIZE  */
28 
29 #ifndef DEMO_HELPER_THREAD_PRIORITY
30 #define DEMO_HELPER_THREAD_PRIORITY (4)
31 #endif /* DEMO_HELPER_THREAD_PRIORITY  */
32 
33 /* Define user configurable symbols. */
34 #ifndef DEMO_IP_STACK_SIZE
35 #define DEMO_IP_STACK_SIZE          (2048)
36 #endif /* DEMO_IP_STACK_SIZE  */
37 
38 #ifndef DEMO_PACKET_COUNT
39 #define DEMO_PACKET_COUNT           (32)
40 #endif /* DEMO_PACKET_COUNT  */
41 
42 #ifndef DEMO_PACKET_SIZE
43 #define DEMO_PACKET_SIZE            (1536)
44 #endif /* DEMO_PACKET_SIZE  */
45 
46 #define DEMO_POOL_SIZE              ((DEMO_PACKET_SIZE + sizeof(NX_PACKET)) * DEMO_PACKET_COUNT)
47 
48 #ifndef DEMO_ARP_CACHE_SIZE
49 #define DEMO_ARP_CACHE_SIZE         (512)
50 #endif /* DEMO_ARP_CACHE_SIZE  */
51 
52 #ifndef DEMO_IP_THREAD_PRIORITY
53 #define DEMO_IP_THREAD_PRIORITY     (1)
54 #endif /* DEMO_IP_THREAD_PRIORITY */
55 
56 #ifdef DEMO_DHCP_DISABLE
57 #ifndef DEMO_IPV4_ADDRESS
58 /*#define DEMO_IPV4_ADDRESS         IP_ADDRESS(192, 168, 100, 33)*/
59 #error "SYMBOL DEMO_IPV4_ADDRESS must be defined. This symbol specifies the IP address of device. "
60 #endif /* DEMO_IPV4_ADDRESS */
61 
62 #ifndef DEMO_IPV4_MASK
63 /*#define DEMO_IPV4_MASK            0xFFFFFF00UL*/
64 #error "SYMBOL DEMO_IPV4_MASK must be defined. This symbol specifies the IP address mask of device. "
65 #endif /* DEMO_IPV4_MASK */
66 
67 #ifndef DEMO_GATEWAY_ADDRESS
68 /*#define DEMO_GATEWAY_ADDRESS      IP_ADDRESS(192, 168, 100, 1)*/
69 #error "SYMBOL DEMO_GATEWAY_ADDRESS must be defined. This symbol specifies the gateway address for routing. "
70 #endif /* DEMO_GATEWAY_ADDRESS */
71 
72 #ifndef DEMO_DNS_SERVER_ADDRESS
73 /*#define DEMO_DNS_SERVER_ADDRESS   IP_ADDRESS(192, 168, 100, 1)*/
74 #error "SYMBOL DEMO_DNS_SERVER_ADDRESS must be defined. This symbol specifies the dns server address for routing. "
75 #endif /* DEMO_DNS_SERVER_ADDRESS */
76 #else
77 #define DEMO_IPV4_ADDRESS           IP_ADDRESS(0, 0, 0, 0)
78 #define DEMO_IPV4_MASK              IP_ADDRESS(0, 0, 0, 0)
79 #endif /* DEMO_DHCP_DISABLE */
80 
81 #ifndef NETWORK_DRIVER
82 #define NETWORK_DRIVER              _nx_pcap_network_driver
83 #endif /* NETWORK_DRIVER */
84 
85 
86 static TX_THREAD        demo_helper_thread;
87 static NX_PACKET_POOL   pool_0;
88 static NX_IP            ip_0;
89 static NX_DNS           dns_0;
90 #ifndef DEMO_DHCP_DISABLE
91 static NX_DHCP          dhcp_0;
92 #endif /* DEMO_DHCP_DISABLE  */
93 
94 
95 /* Define the stack/cache for ThreadX.  */
96 static ULONG demo_ip_stack[DEMO_IP_STACK_SIZE / sizeof(ULONG)];
97 #ifndef DEMO_POOL_STACK_USER
98 static ULONG demo_pool_stack[DEMO_POOL_SIZE / sizeof(ULONG)];
99 static ULONG demo_pool_stack_size = sizeof(demo_pool_stack);
100 #else
101 extern ULONG demo_pool_stack[];
102 extern ULONG demo_pool_stack_size;
103 #endif
104 static ULONG demo_arp_cache_area[DEMO_ARP_CACHE_SIZE / sizeof(ULONG)];
105 static ULONG demo_helper_thread_stack[DEMO_HELPER_STACK_SIZE / sizeof(ULONG)];
106 
107 /* Define the prototypes for demo thread.  */
108 static void demo_helper_thread_entry(ULONG parameter);
109 static void test_entry(void **state);
110 
111 #ifndef DEMO_DHCP_DISABLE
112 static void dhcp_wait();
113 #endif /* DEMO_DHCP_DISABLE */
114 
115 static UINT dns_create();
116 
117 static UINT unix_time_get(ULONG *unix_time);
118 
119 /* Include the platform IP driver. */
120 extern void NETWORK_DRIVER(NX_IP_DRIVER*);
121 
122 int g_argc = 0;
123 char **g_argv = NULL;
124 
125 /* Define main entry point.  */
main(int argc,char ** argv)126 int main(int argc, char **argv)
127 {
128 
129     /* Initialize random seed. */
130     srand(time(0));
131 
132     /* Save arguments passed from command line. */
133     g_argc = argc;
134     g_argv = argv;
135 
136     /* Enter the ThreadX kernel.  */
137     tx_kernel_enter();
138 }
139 
140 /* Define what the initial system looks like.  */
tx_application_define(void * first_unused_memory)141 void    tx_application_define(void *first_unused_memory)
142 {
143 
144 UINT  status;
145 
146     /* Initialize the NetX system.  */
147     nx_system_initialize();
148 
149     /* Create a packet pool.  */
150     status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", DEMO_PACKET_SIZE,
151             (UCHAR *)demo_pool_stack , demo_pool_stack_size);
152 
153     /* Check for pool creation error.  */
154     if (status)
155     {
156         printf("nx_packet_pool_create fail: %u\r\n", status);
157         return;
158     }
159 
160     /* Create an IP instance.  */
161     status = nx_ip_create(&ip_0, "NetX IP Instance 0",
162                           DEMO_IPV4_ADDRESS, DEMO_IPV4_MASK,
163                           &pool_0, NETWORK_DRIVER,
164                           (UCHAR*)demo_ip_stack, sizeof(demo_ip_stack),
165                           DEMO_IP_THREAD_PRIORITY);
166 
167     /* Check for IP create errors.  */
168     if (status)
169     {
170         printf("nx_ip_create fail: %u\r\n", status);
171         return;
172     }
173 
174     /* Enable ARP and supply ARP cache memory for IP Instance 0.  */
175     status = nx_arp_enable(&ip_0, (VOID *)demo_arp_cache_area, sizeof(demo_arp_cache_area));
176 
177     /* Check for ARP enable errors.  */
178     if (status)
179     {
180         printf("nx_arp_enable fail: %u\r\n", status);
181         return;
182     }
183 
184     /* Enable ICMP traffic.  */
185     status = nx_icmp_enable(&ip_0);
186 
187     /* Check for ICMP enable errors.  */
188     if (status)
189     {
190         printf("nx_icmp_enable fail: %u\r\n", status);
191         return;
192     }
193 
194     /* Enable TCP traffic.  */
195     status = nx_tcp_enable(&ip_0);
196 
197     /* Check for TCP enable errors.  */
198     if (status)
199     {
200         printf("nx_tcp_enable fail: %u\r\n", status);
201         return;
202     }
203 
204     /* Enable UDP traffic.  */
205     status = nx_udp_enable(&ip_0);
206 
207     /* Check for UDP enable errors.  */
208     if (status)
209     {
210         printf("nx_udp_enable fail: %u\r\n", status);
211         return;
212     }
213 
214     /* Initialize TLS.  */
215     nx_secure_tls_initialize();
216 
217     /* Create demo helper thread. */
218     status = tx_thread_create(&demo_helper_thread, "Demo Thread",
219                               demo_helper_thread_entry, 0,
220                               demo_helper_thread_stack, DEMO_HELPER_STACK_SIZE,
221                               DEMO_HELPER_THREAD_PRIORITY, DEMO_HELPER_THREAD_PRIORITY,
222                               TX_NO_TIME_SLICE, TX_AUTO_START);
223 
224     /* Check status.  */
225     if (status)
226     {
227         printf("Demo helper thread creation fail: %u\r\n", status);
228         return;
229     }
230 }
231 
232 /* Define demo helper thread entry.  */
demo_helper_thread_entry(ULONG parameter)233 void demo_helper_thread_entry(ULONG parameter)
234 {
235     const struct CMUnitTest tests[] =
236     {
237         cmocka_unit_test(test_entry),
238     };
239 
240     setbuf(stdout, NULL);
241     exit(cmocka_run_group_tests(tests, NULL, NULL));
242 }
243 
log_callback(az_log_classification classification,UCHAR * msg,UINT msg_len)244 static void log_callback(az_log_classification classification, UCHAR *msg, UINT msg_len)
245 {
246     if (classification == AZ_LOG_IOT_AZURERTOS)
247     {
248         printf("%.*s", msg_len, (CHAR *)msg);
249     }
250 }
251 
test_entry(void ** state)252 static void test_entry(void **state)
253 {
254 UINT    status;
255 ULONG   ip_address = 0;
256 ULONG   network_mask = 0;
257 ULONG   gateway_address = 0;
258 
259 #ifndef DEMO_DHCP_DISABLE
260     dhcp_wait();
261 #else
262     nx_ip_gateway_address_set(&ip_0, DEMO_GATEWAY_ADDRESS);
263 #endif /* DEMO_DHCP_DISABLE  */
264 
265     /* Get IP address and gateway address. */
266     nx_ip_address_get(&ip_0, &ip_address, &network_mask);
267     nx_ip_gateway_address_get(&ip_0, &gateway_address);
268 
269     /* Output IP address and gateway address. */
270     printf("IP address: %lu.%lu.%lu.%lu\r\n",
271            (ip_address >> 24),
272            (ip_address >> 16 & 0xFF),
273            (ip_address >> 8 & 0xFF),
274            (ip_address & 0xFF));
275     printf("Mask: %lu.%lu.%lu.%lu\r\n",
276            (network_mask >> 24),
277            (network_mask >> 16 & 0xFF),
278            (network_mask >> 8 & 0xFF),
279            (network_mask & 0xFF));
280     printf("Gateway: %lu.%lu.%lu.%lu\r\n",
281            (gateway_address >> 24),
282            (gateway_address >> 16 & 0xFF),
283            (gateway_address >> 8 & 0xFF),
284            (gateway_address & 0xFF));
285 
286     /* Create DNS.  */
287     status = dns_create();
288 
289     /* Check for DNS create errors.  */
290     if (status)
291     {
292         printf("dns_create fail: %u\r\n", status);
293         return;
294     }
295 
296     nx_azure_iot_log_init(log_callback);
297 
298     /* Start demo.  */
299     demo_entry(&ip_0, &pool_0, &dns_0, unix_time_get);
300 }
301 
302 #ifndef DEMO_DHCP_DISABLE
dhcp_wait()303 static void dhcp_wait()
304 {
305 ULONG   actual_status;
306 
307     printf("DHCP In Progress...\r\n");
308 
309     /* Create the DHCP instance.  */
310     nx_dhcp_create(&dhcp_0, &ip_0, "DHCP Client");
311 
312     /* Start the DHCP Client.  */
313     nx_dhcp_start(&dhcp_0);
314 
315     /* Wait util address is solved. */
316     nx_ip_status_check(&ip_0, NX_IP_ADDRESS_RESOLVED, &actual_status, NX_WAIT_FOREVER);
317 }
318 #endif /* DEMO_DHCP_DISABLE  */
319 
dns_create()320 static UINT dns_create()
321 {
322 
323 UINT    status;
324 ULONG   dns_server_address[3];
325 UINT    dns_server_address_size = 12;
326 
327     /* Create a DNS instance for the Client.  Note this function will create
328        the DNS Client packet pool for creating DNS message packets intended
329        for querying its DNS server. */
330     status = nx_dns_create(&dns_0, &ip_0, (UCHAR *)"DNS Client");
331     if (status)
332     {
333         return(status);
334     }
335 
336     /* Is the DNS client configured for the host application to create the packet pool? */
337 #ifdef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL
338 
339     /* Yes, use the packet pool created above which has appropriate payload size
340        for DNS messages. */
341     status = nx_dns_packet_pool_set(&dns_0, ip_0.nx_ip_default_packet_pool);
342     if (status)
343     {
344         nx_dns_delete(&dns_0);
345         return(status);
346     }
347 #endif /* NX_DNS_CLIENT_USER_CREATE_PACKET_POOL */
348 
349 #ifndef DEMO_DHCP_DISABLE
350     /* Retrieve DNS server address.  */
351     nx_dhcp_interface_user_option_retrieve(&dhcp_0, 0, NX_DHCP_OPTION_DNS_SVR, (UCHAR *)(dns_server_address),
352                                            &dns_server_address_size);
353 #else
354     dns_server_address[0] = DEMO_DNS_SERVER_ADDRESS;
355 #endif /* DEMO_DHCP_DISABLE */
356 
357     /* Add an IPv4 server address to the Client list. */
358     status = nx_dns_server_add(&dns_0, dns_server_address[0]);
359     if (status)
360     {
361         nx_dns_delete(&dns_0);
362         return(status);
363     }
364 
365     /* Output DNS Server address.  */
366     printf("DNS Server address: %lu.%lu.%lu.%lu\r\n",
367            (dns_server_address[0] >> 24),
368            (dns_server_address[0] >> 16 & 0xFF),
369            (dns_server_address[0] >> 8 & 0xFF),
370            (dns_server_address[0] & 0xFF));
371 
372     return(NX_SUCCESS);
373 }
374 
unix_time_get(ULONG * unix_time)375 static UINT unix_time_get(ULONG *unix_time)
376 {
377 
378     *unix_time = (ULONG)time(NULL);
379 
380     return(NX_SUCCESS);
381 }
382