1 /* This demo tests the nx_ppp_restart() function.  To simulate a link down in the middle of the IPCP
2    negotiation, the thread_0/PPP_0 promotes the PPP 1 instance to LCP complete, and its IPCP state to STARTED.
3    Then the PPP0 instance is suspended as part of simulating link down.
4 
5    PPP_1 should go into a FAILED state after the max number of retries, and call the link down callback.
6    NetX PPP has a restart function which reinitializes the PPP instance so it can restart the PPP
7    protocol using nx_ppp_restart().
8 
9    The process is started again, PPP 0 is resumed, and thread 0 promotes the PPP 1 instance ahead
10    to the LCP complete state, and ICP start state.  After the second link down event, the test is complete.
11 
12    This test verifies that the NetX PPP properly clears and restarts a PPP instance, including resetting
13    the PPP state to restart the  IPCP negotiation.
14 */
15 
16 #include "tx_api.h"
17 #include "nx_api.h"
18 #include "nx_ppp.h"
19 
20 extern void         test_control_return(UINT status);
21 
22 #if !defined(NX_DISABLE_IPV4)
23 
24 /* Define demo stack size.   */
25 
26 #define DEMO_STACK_SIZE     2048
27 
28 
29 /* Define the ThreadX and NetX object control blocks...  */
30 
31 static TX_THREAD               thread_0;
32 static TX_THREAD               thread_1;
33 
34 static NX_PACKET_POOL          pool_0;
35 static NX_PACKET_POOL          pool_1;
36 
37 static NX_IP                   ip_0;
38 static NX_IP                   ip_1;
39 
40 static NX_PPP                  ppp_0;
41 static NX_PPP                  ppp_1;
42 
43 
44 /* Define the counters used in the demo application...  */
45 
46 static ULONG                   ppp_0_link_up_counter;
47 static ULONG                   ppp_0_link_down_counter;
48 static ULONG                   ppp_1_link_up_counter;
49 static ULONG                   ppp_1_link_down_counter;
50 static ULONG                   error_counter = 0;
51 static UINT                    suspend_thread = NX_TRUE;
52 
53 /* Define thread prototypes.  */
54 static void         thread_0_entry(ULONG thread_input);
55 static void         thread_1_entry(ULONG thread_input);
56 static void         link_up_callback(NX_PPP *ppp_ptr);
57 static void         link_down_callback(NX_PPP *ppp_ptr);
58 static void         ppp_0_serial_byte_output(UCHAR byte);
59 static void         ppp_1_serial_byte_output(UCHAR byte);
60 static void         invalid_packet_handler(NX_PACKET *packet_ptr);
61 
62 
63 
64 /* Define what the initial system looks like.  */
65 
66 #ifdef CTEST
test_application_define(void * first_unused_memory)67 VOID test_application_define(void *first_unused_memory)
68 #else
69 void    netx_ppp_IPCP_timeout_test_application_define(void *first_unused_memory)
70 #endif
71 {
72 
73 CHAR    *pointer;
74 UINT    status;
75 
76     /* Setup the working pointer.  */
77     pointer =  (CHAR *) first_unused_memory;
78 
79     /* Create the thread 0.  */
80     tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
81             pointer, DEMO_STACK_SIZE,
82             5, 5, TX_NO_TIME_SLICE, TX_AUTO_START);
83     pointer =  pointer + DEMO_STACK_SIZE;
84 
85     /* Create the thread 1.  */
86     tx_thread_create(&thread_1, "thread 1", thread_1_entry, 0,
87             pointer, DEMO_STACK_SIZE,
88             5, 5, TX_NO_TIME_SLICE, TX_AUTO_START);
89     pointer =  pointer + DEMO_STACK_SIZE;
90 
91     /* Initialize the NetX system.  */
92     nx_system_initialize();
93 
94     /* Create a packet pool.  */
95     status =  nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 1024, pointer, 8192);
96     pointer = pointer + 8192;
97     status +=  nx_packet_pool_create(&pool_1, "NetX Main Packet Pool",  NX_PPP_MIN_PACKET_PAYLOAD, pointer, 4096);
98     pointer = pointer + 4096;
99 
100     /* Check for pool creation error.  */
101     if (status)
102         error_counter++;
103 
104 
105     /* Create the first PPP instance.  */
106     status =  nx_ppp_create(&ppp_0, "PPP0", &ip_0, pointer, 2048, 1, &pool_0, invalid_packet_handler, ppp_0_serial_byte_output);
107     pointer =  pointer + 2048;
108 
109     /* Check for PPP create error.   */
110     if (status)
111         error_counter++;
112 
113     /* Define the IP addresses. This PPP instance is effectively the server since it has both IP addresses. */
114     status =  nx_ppp_ip_address_assign(&ppp_0, IP_ADDRESS(1, 2, 3, 4), IP_ADDRESS(1, 2, 3, 5));
115 
116     /* Check for PPP IP address assign error.   */
117     if (status)
118         error_counter++;
119 
120     /* Create an IP instance.  */
121     status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(0, 0, 0, 0), 0xFFFFF000UL, &pool_0, nx_ppp_driver,
122                           pointer, 2048, 1);
123     pointer =  pointer + 2048;
124 
125     /* Check for IP create error.   */
126     if (status)
127         error_counter++;
128 
129     /* Register the link up/down callbacks.  */
130     status =  nx_ppp_link_up_notify(&ppp_0, link_up_callback);
131     status += nx_ppp_link_down_notify(&ppp_0, link_down_callback);
132 
133     /* Check for PPP link up/down callback registration error(s).   */
134     if (status)
135         error_counter++;
136 
137     /* Create the next PPP instance.  */
138     status =  nx_ppp_create(&ppp_1, "PPP1", &ip_1, pointer, 2048, 1, &pool_1, invalid_packet_handler, ppp_1_serial_byte_output);
139     pointer =  pointer + 2048;
140 
141     /* Check for PPP create error.   */
142     if (status)
143         error_counter++;
144 
145     /* Define IP address. This PPP instance is effectively the client since it doesn't have any IP addresses. */
146     status =  nx_ppp_ip_address_assign(&ppp_1, IP_ADDRESS(0, 0, 0, 0), IP_ADDRESS(0, 0, 0, 0));
147 
148     /* Check for PPP IP address assign error.   */
149     if (status)
150         error_counter++;
151 
152     /* Create another IP instance.  */
153     status += nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(0, 0, 0, 0), 0xFFFFF000UL, &pool_1, nx_ppp_driver,
154                            pointer, 2048, 1);
155     pointer =  pointer + 2048;
156 
157     /* Check for IP create error.   */
158     if (status)
159         error_counter++;
160 
161     /* Register the link up/down callbacks.  */
162     status =  nx_ppp_link_up_notify(&ppp_1, link_up_callback);
163     status += nx_ppp_link_down_notify(&ppp_1, link_down_callback);
164 
165     /* Check for PPP link up/down callback registration error(s).   */
166     if (status)
167         error_counter++;
168 
169     /* Enable UDP traffic.  */
170     nx_udp_enable(&ip_0);
171     nx_udp_enable(&ip_1);
172 
173     /* Enable ICMP traffic.  */
174     nx_icmp_enable(&ip_0);
175     nx_icmp_enable(&ip_1);
176 
177 }
178 
179 
180 /* Define the test threads.  */
181 
thread_0_entry(ULONG thread_input)182 static void    thread_0_entry(ULONG thread_input)
183 {
184 
185 UINT        status;
186 ULONG       ip_status;
187 
188     /* Print out test information banner.  */
189     printf("NetX Test:   PPP IPCP Timeout/Restart Test.............................");
190 
191     if (error_counter)
192     {
193 
194         printf("ERROR!\n");
195         test_control_return(1);
196     }
197 
198     do
199     {
200 
201         if (suspend_thread)
202         {
203 
204             if (ppp_1.nx_ppp_lcp_state >= 2)
205             {
206 
207                 suspend_thread = NX_FALSE;
208 
209                 /* PPP_1 is in the LCP completed state. Suspend PPP_0 thread so PPP_1 will not be able
210                    to complete the IPCP protocol. */
211                 tx_thread_suspend(&(ppp_0.nx_ppp_thread));
212 
213                 ppp_1.nx_ppp_timeout =  NX_PPP_PROTOCOL_TIMEOUT;
214                 ppp_1.nx_ppp_lcp_state =  NX_PPP_LCP_COMPLETED_STATE;
215                 ppp_1.nx_ppp_ipcp_state =  NX_PPP_IPCP_START_STATE;
216 
217             }
218 
219         }
220 
221         /* Determine if the two or more restarts have occurred */
222         if (ppp_1_link_down_counter >= 2)
223         {
224             break;
225         }
226 
227         /* Wait for the link to come up (this should not happen if we are
228            testing the link down callback.  */
229         status =  nx_ip_status_check(&ip_0, NX_IP_LINK_ENABLED, &ip_status, NX_IP_PERIODIC_RATE/2);
230 
231     } while (status != NX_SUCCESS) ;
232 
233     /* Determine if the test completed successfully. */
234     if ((error_counter == 0)  && (ppp_0_link_down_counter == 0) && (ppp_1_link_down_counter >= 2))
235     {
236         printf("SUCCESS!\n");
237         test_control_return(0);
238     }
239     else
240     {
241         printf("ERROR!\n");
242         test_control_return(1);
243     }
244 
245 }
246 
247 
thread_1_entry(ULONG thread_input)248 static void    thread_1_entry(ULONG thread_input)
249 {
250 
251 
252 UINT        status;
253 ULONG       ip_status;
254 
255     tx_thread_sleep(20);
256     do
257     {
258 
259         /* If this is the second restart, the test is complete. */
260         if (ppp_1_link_down_counter > 1)
261         {
262 
263             return;
264         }
265 
266         /* Wait for the link to come up.  */
267         status =  nx_ip_status_check(&ip_1, NX_IP_LINK_ENABLED, &ip_status, NX_IP_PERIODIC_RATE/2);
268 
269     } while (status != NX_SUCCESS);
270 
271 }
272 
273 /* Define serial output routines.  Normally these routines would
274    map to physical UART routines and the nx_ppp_byte_receive call
275    would be made from a UART receive interrupt.  */
276 
ppp_0_serial_byte_output(UCHAR byte)277 static void    ppp_0_serial_byte_output(UCHAR byte)
278 {
279 
280     /* Just feed the PPP 1 input routine.  */
281     nx_ppp_byte_receive(&ppp_1, byte);
282 }
283 
ppp_1_serial_byte_output(UCHAR byte)284 static void    ppp_1_serial_byte_output(UCHAR byte)
285 {
286 
287     /* Just feed the PPP 0 input routine.  */
288     nx_ppp_byte_receive(&ppp_0, byte);
289 }
290 
291 
invalid_packet_handler(NX_PACKET * packet_ptr)292 static void invalid_packet_handler(NX_PACKET *packet_ptr)
293 {
294 
295     error_counter++;
296     nx_packet_release(packet_ptr);
297 }
298 
299 
link_up_callback(NX_PPP * ppp_ptr)300 static void link_up_callback(NX_PPP *ppp_ptr)
301 {
302 
303     /* Just increment the link up counter.  */
304     if (ppp_ptr == &ppp_0)
305         ppp_0_link_up_counter++;
306     else
307         ppp_1_link_up_counter++;
308 }
309 
310 
link_down_callback(NX_PPP * ppp_ptr)311 static void link_down_callback(NX_PPP *ppp_ptr)
312 {
313 
314     /* Just increment the link down counter.  */
315     if (ppp_ptr == &ppp_0)
316         ppp_0_link_down_counter++;
317     else
318         ppp_1_link_down_counter++;
319 
320     if (ppp_ptr -> nx_ppp_ipcp_state != NX_PPP_IPCP_FAILED_STATE)
321     {
322         /* Error test should only restart from the IPCP FAILED state */
323         error_counter++;
324         return;
325     }
326 
327     /* If this is the second restart, the test is complete. */
328     if (ppp_1_link_down_counter > 1)
329     {
330         /* Success. Restart test is complete */
331         return;
332     }
333 
334     /* Restart PPP 1.  */
335     nx_ppp_restart(ppp_ptr);
336 
337     if (ppp_1_link_down_counter == 1)
338     {
339         /* First restart. Wait for second restart to verify first restart succeeds */
340         suspend_thread = NX_TRUE;
341     }
342 
343     return;
344 
345 }
346 #else
347 
348 #ifdef CTEST
test_application_define(void * first_unused_memory)349 VOID test_application_define(void *first_unused_memory)
350 #else
351 void    netx_ppp_IPCP_timeout_test_application_define(void *first_unused_memory)
352 #endif
353 {
354 
355     /* Print out test information banner.  */
356     printf("NetX Test:   PPP IPCP Timeout/Restart Test.............................N/A\n");
357 
358     test_control_return(3);
359 }
360 #endif
361 
362 
363