1 /* This is a small demo of DHCP Client for multiple interfaces for the high-performance NetX IP stack.
2 
3    It is suggested that applications call interface specific API to do specific action on the specified
4    interface if DHCP is enabled on multiple interfaces at the same time.
5    Example of a device possibly with a secondary interfaces attached, and DHCP Client having only the secondary
6    interface enabled for DHCP:
7 
8 #if (NX_MAX_PHYSICAL_INTERFACES >= 2) && (NX_DHCP_CLIENT_MAX_RECORDS >= 2)
9 
10        Client configured for DHCP enabled on more than one interface. Use the interface specific service to
11        request Client IP on the secondary interface.
12 
13        status = nx_dhcp_interface_request_client_ip(&dhcp_client, 1, NX_DHCP_CLIENT_IP_ADDRESS_1, SKIP_DISCOVER_MESSAGE);
14 #else
15         Client is configured for one interface to be enabled for DHCP. Use the non-interface specific service
16         to perform the request Client IP action on the interface index that the Client has set for DHCP.
17 
18         Note: the application must first call nx_dhcp_set_interface_index() to set the secondary interface as the interface
19         to run DHCP on. Otherwise DHCP runs on the primary interface, by default.
20 
21         status = nx_dhcp_request_client_ip(&dhcp_client, NX_DHCP_CLIENT_IP_ADDRESS_1, SKIP_DISCOVER_MESSAGE);
22 #endif
23 
24         if (status)
25             error_counter++;
26 
27 */
28 
29 #include   "tx_api.h"
30 #include   "nx_api.h"
31 #include   "nxd_dhcp_client.h"
32 
33 #define     DEMO_STACK_SIZE             4096
34 #define     NX_PACKET_SIZE              1536
35 #define     NX_PACKET_POOL_SIZE         NX_PACKET_SIZE * 8
36 
37 
38 /* If defined, the host requests a (previous) client IP address. */
39 /*
40 #define REQUEST_CLIENT_IP
41 */
42 
43 #ifdef REQUEST_CLIENT_IP
44 /* Request a specific IP address using the DHCP client address option. */
45 #define     NX_DHCP_CLIENT_IP_ADDRESS_0   IP_ADDRESS(192, 168, 0, 18)
46 #define     NX_DHCP_CLIENT_IP_ADDRESS_1   IP_ADDRESS(10, 0, 0, 18)
47 
48 /* If defined NX_TRUE, the client requests to jump to the boot state and skip the DISCOVER message.  */
49 #define     SKIP_DISCOVER_MESSAGE       NX_TRUE
50 #endif /* REQUEST_CLIENT_IP  */
51 
52 /* Define the ThreadX and NetX object control blocks...  */
53 TX_THREAD               client_thread;
54 NX_PACKET_POOL          client_pool;
55 NX_IP                   client_ip;
56 NX_DHCP                 dhcp_client;
57 
58 
59 /* Define the counters used in the demo application...  */
60 ULONG                   client_thread_counter;
61 ULONG                   state_changes;
62 ULONG                   error_counter;
63 CHAR                    *pointer;
64 
65 
66 /* Define thread prototypes.  */
67 void    client_thread_entry(ULONG thread_input);
68 void    dhcp_interface_state_change(NX_DHCP *dhcp_ptr, UINT iface_index, UCHAR new_state);
69 
70 /******** Optionally substitute your Ethernet driver here. ***********/
71 void    _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req);
72 
73 /* Define main entry point.  */
74 
main()75 int main()
76 {
77 
78     /* Enter the ThreadX kernel.  */
79     tx_kernel_enter();
80     return 0;
81 }
82 
83 
84 /* Define what the initial system looks like.  */
tx_application_define(void * first_unused_memory)85 void    tx_application_define(void *first_unused_memory)
86 {
87 
88 UINT    status;
89 
90 
91     /* Setup the working pointer.  */
92     pointer = (CHAR *) first_unused_memory;
93 
94     /* Create the client thread.  */
95     tx_thread_create(&client_thread, "thread client", client_thread_entry, 0,
96             pointer, DEMO_STACK_SIZE,
97             4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
98     pointer = pointer + DEMO_STACK_SIZE;
99 
100     /* Initialize the NetX system.  */
101     nx_system_initialize();
102 
103     /* Create the client packet pool.  */
104     status = nx_packet_pool_create(&client_pool, "NetX Main Packet Pool", 1024, pointer, NX_PACKET_POOL_SIZE);
105     pointer = pointer + NX_PACKET_POOL_SIZE;
106 
107     /* Check for pool creation error.  */
108     if (status)
109         return;
110 
111     /* Create an IP instance for the DHCP Client.  */
112     status = nx_ip_create(&client_ip, "DHCP Client", IP_ADDRESS(0, 0, 0, 0), 0xFFFFFF00UL, &client_pool, _nx_ram_network_driver, pointer, 2048, 1);
113     pointer = pointer + 2048;
114 
115     /* Check for IP create errors.  */
116     if (status)
117         return;
118 
119     /* Enable ARP and supply ARP cache memory for DHCP Client IP.  */
120     status = nx_arp_enable(&client_ip, (void *) pointer, 1024);
121     pointer = pointer + 1024;
122 
123     /* Check for ARP enable errors.  */
124     if (status)
125         return;
126 
127     /* Enable UDP traffic.  */
128     status = nx_udp_enable(&client_ip);
129 
130     /* Check for UDP enable errors.  */
131     if (status)
132         return;
133 
134     /* Enable TCP traffic.  */
135     status = nx_tcp_enable(&client_ip);
136 
137     /* Check for TCP enable errors.  */
138     if (status)
139         return;
140 
141     /* Enable ICMP.  */
142     status = nx_icmp_enable(&client_ip);
143 
144     /* Check for errors.  */
145     if (status)
146         return;
147 }
148 
149 
150 /* Define the client thread.  */
client_thread_entry(ULONG thread_input)151 void    client_thread_entry(ULONG thread_input)
152 {
153 
154 UINT        status;
155 UINT        actual_status;
156 ULONG       server_address;
157 
158     NX_PARAMETER_NOT_USED(thread_input);
159 
160      /*  Check if there are multiple network interfaces */
161 
162 #if (NX_MAX_PHYSICAL_INTERFACES >= 2) && (NX_DHCP_CLIENT_MAX_RECORDS >= 2)
163     /* There are.  Attach the second interface.  */
164     status = nx_ip_interface_attach(&client_ip, "Second interface", IP_ADDRESS(0, 0, 0, 0), 0xFFFFFF00UL,_nx_ram_network_driver);
165 
166     /* Check status.  */
167     if (status)
168         return;
169 #endif
170 
171     /* Create the DHCP instance; this automatically enables DHCP on the primary interface.  */
172     status = nx_dhcp_create(&dhcp_client, &client_ip, "dhcp_client");
173     if (status)
174         return;
175 
176     /* Check if there are multiple network interfaces and if DHCP CLient is set up to run DHCP on multiple interfaces. */
177 #if (NX_MAX_PHYSICAL_INTERFACES >= 2) && (NX_DHCP_CLIENT_MAX_RECORDS >= 2)
178     /* Enable DHCP for specified interface(1:second interface).  */
179     status = nx_dhcp_interface_enable(&dhcp_client, 1);
180     if (status)
181         return;
182 #else
183     /* for NX_MAX_PHYSICAL_INTERFACES >= 2, NX_DHCP_CLIENT_MAX_RECORDS == 1*/
184     status = nx_dhcp_set_interface_index(&dhcp_client, 1);
185 #endif
186 
187 #ifdef REQUEST_CLIENT_IP
188 
189     /* nx_dhcp_request_client_ip() requests a specific IP address for DHCP client address option on the first DHCP enabled (valid) interface it finds. */
190     /* Suggest using nx_dhcp_interface_request_client_ip() on a single interface if DHCP is enabled on multiple interfaces
191        status = nx_dhcp_interface_request_client_ip(&dhcp_client, 1, NX_DHCP_CLIENT_IP_ADDRESS_0, SKIP_DISCOVER_MESSAGE)
192            requests the IP address on the specified address (1:second interface)
193     */
194     status = nx_dhcp_request_client_ip(&dhcp_client, NX_DHCP_CLIENT_IP_ADDRESS_0, SKIP_DISCOVER_MESSAGE);
195     if (status)
196         error_counter++;
197 
198 #endif /* REQUEST_CLIENT_IP  */
199 
200     /* Clear the broadcast flag.  */
201     /* nx_dhcp_clear_broadcast_flag(&dhcp_client) clears the broadcast flag on all DHCP enabled interfaces.
202        Suggest using nx_dhcp_interface_clear_broadcast_flag() to clear the flag on one interface if DHCP is enabled on multiple interfaces
203        status = nx_dhcp_interface_clear_broadcast_flag(&dhcp_client, 1) clears the broadcast flag on the specified interface(1:second interface)
204     */
205     status = nx_dhcp_clear_broadcast_flag(&dhcp_client, NX_TRUE);
206     if (status)
207         error_counter++;
208 
209 
210     /* Register the interface state change callback.  */
211     status = nx_dhcp_interface_state_change_notify(&dhcp_client, dhcp_interface_state_change);
212     if (status)
213         error_counter++;
214 
215     /* Start the DHCP Client.  */
216     /* nx_dhcp_start(&dhcp_client) start DHCP for all DHCP enabled interfaces.
217        Suggest using nx_dhcp_interface_start() to start DHCP on one interface if DHCP is enabled on multiple interfaces
218        status = nx_dhcp_interface_start(&dhcp_client, 1) starts DHCP on the specified interface (1:second interface)
219     */
220     status = nx_dhcp_start(&dhcp_client);
221 
222     /* Loop to test DHCP.  */
223     while (1)
224     {
225 
226         /* Check the address resolution for primary interface.  */
227         nx_ip_interface_status_check(&client_ip, 0, NX_IP_ADDRESS_RESOLVED, (ULONG *)&actual_status, NX_WAIT_FOREVER);
228 
229         /* Check the address resolution for second interface.  */
230         nx_ip_interface_status_check(&client_ip, 1, NX_IP_ADDRESS_RESOLVED, (ULONG *)&actual_status, NX_WAIT_FOREVER);
231 
232         /* Use this API to get the Server address.  */
233         /* nx_dhcp_server_address_get(&dhcp_client, &server_address) get the server address for the first DHCP enabled ("valid") interface.
234            Suggest using nx_dhcp_interface_server_address_get() to get the server address on a specific interface if DHCP is enabled on multiple interfaces
235            status = nx_dhcp_interface_server_address_get(&dhcp_client, 1, &server_address) returns the server address on specified interface(1:second interface)
236         */
237         status = nx_dhcp_server_address_get(&dhcp_client, &server_address);
238         if (status)
239             error_counter++;
240 
241 
242         /* Release the IP address the Client is bound to.
243 
244            Use the nx_dhcp_release() API to release an IP address if the host is switching networks or running the host through DHCP cycles.
245            Note that it is not necessary to call nx_dhcp_reinitialize() or nx_dhcp_interface_reinitialize() after calling this
246            function. DHCP on this interface (or interfaces) is ready to be restarted. */
247 
248         /* nx_dhcp_release(&dhcp_client) releases the DHCP generated IP address for all DHCP enabled interfaces.
249            Suggest using nx_dhcp_interface_release() to release the IP address on a specific interface if DHCP is enabled on multiple interfaces
250            status = nx_dhcp_interface_release(&dhcp_client, 1) releases the IP address for the specified interface(1:second interface)
251         */
252         status = nx_dhcp_release(&dhcp_client);
253         if (status)
254             error_counter++;
255 
256         /* Stopping the DHCP client.
257 
258            Use this API if the Client has not reached the BOUND state. This simply stops the DHCP
259            Client.  It does not clear any network parameters or reset the Client state to NOT STARTED.  To do clear network parameters,
260            and reset the state (e.g. before calling nx_dhcp_start() on the stopped interface(s), call nx_dhcp_reinitialize() or
261            nx_dhcp_interface_reinitialize() depending which interface(s) need to be reinitialized.
262         */
263 
264         /* nx_dhcp_stop(&dhcp_client) stops DHCP on all DHCP enabled interfaces.
265            Suggest using nx_dhcp_interface_stop() to stop DHCP on a specific interface if DHCP is enabled on multiple interfaces
266            status = nx_dhcp_interface_stop(&dhcp_client, 1) stop DHCP on the specified interface(1:second interface)
267            */
268         status = nx_dhcp_stop(&dhcp_client);
269         if (status)
270             error_counter++;
271 
272         /* Sleep one second. */
273         tx_thread_sleep(NX_IP_PERIODIC_RATE);
274 
275         /* Reinitialize the Client for restarting DHCP.
276 
277            Use this API to clear the network parameters and restart the client in the not started state. */
278 
279         /* nx_dhcp_reinitialize(&dhcp_client) clears the network parameters on all DHCP enabled interfaces.
280            Suggest using nx_dhcp_interface_reinitialize() to reinitialize DHCP on a specific interface if DHCP is enabled on multiple interfaces
281            status = nx_dhcp_interface_reinitialize(&dhcp_client, 1) reinitializes DHCP on the specified interface(1:second interface)
282            */
283         status = nx_dhcp_reinitialize(&dhcp_client);
284         if (status)
285             error_counter++;
286 
287         /* Resume the DHCP client thread. */
288         /* nx_dhcp_start(&dhcp_client) start DHCP for all DHCP enabled interfaces.
289            or nx_dhcp_interface_start(&dhcp_client, 1) to start DHCP for specified interface(1:second interface) */
290         status = nx_dhcp_start(&dhcp_client);
291         if (status)
292             error_counter++;
293     }
294 
295     /* All done. Return resources to NetX and ThreadX. */
296     nx_dhcp_delete(&dhcp_client);
297 
298     return;
299 }
300 
301 
dhcp_interface_state_change(NX_DHCP * dhcp_ptr,UINT iface_index,UCHAR new_state)302 void dhcp_interface_state_change(NX_DHCP *dhcp_ptr, UINT iface_index,  UCHAR new_state)
303 {
304 
305     NX_PARAMETER_NOT_USED(dhcp_ptr);
306     NX_PARAMETER_NOT_USED(iface_index);
307     NX_PARAMETER_NOT_USED(new_state);
308 
309     /* Increment state changes counter.  */
310     state_changes++;
311 
312     return;
313 }
314 
315