1 /*
2    demo_netx_nat.c
3 
4    This is a small demo of NAT (Network Address Translation) on the high-performance
5    NetX TCP/IP stack.  This demo relies on ThreadX, NetX and NAT APIs to perform network
6    address translation for IP packets traveling between private and external networks.
7    this demo concentrates on the ICMP ping operation.
8 */
9 
10 #include   "tx_api.h"
11 #include   "nx_api.h"
12 #include   "nx_nat.h"
13 
14 extern void    test_control_return(UINT status);
15 #if defined NX_NAT_ENABLE && defined __PRODUCT_NETXDUO__ && (NX_MAX_PHYSICAL_INTERFACES >= 2)
16 
17 #define     DEMO_STACK_SIZE         2048
18 #define     DEMO_DATA               "ABCDEFGHIJKLMNOPQRSTUVWXYZ "
19 
20 /* Define the ThreadX and NetX object control blocks...  */
21 
22 static TX_THREAD                    ntest_0;
23 
24 /* Set up the NAT components. */
25 
26 /* Create a NAT instance, packet pool and translation table. */
27 
28 NX_NAT_DEVICE                       nat_server;
29 NX_IP                               nat_ip;
30 NX_IP                               local_ip;
31 NX_IP                               external_ip;
32 NX_PACKET_POOL                      nat_packet_pool;
33 UINT                                error_counter = 0;
34 
35 
36 /* Configure the NAT network parameters. */
37 
38 /* Set NetX IP packet pool packet size. This should be less than the Maximum Transmit Unit (MTU) of
39    the driver (allow enough room for the Ethernet header plus padding bytes for frame alignment).  */
40 #define NX_NAT_PACKET_SIZE                          1536
41 
42 
43 /* Set the size of the NAT IP packet pool.  */
44 #define NX_NAT_PACKET_POOL_SIZE                     (NX_NAT_PACKET_SIZE * 10)
45 
46 /* Set NetX IP helper thread stack size. */
47 #define NX_NAT_IP_THREAD_STACK_SIZE                 2048
48 
49 /* Set the server IP thread priority */
50 #define NX_NAT_IP_THREAD_PRIORITY                   2
51 
52 /* Set ARP cache size of a NAT ip instance. */
53 #define NX_NAT_ARP_CACHE_SIZE                       1024
54 
55 /* Set NAT entries memory size. */
56 #define NX_NAT_ENTRY_CACHE_SIZE                     1024
57 
58 /* Define NAT IP addresses, local host private IP addresses and external host IP address. */
59 #define NX_NAT_LOCAL_IPADR              (IP_ADDRESS(192, 168, 2, 1))
60 #define NX_NAT_LOCAL_HOST1              (IP_ADDRESS(192, 168, 2, 3))
61 #define NX_NAT_LOCAL_HOST2              (IP_ADDRESS(192, 168, 2, 10))
62 #define NX_NAT_LOCAL_GATEWAY            (IP_ADDRESS(192, 168, 2, 1))
63 #define NX_NAT_LOCAL_NETMASK            (IP_ADDRESS(255, 255, 255, 0))
64 #define NX_NAT_EXTERNAL_IPADR           (IP_ADDRESS(192, 168, 0, 10))
65 #define NX_NAT_EXTERNAL_HOST            (IP_ADDRESS(192, 168, 0, 100))
66 #define NX_NAT_EXTERNAL_GATEWAY         (IP_ADDRESS(192, 168, 0, 1))
67 #define NX_NAT_EXTERNAL_NETMASK         (IP_ADDRESS(255, 255, 255, 0))
68 
69 /* Create NAT structures for preloading NAT tables with static
70    entries for local server hosts. */
71 NX_NAT_TRANSLATION_ENTRY            server_inbound_entry_icmp;
72 
73 /* Define thread prototypes.  */
74 static void     ntest_0_entry(ULONG thread_input);
75 extern void    _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req);
76 
77 /* Define main entry point.  */
78 
main()79 int main()
80 {
81 
82     /* Enter the ThreadX kernel.  */
83     tx_kernel_enter();
84 }
85 
86 
87 /* Define what the initial system looks like.  */
88 
tx_application_define(void * first_unused_memory)89 void    tx_application_define(void *first_unused_memory)
90 {
91 
92 UINT     status;
93 UCHAR    *pointer;
94 
95     /* Initialize the NetX system. */
96     nx_system_initialize();
97 
98     /* Setup the pointer to unallocated memory.  */
99     pointer =  (UCHAR *) first_unused_memory;
100 
101     /* Create the main thread.  */
102     tx_thread_create(&ntest_0, "thread 0", ntest_0_entry, 0,
103                      pointer, DEMO_STACK_SIZE,
104                      4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
105     pointer =  pointer + DEMO_STACK_SIZE;
106 
107     /* Create NAT packet pool. */
108     status =  nx_packet_pool_create(&nat_packet_pool, "NAT Packet Pool",
109                                     NX_NAT_PACKET_SIZE, pointer,
110                                     NX_NAT_PACKET_POOL_SIZE);
111 
112     /* Update pointer to unallocated (free) memory. */
113     pointer = pointer + NX_NAT_PACKET_POOL_SIZE;
114 
115     /* Check status.  */
116     if (status)
117         return;
118 
119     /* Create IP instances for NAT server (global network) */
120     status = nx_ip_create(&nat_ip, "NAT IP Instance", NX_NAT_EXTERNAL_IPADR, NX_NAT_EXTERNAL_NETMASK,
121                           &nat_packet_pool, _nx_ram_network_driver, pointer,
122                           NX_NAT_IP_THREAD_STACK_SIZE, NX_NAT_IP_THREAD_PRIORITY);
123 
124     /* Update pointer to unallocated (free) memory. */
125     pointer =  pointer + NX_NAT_IP_THREAD_STACK_SIZE;
126 
127     /* Check status.  */
128     if (status)
129     {
130         error_counter++;
131         return;
132     }
133 
134     /* Set the private interface(private network).  */
135     status += nx_ip_interface_attach(&nat_ip, "Private Interface", NX_NAT_LOCAL_IPADR, NX_NAT_LOCAL_NETMASK, _nx_ram_network_driver);
136 
137     /* Check status.  */
138     if (status)
139     {
140         error_counter++;
141         return;
142     }
143 
144     /* Create IP instances for Local network IP instance */
145     status = nx_ip_create(&local_ip, "Local IP Instance", NX_NAT_LOCAL_HOST1, NX_NAT_LOCAL_NETMASK,
146                           &nat_packet_pool, _nx_ram_network_driver, pointer,
147                           NX_NAT_IP_THREAD_STACK_SIZE, NX_NAT_IP_THREAD_PRIORITY);
148 
149     /* Update pointer to unallocated (free) memory. */
150     pointer =  pointer + NX_NAT_IP_THREAD_STACK_SIZE;
151 
152     /* Check status.  */
153     if (status)
154     {
155         error_counter++;
156         return;
157     }
158 
159     /* Create IP instances for external network IP instance */
160     status = nx_ip_create(&external_ip, "External IP Instance", NX_NAT_EXTERNAL_HOST, NX_NAT_EXTERNAL_NETMASK,
161                           &nat_packet_pool, _nx_ram_network_driver, pointer,
162                           NX_NAT_IP_THREAD_STACK_SIZE, NX_NAT_IP_THREAD_PRIORITY);
163 
164     /* Update pointer to unallocated (free) memory. */
165     pointer =  pointer + NX_NAT_IP_THREAD_STACK_SIZE;
166 
167     /* Check status.  */
168     if (status)
169     {
170         error_counter++;
171         return;
172     }
173 
174     /* Set the global network gateway for NAT IP instance.  */
175     status = nx_ip_gateway_address_set(&nat_ip, NX_NAT_EXTERNAL_GATEWAY);
176 
177     /* Check status.  */
178     if (status)
179     {
180         error_counter++;
181         return;
182     }
183 
184     /* Set the global network gateway for Local IP instance.  */
185     status = nx_ip_gateway_address_set(&local_ip, NX_NAT_LOCAL_GATEWAY);
186 
187     /* Check status.  */
188     if (status)
189     {
190         error_counter++;
191         return;
192     }
193 
194     /* Set the global network gateway for External IP instance.  */
195     status = nx_ip_gateway_address_set(&external_ip, NX_NAT_EXTERNAL_GATEWAY);
196 
197     /* Check status.  */
198     if (status)
199     {
200         error_counter++;
201         return;
202     }
203 
204 
205     /* Enable ARP and supply ARP cache memory for NAT IP isntance. */
206     status =  nx_arp_enable(&nat_ip, (void **) pointer,
207                             NX_NAT_ARP_CACHE_SIZE);
208 
209     /* Check status.  */
210     if (status)
211     {
212         error_counter++;
213         return;
214     }
215 
216     /* Update pointer to unallocated (free) memory. */
217     pointer = pointer + NX_NAT_ARP_CACHE_SIZE;
218 
219     /* Enable ARP and supply ARP cache memory for Local IP isntance. */
220     status =  nx_arp_enable(&local_ip, (void **) pointer,
221                             NX_NAT_ARP_CACHE_SIZE);
222 
223     /* Check status.  */
224     if (status)
225     {
226         error_counter++;
227         return;
228     }
229 
230     /* Update pointer to unallocated (free) memory. */
231     pointer = pointer + NX_NAT_ARP_CACHE_SIZE;
232 
233     /* Enable ARP and supply ARP cache memory for External IP isntance. */
234     status =  nx_arp_enable(&external_ip, (void **) pointer,
235                             NX_NAT_ARP_CACHE_SIZE);
236 
237     /* Check status.  */
238     if (status)
239     {
240         error_counter++;
241         return;
242     }
243 
244     /* Update pointer to unallocated (free) memory. */
245     pointer = pointer + NX_NAT_ARP_CACHE_SIZE;
246 
247     /* Enable ICMP. */
248     nx_icmp_enable(&nat_ip);
249     nx_icmp_enable(&local_ip);
250     nx_icmp_enable(&external_ip);
251 
252     /* Create a NetX NAT server and cache with a global interface index.  */
253     status =  nx_nat_create(&nat_server, &nat_ip, 0, pointer, NX_NAT_ENTRY_CACHE_SIZE);
254 
255     /* Check status.  */
256     if (status)
257     {
258         error_counter++;
259         return;
260     }
261 
262     /* Update pointer to unallocated (free) memory. */
263     pointer = pointer + NX_NAT_ENTRY_CACHE_SIZE;
264 }
265 
266 /* Define the test threads.  */
267 
ntest_0_entry(ULONG thread_input)268 static void    ntest_0_entry(ULONG thread_input)
269 {
270 
271 UINT        status;
272 NX_PACKET   *my_packet;
273 
274     NX_PARAMETER_NOT_USED(thread_input);
275 
276     /***********************************/
277     /*       Disable NAT feature       */
278     /***********************************/
279     /* Local Host ping External Host address.  */
280     status =  nx_icmp_ping(&local_ip, NX_NAT_EXTERNAL_HOST, DEMO_DATA, sizeof(DEMO_DATA), &my_packet, NX_IP_PERIODIC_RATE);
281 
282     /* Check status.  */
283     if (status == NX_SUCCESS)
284     {
285         error_counter++;
286         return;
287     }
288 
289     /* Check the NAT forwarded count.  */
290 #ifndef NX_DISABLE_NAT_INFO
291     if ((nat_server.forwarded_packets_received != 0) || (nat_server.forwarded_packets_sent != 0) ||(nat_server.forwarded_packets_dropped != 0))
292     {
293         error_counter++;
294         return;
295     }
296 #endif
297 
298     /* External Host ping NAT External address, NAT IP instance will response the requet.  */
299     status = nx_icmp_ping(&external_ip, NX_NAT_EXTERNAL_IPADR, DEMO_DATA, sizeof(DEMO_DATA), &my_packet, NX_IP_PERIODIC_RATE);
300 
301     /* Check status.  */
302     if ((status != NX_SUCCESS) || (my_packet == NX_NULL) || (my_packet -> nx_packet_length != 28))
303     {
304         error_counter++;
305         return;
306     }
307 
308     /* Check the NAT forwarded count.  */
309 #ifndef NX_DISABLE_NAT_INFO
310     if ((nat_server.forwarded_packets_received != 0) || (nat_server.forwarded_packets_sent != 0) ||(nat_server.forwarded_packets_dropped != 0))
311     {
312         error_counter++;
313         return;
314     }
315 #endif
316 
317     /***********************************/
318     /*       Enable NAT feature        */
319     /***********************************/
320 
321     /* Enable the NAT service.  */
322     nx_nat_enable(&nat_server);
323 
324     /* Local Host ping External Host address.  */
325     status =  nx_icmp_ping(&local_ip, NX_NAT_EXTERNAL_HOST, DEMO_DATA, sizeof(DEMO_DATA), &my_packet, NX_IP_PERIODIC_RATE);
326 
327     if ((status != NX_SUCCESS) || (my_packet == NX_NULL) || (my_packet -> nx_packet_length != 28))
328     {
329         error_counter++;
330         return;
331     }
332 
333     /* Check the NAT forwarded count.  */
334 #ifndef NX_DISABLE_NAT_INFO
335     if ((nat_server.forwarded_packets_received != 2) || (nat_server.forwarded_packets_sent != 2) ||(nat_server.forwarded_packets_dropped != 0))
336     {
337         error_counter++;
338         return;
339     }
340 #endif
341 
342     /* External Host ping NAT External address, NAT IP instance will response the requet.  */
343     status =  nx_icmp_ping(&external_ip, NX_NAT_EXTERNAL_IPADR, DEMO_DATA, sizeof(DEMO_DATA), &my_packet, NX_IP_PERIODIC_RATE);
344 
345     if ((status != NX_SUCCESS) || (my_packet == NX_NULL) || (my_packet -> nx_packet_length != 28))
346     {
347         error_counter++;
348         return;
349     }
350 
351     /* Check the NAT forwarded count.  NAT receive the ping request, but can not forward this packet to local network.  discard it.  */
352 #ifndef NX_DISABLE_NAT_INFO
353     if ((nat_server.forwarded_packets_received != 3) || (nat_server.forwarded_packets_sent != 2) ||(nat_server.forwarded_packets_dropped != 1))
354     {
355         error_counter++;
356         return;
357     }
358 #endif
359 
360     /**********************************************/
361     /*       Preload a inbound entry for ICMP     */
362     /**********************************************/
363 
364     /* Calling NAT API to create a inbound entry.  */
365     status = nx_nat_inbound_entry_create(&nat_server, &server_inbound_entry_icmp, NX_NAT_LOCAL_HOST1, 0, 0, NX_PROTOCOL_ICMP);
366 
367     if (status != NX_SUCCESS)
368     {
369         error_counter++;
370         return;
371     }
372 
373     /* External Host ping NAT External address, LOCAL HOST1 will response all inbound icmp request from external network.  */
374     status =  nx_icmp_ping(&external_ip, NX_NAT_EXTERNAL_IPADR, DEMO_DATA, sizeof(DEMO_DATA), &my_packet, NX_IP_PERIODIC_RATE);
375 
376     if ((status != NX_SUCCESS) || (my_packet == NX_NULL) || (my_packet -> nx_packet_length != 28))
377     {
378         error_counter++;
379         return;
380     }
381 
382     /* Check the NAT forwarded count.  */
383 #ifndef NX_DISABLE_NAT_INFO
384     if ((nat_server.forwarded_packets_received != 5) || (nat_server.forwarded_packets_sent != 4) ||(nat_server.forwarded_packets_dropped != 1))
385     {
386         error_counter++;
387         return;
388     }
389 #endif
390 }
391 #endif
392