1 /* This is a small demo of TELNET on the high-performance NetX TCP/IP stack.
2    This demo relies on ThreadX and NetX to show a simple TELNET connection,
3    send, server echo, and then disconnection from the TELNET server.  */
4 
5 #include  "tx_api.h"
6 #include  "nx_api.h"
7 #include  "nxd_telnet_client.h"
8 #include  "nxd_telnet_server.h"
9 
10 #define     DEMO_STACK_SIZE         4096
11 
12 
13 /* Define the ThreadX and NetX object control blocks...  */
14 
15 TX_THREAD               server_thread;
16 TX_THREAD               client_thread;
17 NX_PACKET_POOL          pool_server;
18 NX_PACKET_POOL          pool_client;
19 NX_IP                   ip_server;
20 NX_IP                   ip_client;
21 
22 
23 /* If the Telnet connection requires IPv6 support, define USE_IPV6.  Note that
24    the NetX Duo Telnet Client and Server can communicate over IPv4 regardless
25    if IPv6 is enabled in NetX Duo. However to use IPv6 addressing, the
26    FEATURE_NX_IPV6 must be defined in nx_user.h.  */
27 #ifdef NX_DISABLE_IPV4
28 #define USE_IPV6
29 #endif /* NX_DISABLE_IPV4 */
30 
31 #ifdef USE_IPV6
32 NXD_ADDRESS     server_ip_address;
33 #endif
34 
35 /* Define TELNET objects.  */
36 
37 NX_TELNET_SERVER        my_server;
38 NX_TELNET_CLIENT        my_client;
39 
40 
41 #define         SERVER_ADDRESS          IP_ADDRESS(1,2,3,4)
42 #define         CLIENT_ADDRESS          IP_ADDRESS(1,2,3,5)
43 
44 
45 /* Define the counters used in the demo application...  */
46 
47 ULONG                   error_counter;
48 
49 
50 /* Define timeout in ticks for connecting and sending/receiving data. */
51 
52 #define                 TELNET_TIMEOUT  (2 * NX_IP_PERIODIC_RATE)
53 
54 /* Define function prototypes.  */
55 
56 void    thread_server_entry(ULONG thread_input);
57 void    thread_client_entry(ULONG thread_input);
58 
59 /* Replace the 'ram' driver with your actual Ethernet driver. */
60 void    _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req);
61 
62 
63 /* Define the application's TELNET Server callback routines.  */
64 
65 void    telnet_new_connection(NX_TELNET_SERVER *server_ptr, UINT logical_connection);
66 void    telnet_receive_data(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr);
67 void    telnet_connection_end(NX_TELNET_SERVER *server_ptr, UINT logical_connection);
68 
69 
70 /* Define main entry point.  */
71 
main()72 int main()
73 {
74 
75     /* Enter the ThreadX kernel.  */
76     tx_kernel_enter();
77 }
78 
79 
80 /* Define what the initial system looks like.  */
tx_application_define(void * first_unused_memory)81 void    tx_application_define(void *first_unused_memory)
82 {
83 
84 UINT    status;
85 CHAR    *pointer;
86 
87 
88     /* Setup the working pointer.  */
89     pointer =  (CHAR *) first_unused_memory;
90 
91     /* Create the server thread.  */
92     tx_thread_create(&server_thread, "server thread", thread_server_entry, 0,
93             pointer, DEMO_STACK_SIZE,
94             4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
95 
96     pointer =  pointer + DEMO_STACK_SIZE;
97 
98     /* Create the client thread.  */
99     tx_thread_create(&client_thread, "client thread", thread_client_entry, 0,
100             pointer, DEMO_STACK_SIZE,
101             6, 6, TX_NO_TIME_SLICE, TX_AUTO_START);
102 
103     pointer =  pointer + DEMO_STACK_SIZE;
104 
105     /* Initialize the NetX system.  */
106     nx_system_initialize();
107 
108     /* Create packet pool.  */
109     nx_packet_pool_create(&pool_server, "Server NetX Packet Pool", 600, pointer, 8192);
110     pointer = pointer + 8192;
111 
112     /* Create an IP instance.  */
113     nx_ip_create(&ip_server, "Server NetX IP Instance", SERVER_ADDRESS,
114                         0xFFFFFF00UL, &pool_server, _nx_ram_network_driver,
115                         pointer, 4096, 1);
116 
117     pointer =  pointer + 4096;
118 
119     /* Create another packet pool. */
120     nx_packet_pool_create(&pool_client, "Client NetX Packet Pool", 600, pointer, 8192);
121     pointer = pointer + 8192;
122 
123     /* Create another IP instance.  */
124     nx_ip_create(&ip_client, "Client NetX IP Instance", CLIENT_ADDRESS,
125                         0xFFFFFF00UL, &pool_client, _nx_ram_network_driver,
126                         pointer, 4096, 1);
127 
128     pointer = pointer + 4096;
129 
130 #ifndef NX_DISABLE_IPV4
131     /* Enable ARP and supply ARP cache memory for IP Instance 0.  */
132     nx_arp_enable(&ip_server, (void *) pointer, 1024);
133     pointer = pointer + 1024;
134 
135     /* Enable ARP and supply ARP cache memory for IP Instance 1.  */
136     nx_arp_enable(&ip_client, (void *) pointer, 1024);
137     pointer = pointer + 1024;
138 #endif /* NX_DISABLE_IPV4  */
139 
140     /* Enable TCP processing for both IP instances.  */
141     nx_tcp_enable(&ip_server);
142     nx_tcp_enable(&ip_client);
143 
144 #ifdef USE_IPV6
145     /* Next set the NetX Duo Telnet Server address. */
146     server_ip_address.nxd_ip_address.v6[3] = 0x106;
147     server_ip_address.nxd_ip_address.v6[2] = 0x0;
148     server_ip_address.nxd_ip_address.v6[1] = 0x0000f101;
149     server_ip_address.nxd_ip_address.v6[0] = 0x20010db8;
150     server_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
151 #endif
152 
153     /* Create the NetX TELNET Server.  */
154     status =  nx_telnet_server_create(&my_server, "Telnet Server", &ip_server,
155                     pointer, 2048, telnet_new_connection, telnet_receive_data,
156                     telnet_connection_end);
157 
158     /* Check for errors.  */
159     if (status)
160         error_counter++;
161 
162     return;
163 }
164 
165 /* Define the Server thread.  */
thread_server_entry(ULONG thread_input)166 void    thread_server_entry(ULONG thread_input)
167 {
168 
169 UINT    status;
170 #ifdef USE_IPV6
171 UINT   iface_index, address_index;
172 #endif
173 
174     NX_PARAMETER_NOT_USED(thread_input);
175 
176     /* Allow IP thread task to initialize the system. */
177     tx_thread_sleep(NX_IP_PERIODIC_RATE);
178 
179 #ifdef USE_IPV6
180     /* Here's where we make the Telnet Server IPv6 enabled. */
181     status = nxd_ipv6_enable(&ip_server);
182 
183     /* Check for ipv6 enable error.  */
184     if (status)
185     {
186 
187         error_counter++;
188         return;
189      }
190 
191     status = nxd_icmp_enable(&ip_server);
192 
193     /* Check for icmp6 enable error.  */
194     if (status)
195     {
196 
197         error_counter++;
198         return;
199      }
200 
201 
202 
203      /* Set the link local address with the host MAC address. */
204     /* This assumes we are using the primary network interface (index 0). */
205     iface_index = 0;
206 
207     status = nxd_ipv6_address_set(&ip_server, iface_index, NX_NULL, 10, &address_index);
208 
209     /* Check for link local address set error.  */
210     if (status)
211     {
212 
213         error_counter++;
214         return;
215      }
216 
217     /* Set the host global IP address. We are assuming a 64
218        bit prefix here but this can be any value (< 128). */
219     status = nxd_ipv6_address_set(&ip_server, iface_index, &server_ip_address, 64, &address_index);
220 
221     /* Check for global address set error.  */
222     if (status)
223     {
224 
225         error_counter++;
226         return;
227      }
228 
229     /* Wait while NetX Duo validates the link local and global address. */
230     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
231 #endif
232 
233 
234     /* Start the TELNET Server.  */
235     status =  nx_telnet_server_start(&my_server);
236 
237     /* Check for errors.  */
238     if (status != NX_SUCCESS)
239     {
240 
241         return;
242     }
243 
244 
245 }
246 
247 /* Define the client thread.  */
thread_client_entry(ULONG thread_input)248 void    thread_client_entry(ULONG thread_input)
249 {
250 
251 NX_PACKET   *my_packet;
252 UINT        status;
253 #ifdef USE_IPV6
254 NXD_ADDRESS     client_ip_address;
255 UINT   iface_index, address_index;
256 #endif
257 
258     NX_PARAMETER_NOT_USED(thread_input);
259 
260     /* Allow IP thread task to initialize the system. */
261     tx_thread_sleep(NX_IP_PERIODIC_RATE);
262 
263 #ifdef USE_IPV6
264 
265     /* Here's where we make the Telnet Client IPv6 enabled. */
266     status= nxd_ipv6_enable(&ip_client);
267 
268 
269     /* Check for ipv6 enable error.  */
270     if (status)
271     {
272 
273         error_counter++;
274         return;
275      }
276 
277     nxd_icmp_enable(&ip_client);
278 
279 
280     /* Check for icmp6 enable error.  */
281     if (status)
282     {
283 
284         error_counter++;
285         return;
286     }
287 
288     client_ip_address.nxd_ip_address.v6[3] = 0x101;
289     client_ip_address.nxd_ip_address.v6[2] = 0x0;
290     client_ip_address.nxd_ip_address.v6[1] = 0x0000f101;
291     client_ip_address.nxd_ip_address.v6[0] = 0x20010db8;
292     client_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
293 
294     /* Set the Client link local and global addresses. */
295 
296      /* Set the link local address with the host MAC address. */
297     iface_index = 0;
298 
299     /* This assumes we are using the primary network interface (index 0). */
300     status = nxd_ipv6_address_set(&ip_client, iface_index, NX_NULL, 10, &address_index);
301 
302     /* Check for link local address set error.  */
303     if (status)
304     {
305 
306         error_counter++;
307         return;
308      }
309 
310      /* Set the host global IP address. We are assuming a 64
311        bit prefix here but this can be any value (< 128). */
312     status = nxd_ipv6_address_set(&ip_client, iface_index, &client_ip_address, 64, &address_index);
313 
314     /* Check for global address set error.  */
315     if (status)
316     {
317 
318         error_counter++;
319         return;
320      }
321 
322     /* Let NetX Duo validate the addresses. */
323     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
324 
325 #endif /* USE_IPV6 */
326 
327     /* Create a TELENT client instance.  */
328     status =  nx_telnet_client_create(&my_client, "My TELNET Client", &ip_client, 600);
329 
330     /* Check status.  */
331     if (status != NX_SUCCESS)
332     {
333         return;
334     }
335 
336     do
337     {
338 #ifdef USE_IPV6
339 
340         /* Connect the TELNET client to the TELNET Server at port 23 over IPv6. Note that this
341            service accept IPv4 addresses in the NXD_ADDRESS server_ip_address input.  */
342         status =  nxd_telnet_client_connect(&my_client, &server_ip_address, NX_TELNET_SERVER_PORT, TELNET_TIMEOUT);
343 
344 #else
345         /* Connect the TELNET client to the TELNET Server at port 23 over IPv4.  */
346         status =  nx_telnet_client_connect(&my_client, SERVER_ADDRESS, NX_TELNET_SERVER_PORT, TELNET_TIMEOUT);
347 #endif
348     } while (status != NX_SUCCESS);
349 
350     /* Check status.  */
351     if (status != NX_SUCCESS)
352     {
353         return;
354     }
355 
356     /* Allocate a packet.  */
357     status =  nx_packet_allocate(&pool_client, &my_packet, NX_TCP_PACKET, NX_WAIT_FOREVER);
358 
359     /* Check status.  */
360     if (status != NX_SUCCESS)
361     {
362         return;
363     }
364 
365     /* Build a simple 1-byte message.  */
366     nx_packet_data_append(my_packet, "a", 1, &pool_client, NX_WAIT_FOREVER);
367 
368     /* Send the packet to the TELNET Server.  */
369     status =  nx_telnet_client_packet_send(&my_client, my_packet, TELNET_TIMEOUT);
370 
371     /* Check status.  */
372     if (status != NX_SUCCESS)
373     {
374         return;
375     }
376 
377     /* Pickup the Server header.  */
378     status =  nx_telnet_client_packet_receive(&my_client, &my_packet, TELNET_TIMEOUT);
379 
380     /* Check status.  */
381     if (status != NX_SUCCESS)
382     {
383         return;
384     }
385 
386     /* At this point the packet should contain the Server's banner
387        message sent by the Server callback function below.  Just
388        release it for this demo.  */
389     nx_packet_release(my_packet);
390 
391     /* Pickup the Server echo of the character.  */
392     status =  nx_telnet_client_packet_receive(&my_client, &my_packet, TELNET_TIMEOUT);
393 
394     /* Check status.  */
395     if (status != NX_SUCCESS)
396     {
397         return;
398     }
399 
400     /* At this point the packet should contain the character 'a' that
401        we sent earlier.  Just release the packet for now.  */
402     nx_packet_release(my_packet);
403 
404     /* Now disconnect form the TELNET Server.  */
405     status =  nx_telnet_client_disconnect(&my_client, TELNET_TIMEOUT);
406 
407 
408     /* Check status.  */
409     if (status != NX_SUCCESS)
410     {
411         return;
412     }
413 
414     /* Delete the TELNET Client.  */
415     status =  nx_telnet_client_delete(&my_client);
416 
417     /* Check status.  */
418     if (status != NX_SUCCESS)
419     {
420         return;
421     }
422 }
423 
424 
425 /* This routine is called by the NetX Telnet Server whenever a new Telnet client
426    connection is established.  */
telnet_new_connection(NX_TELNET_SERVER * server_ptr,UINT logical_connection)427 void  telnet_new_connection(NX_TELNET_SERVER *server_ptr, UINT logical_connection)
428 {
429 
430 UINT        status;
431 NX_PACKET   *packet_ptr;
432 
433 
434 
435     /* Allocate a packet for client greeting. */
436     status =  nx_packet_allocate(&pool_server, &packet_ptr, NX_TCP_PACKET, NX_NO_WAIT);
437 
438     if (status != NX_SUCCESS)
439     {
440         error_counter++;
441         return;
442     }
443 
444     /* Build a banner message and a prompt.  */
445     nx_packet_data_append(packet_ptr, "**** Welcome to NetX TELNET Server ****\r\n\r\n\r\n", 45,
446                           &pool_server, NX_NO_WAIT);
447 
448     nx_packet_data_append(packet_ptr, "NETX> ", 6, &pool_server, NX_NO_WAIT);
449 
450     /* Send the packet to the client.  */
451     status =  nx_telnet_server_packet_send(server_ptr, logical_connection, packet_ptr, TELNET_TIMEOUT);
452 
453     if (status != NX_SUCCESS)
454     {
455         error_counter++;
456         nx_packet_release(packet_ptr);
457     }
458 
459     return;
460 }
461 
462 
463 /* This routine is called by the NetX Telnet Server whenever data is present on a Telnet client
464    connection.  */
telnet_receive_data(NX_TELNET_SERVER * server_ptr,UINT logical_connection,NX_PACKET * packet_ptr)465 void  telnet_receive_data(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr)
466 {
467 
468 UINT    status;
469 UCHAR   alpha;
470 
471 
472     /* This demo just echoes the character back and on <cr,lf> sends a new prompt back to the
473        client.  A real system would most likely buffer the character(s) received in a buffer
474        associated with the supplied logical connection and process according to it.  */
475 
476 
477     /* Just throw away carriage returns.  */
478     if ((packet_ptr -> nx_packet_prepend_ptr[0] == '\r') && (packet_ptr -> nx_packet_length == 1))
479     {
480 
481         nx_packet_release(packet_ptr);
482         return;
483     }
484 
485     /* Setup new line on line feed.  */
486     if ((packet_ptr -> nx_packet_prepend_ptr[0] == '\n') ||
487         ((packet_ptr -> nx_packet_prepend_ptr[0] == '\r') && (packet_ptr -> nx_packet_prepend_ptr[1] == '\n')))
488     {
489 
490         /* Clean up the packet.  */
491         packet_ptr -> nx_packet_length =  0;
492         packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_data_start + NX_TCP_PACKET;
493         packet_ptr -> nx_packet_append_ptr =   packet_ptr -> nx_packet_data_start + NX_TCP_PACKET;
494 
495         /* Build the next prompt.  */
496         nx_packet_data_append(packet_ptr, "\r\nNETX> ", 8, &pool_server, NX_NO_WAIT);
497 
498         /* Send the packet to the client.  */
499         status =  nx_telnet_server_packet_send(server_ptr, logical_connection, packet_ptr, TELNET_TIMEOUT);
500 
501         if (status != NX_SUCCESS)
502         {
503             error_counter++;
504             nx_packet_release(packet_ptr);
505         }
506 
507         return;
508     }
509 
510     /* Pickup first character (usually only one from client).  */
511     alpha =  packet_ptr -> nx_packet_prepend_ptr[0];
512 
513     /* Echo character.  */
514     status =  nx_telnet_server_packet_send(server_ptr, logical_connection, packet_ptr, TELNET_TIMEOUT);
515 
516     if (status != NX_SUCCESS)
517     {
518         error_counter++;
519         nx_packet_release(packet_ptr);
520     }
521 
522     /* Check for a disconnection.  */
523     if (alpha == 'q')
524     {
525 
526         /* Initiate server disconnection.  */
527         nx_telnet_server_disconnect(server_ptr, logical_connection);
528     }
529 }
530 
531 
532 /* This routine is called by the NetX Telnet Server whenever the client disconnects.  */
telnet_connection_end(NX_TELNET_SERVER * server_ptr,UINT logical_connection)533 void  telnet_connection_end(NX_TELNET_SERVER *server_ptr, UINT logical_connection)
534 {
535     NX_PARAMETER_NOT_USED(server_ptr);
536     NX_PARAMETER_NOT_USED(logical_connection);
537 
538     /* Cleanup any application specific connection or buffer information.  */
539     return;
540 }
541 
542