1 /* This is a small demo of DHCP Client for the high-performance NetX IP stack.  */
2 
3 #include   "tx_api.h"
4 #include   "nx_api.h"
5 #ifndef NX_DISABLE_IPV4
6 #include   "nxd_dhcp_client.h"
7 #include   "nxd_dhcp_server.h"
8 
9 #define     DEMO_STACK_SIZE             4096
10 #define     NX_PACKET_SIZE              1536
11 #define     NX_PACKET_POOL_SIZE         NX_PACKET_SIZE * 8
12 
13 #define     NX_DHCP_SERVER_IP_ADDRESS_0 IP_ADDRESS(10,0,0,1)
14 #define     START_IP_ADDRESS_LIST_0     IP_ADDRESS(10,0,0,10)
15 #define     END_IP_ADDRESS_LIST_0       IP_ADDRESS(10,0,0,19)
16 
17 #define     NX_DHCP_SUBNET_MASK_0       IP_ADDRESS(255,255,255,0)
18 #define     NX_DHCP_DEFAULT_GATEWAY_0   IP_ADDRESS(10,0,0,1)
19 #define     NX_DHCP_DNS_SERVER_0        IP_ADDRESS(10,0,0,1)
20 
21 /* Define the interface index.  */
22 #define     NX_DHCP_INTERFACE_INDEX     0
23 
24 /* If defined, the host requests a (previous) client IP address. */
25 /*
26 #define REQUEST_CLIENT_IP
27 */
28 
29 #ifdef REQUEST_CLIENT_IP
30 /* Request a specific IP address using the DHCP client address option. */
31 #define     NX_DHCP_CLIENT_IP_ADDRESS   IP_ADDRESS(10,0,0,18)
32 
33 /* If defined NX_TRUE, the client requests to jump to the boot state and skip the DISCOVER message.  */
34 #define     SKIP_DISCOVER_MESSAGE       NX_TRUE
35 #endif
36 
37 
38 
39 /* Define the ThreadX and NetX object control blocks...  */
40 TX_THREAD               client_thread;
41 NX_PACKET_POOL          client_pool;
42 NX_IP                   client_ip;
43 NX_DHCP                 dhcp_client;
44 
45 TX_THREAD               server_thread;
46 NX_PACKET_POOL          server_pool;
47 NX_IP                   server_ip;
48 NX_DHCP_SERVER          dhcp_server;
49 
50 /* Define the counters used in the demo application...  */
51 
52 ULONG                   client_thread_counter;
53 ULONG                   state_changes;
54 ULONG                   error_counter;
55 CHAR                    *pointer;
56 
57 UCHAR message[50] = "My Ping Request!" ;
58 
59 
60 /* Define thread prototypes.  */
61 
62 void    server_thread_entry(ULONG thread_input);
63 void    client_thread_entry(ULONG thread_input);
64 void    dhcp_state_change(NX_DHCP *dhcp_ptr, UCHAR new_state);
65 
66 /******** Optionally substitute your Ethernet driver here. ***********/
67 void    _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req);
68 
69 /* Define main entry point.  */
70 
main()71 int main()
72 {
73 
74     /* Enter the ThreadX kernel.  */
75     tx_kernel_enter();
76     return 0;
77 }
78 
79 
80 /* Define what the initial system looks like.  */
81 
tx_application_define(void * first_unused_memory)82 void    tx_application_define(void *first_unused_memory)
83 {
84 
85 UINT    status;
86 
87 
88     /* Setup the working pointer.  */
89     pointer = (CHAR *) first_unused_memory;
90 
91     /* Create the client thread.  */
92     tx_thread_create(&client_thread, "thread client", client_thread_entry, 0,
93             pointer, DEMO_STACK_SIZE,
94             4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
95     pointer = pointer + DEMO_STACK_SIZE;
96 
97     /* Create the server thread.  */
98     tx_thread_create(&server_thread, "thread server", server_thread_entry, 0,
99             pointer, DEMO_STACK_SIZE,
100             3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);
101     pointer = pointer + DEMO_STACK_SIZE;
102 
103     /* Initialize the NetX system.  */
104     nx_system_initialize();
105 
106     /* Create the client packet pool.  */
107     status = nx_packet_pool_create(&client_pool, "NetX Main Packet Pool", 1024, pointer, NX_PACKET_POOL_SIZE);
108     pointer = pointer + NX_PACKET_POOL_SIZE;
109 
110     /* Check for pool creation error.  */
111     if (status)
112         return;
113 
114     /* Create the server packet pool.  */
115     status = nx_packet_pool_create(&server_pool, "NetX Main Packet Pool", 1024, pointer, NX_PACKET_POOL_SIZE);
116     pointer = pointer + NX_PACKET_POOL_SIZE;
117 
118     /* Check for pool creation error.  */
119     if (status)
120         return;
121 
122     /* Create an IP instance for the DHCP Client.  */
123     status = nx_ip_create(&client_ip, "DHCP Client", IP_ADDRESS(0, 0, 0, 0), 0xFFFFFF00UL, &client_pool, _nx_ram_network_driver, pointer, 2048, 1);
124     pointer = pointer + 2048;
125 
126     /* Check for IP create errors.  */
127     if (status)
128         return;
129 
130     /* Create an IP instance for the DHCP Server.  */
131     status = nx_ip_create(&server_ip, "DHCP Server", NX_DHCP_SERVER_IP_ADDRESS_0, 0xFFFFFF00UL, &server_pool, _nx_ram_network_driver, pointer, 2048, 1);
132     pointer = pointer + 2048;
133 
134     /* Check for IP create errors.  */
135     if (status)
136         return;
137 
138     /* Enable ARP and supply ARP cache memory for DHCP Client IP.  */
139     status = nx_arp_enable(&client_ip, (void *) pointer, 1024);
140     pointer = pointer + 1024;
141 
142     /* Enable ARP and supply ARP cache memory for DHCP Server IP.  */
143     status += nx_arp_enable(&server_ip, (void *) pointer, 1024);
144     pointer = pointer + 1024;
145 
146     /* Check for ARP enable errors.  */
147     if (status)
148         return;
149 
150     /* Enable UDP traffic.  */
151     status = nx_udp_enable(&client_ip);
152     status += nx_udp_enable(&server_ip);
153 
154     /* Check for UDP enable errors.  */
155     if (status)
156         return;
157 
158     /* Enable ICMP.  */
159     status = nx_icmp_enable(&client_ip);
160     status += nx_icmp_enable(&server_ip);
161 
162     /* Check for errors.  */
163     if (status)
164         return;
165 }
166 
167 /* Define the server thread.  */
168 
server_thread_entry(ULONG thread_input)169 void    server_thread_entry(ULONG thread_input)
170 {
171 
172 UINT        status;
173 UINT        addresses_added;
174 
175     NX_PARAMETER_NOT_USED(thread_input);
176 
177     /* Modified the mtu size to avoid fragmenting the DHCP packet since the default mtu size is 128 in _nx_ram_network_driver.  */
178     status = nx_ip_interface_mtu_set(&server_ip, NX_DHCP_INTERFACE_INDEX, 1500);
179 
180     /* Check for MTU set errors.  */
181     if (status)
182         return;
183 
184     /* Create the DHCP Server.  */
185     status = nx_dhcp_server_create(&dhcp_server, &server_ip, pointer, DEMO_STACK_SIZE,
186                                    "DHCP Server", &server_pool);
187     pointer = pointer + DEMO_STACK_SIZE;
188 
189     /* Check for errors creating the DHCP Server. */
190     if (status)
191         return;
192 
193     /* Load the assignable DHCP IP addresses for the first interface.  */
194     status = nx_dhcp_create_server_ip_address_list(&dhcp_server, NX_DHCP_INTERFACE_INDEX, START_IP_ADDRESS_LIST_0,
195                                                    END_IP_ADDRESS_LIST_0, &addresses_added);
196 
197     /* Check for errors creating the list. */
198     if (status)
199         return;
200 
201     /* Verify all the addresses were added to the list. */
202     if (addresses_added != 10)
203         return;
204 
205     /* Set the interface network parameters.  */
206     status = nx_dhcp_set_interface_network_parameters(&dhcp_server, NX_DHCP_INTERFACE_INDEX, NX_DHCP_SUBNET_MASK_0,
207                                                       NX_DHCP_DEFAULT_GATEWAY_0, NX_DHCP_DNS_SERVER_0);
208 
209     /* Check for errors setting network parameters. */
210     if (status)
211         return;
212 
213     /* Start DHCP Server task.  */
214     status = nx_dhcp_server_start(&dhcp_server);
215 
216     /* Check for errors starting up the DHCP server.  */
217     if (status)
218     return;
219 }
220 
221 
222 /* Define the client thread.  */
223 
client_thread_entry(ULONG thread_input)224 void    client_thread_entry(ULONG thread_input)
225 {
226 
227 UINT        status;
228 UINT        actual_status;
229 UINT        length;
230 UINT        ping = NX_TRUE;
231 UINT        run_dhcp_client = NX_TRUE;
232 NX_PACKET   *my_packet;
233 
234     NX_PARAMETER_NOT_USED(thread_input);
235 
236     /* Modified the mtu size to avoid fragmenting the DHCP packet since the default mtu size is 128 in _nx_ram_network_driver.  */
237     status = nx_ip_interface_mtu_set(&client_ip, NX_DHCP_INTERFACE_INDEX, 1500);
238 
239     /* Check for MTU set errors.  */
240     if (status)
241         return;
242 
243     /* Create the DHCP instance.  */
244     status = nx_dhcp_create(&dhcp_client, &client_ip, "DHCP-CLIENT");
245     if (status)
246         return;
247 
248 #ifdef REQUEST_CLIENT_IP
249     /* Request a specific IP address using the DHCP client address option. */
250     status = nx_dhcp_request_client_ip(&dhcp_client, NX_DHCP_CLIENT_IP_ADDRESS, SKIP_DISCOVER_MESSAGE);
251     if (status)
252         error_counter++;
253 #endif
254 
255     /* Register state change variable.  */
256     status = nx_dhcp_state_change_notify(&dhcp_client, dhcp_state_change);
257     if (status)
258         error_counter++;
259 
260     /* Start the DHCP Client.  */
261     nx_dhcp_start(&dhcp_client);
262     while(run_dhcp_client)
263     {
264 
265         /* Wait for DHCP to assign the IP address.  */
266         do
267         {
268 
269             /* Check for address resolution.  */
270             status = nx_ip_status_check(&client_ip, NX_IP_ADDRESS_RESOLVED, (ULONG *) &actual_status, NX_IP_PERIODIC_RATE);
271 
272             /* Check status.  */
273             if (status)
274             {
275                 /* wait a bit. */
276                 tx_thread_sleep(NX_IP_PERIODIC_RATE);
277             }
278 
279         } while (status != NX_SUCCESS);
280 
281         length = sizeof(message);
282 
283         while(ping)
284         {
285 
286             /* Send pings to another host on the network...  */
287             status = nx_icmp_ping(&client_ip, NX_DHCP_SERVER_IP_ADDRESS_0, (CHAR *)message, length, &my_packet, NX_IP_PERIODIC_RATE);
288             if (status)
289                error_counter++;
290             else
291                 nx_packet_release(my_packet);
292 
293             /* Increment counter.  */
294             client_thread_counter++;
295 
296             /* Sleep for a few ticks...  */
297             tx_thread_sleep(NX_IP_PERIODIC_RATE);
298         }
299 
300         /* Use this API to send a message to the server, e.g. a DECLINE if the IP address is owned by another host.
301         nx_dhcp_send_request(&dhcp_client, NX_DHCP_TYPE_DHCPDECLINE);
302         */
303 
304         /* Use this API to release an IP address if the host is switching networks or running the host through DHCP cycles.
305         nx_dhcp_release(&dhcp_client);
306         */
307 
308         /* Stopping the DHCP client. */
309         nx_dhcp_stop(&dhcp_client);
310 
311         tx_thread_sleep(NX_IP_PERIODIC_RATE);
312 
313         /* Use this API to clear the network parameters and restart the client in the INIT state. */
314         nx_dhcp_reinitialize(&dhcp_client);
315 
316         /* Resume the DHCP client thread. */
317         nx_dhcp_start(&dhcp_client);
318 
319         /* Ok to resume ping attempts. */
320         ping = NX_TRUE;
321     }
322 
323     /* All done. Return resources to NetX and ThreadX. */
324     nx_dhcp_delete(&dhcp_client);
325 
326     return;
327 }
328 
329 
dhcp_state_change(NX_DHCP * dhcp_ptr,UCHAR new_state)330 void dhcp_state_change(NX_DHCP *dhcp_ptr, UCHAR new_state)
331 {
332 
333     NX_PARAMETER_NOT_USED(dhcp_ptr);
334     NX_PARAMETER_NOT_USED(new_state);
335 
336     /* Increment state changes counter.  */
337     state_changes++;
338 
339     return;
340 }
341 #endif /* NX_DISABLE_IPV4 */
342