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