1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  TCP protocol commands			File: ui_tcpcmds.c
5    *
6    *  This file contains commands that make use of the TCP protocol
7    *  in CFE, assuming it's configured.
8    *
9    *  Author:  Mitch Lichtenberg
10    *
11    *********************************************************************
12    *
13    *  Copyright 2000,2001,2002,2003
14    *  Broadcom Corporation. All rights reserved.
15    *
16    *  This software is furnished under license and may be used and
17    *  copied only in accordance with the following terms and
18    *  conditions.  Subject to these conditions, you may download,
19    *  copy, install, use, modify and distribute modified or unmodified
20    *  copies of this software in source and/or binary form.  No title
21    *  or ownership is transferred hereby.
22    *
23    *  1) Any source code used, modified or distributed must reproduce
24    *     and retain this copyright notice and list of conditions
25    *     as they appear in the source file.
26    *
27    *  2) No right is granted to use any trade name, trademark, or
28    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
29    *     name may not be used to endorse or promote products derived
30    *     from this software without the prior written permission of
31    *     Broadcom Corporation.
32    *
33    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
34    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
35    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
37    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
38    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
39    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
41    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
43    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
44    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
45    *     THE POSSIBILITY OF SUCH DAMAGE.
46    ********************************************************************* */
47
48#include "cfe.h"
49#include "ui_command.h"
50
51#if CFG_TCP
52#include "net_ebuf.h"
53#include "net_api.h"
54#endif
55
56
57/*  *********************************************************************
58    *  Configuration
59    ********************************************************************* */
60
61/*  *********************************************************************
62    *  prototypes
63    ********************************************************************* */
64
65#if CFG_TCP
66
67int ui_init_tcpcmds(void);
68
69static int ui_cmd_rlogin(ui_cmdline_t *cmd,int argc,char *argv[]);
70static int ui_cmd_connect(ui_cmdline_t *cmd,int argc,char *argv[]);
71static int ui_cmd_listen(ui_cmdline_t *cmd,int argc,char *argv[]);
72static int ui_cmd_tcpconstest(ui_cmdline_t *cmd,int argc,char *argv[]);
73static int ui_cmd_ttcp(ui_cmdline_t *cmd,int argc,char *argv[]);
74#define isdigit(d) (((d) >= '0') && ((d) <= '9'))
75
76
77/*  *********************************************************************
78    *  ui_init_tcpcmds()
79    *
80    *  Add TCP-specific commands to the command table
81    *
82    *  Input parameters:
83    *  	   nothing
84    *
85    *  Return value:
86    *  	   0
87    ********************************************************************* */
88
89
90int ui_init_tcpcmds(void)
91{
92
93    cmd_addcmd("rlogin",
94	       ui_cmd_rlogin,
95	       NULL,
96	       "mini rlogin client.",
97	       "rlogin hostname [username]\n\n"
98	       "Connects to a remote system using the RLOGIN protocol.  The remote"
99	       "system must have appropriate permissions in place (usually via the"
100	       "file '.rhosts') for CFE to connect.  To terminate the session, type"
101	       "a tilde (~) character followed by a period (.)",
102	       "");
103
104    cmd_addcmd("tcp connect",
105	       ui_cmd_connect,
106	       NULL,
107	       "TCP connection test.",
108	       "tcp connect hostname [portnum]",
109	       "-q;sink output, don't display on terminal|"
110	       "-d;Send junk data to discard|"
111	       "-nodelay;set nodelay option on socket|"
112	       "-srcport=*;Specify the source port");
113
114    cmd_addcmd("tcp listen",
115	       ui_cmd_listen,
116	       NULL,
117	       "port listener.",
118	       "tcp listen portnum",
119	       "-q;sink output, don't display on terminal|"
120	       "-d;Send junk data to discard|"
121	       "-nodelay;set nodelay option on socket");
122
123
124    cmd_addcmd("tcp constest",
125	       ui_cmd_tcpconstest,
126	       NULL,
127	       "tcp console test.",
128	       "tcp constest device",
129	       "");
130
131    cmd_addcmd("ttcp",
132	       ui_cmd_ttcp,
133	       NULL,
134	       "TCP test command.",
135	       "ttcp -t [-options] host\n"
136	       "ttcp -r [-options]\n\n",
137	       "-t;Source a pattern to the network|"
138	       "-r;Sink (discard) data from the network|"
139	       "-D;Don't buffer TCP writes (TCP_NODELAY)|"
140	       "-n=*;Number of buffers to send (-t only) (default 2048)|"
141	       "-l=*;Size of buffer to send/receive (default 2048)|"
142	       "-p=*;Port number to use (default 5001)");
143
144    return 0;
145}
146
147
148
149
150
151static unsigned long rand(void)
152{
153    static unsigned long seed = 1;
154    long x, hi, lo, t;
155
156    x = seed;
157    hi = x / 127773;
158    lo = x % 127773;
159    t = 16807 * lo - 2836 * hi;
160    if (t <= 0) t += 0x7fffffff;
161    seed = t;
162    return t;
163}
164
165
166static int ui_cmd_rlogin(ui_cmdline_t *cmd,int argc,char *argv[])
167{
168    int s;
169    uint8_t hostaddr[IP_ADDR_LEN];
170    char *host;
171    int res;
172    int connflag;
173    int rxdata;
174    int sport;
175    uint8_t data[100];
176    int tilde;
177    char *username;
178    uint8_t *p;
179
180    /*
181     * Process args
182     */
183
184    host = cmd_getarg(cmd,0);
185    if (!host) return ui_showusage(cmd);
186
187    username = cmd_getarg(cmd,1);
188    if (!username) username = "";
189
190    /*
191     * Look up remote host
192     */
193
194    if (isdigit(*host)) {
195	if (parseipaddr(host,hostaddr) < 0) {
196	    xprintf("Invalid IP address: %s\n",host);
197	    return -1;
198	    }
199	}
200    else {
201	res = dns_lookup(host,hostaddr);
202	if (res < 0) {
203	    return ui_showerror(res,"Could not resolve IP address of host %s",host);
204	    }
205	}
206
207    /*
208     * Create TCP socket and bind to a port number less than 1023
209     * See RFC1282 for more info about this
210     */
211
212    s = tcp_socket();
213
214    if (s < 0) {
215	return ui_showerror(s,"Could not create TCP socket");
216	}
217
218    res = 0;
219    tilde = 0;
220    for (sport = 1023; sport > 513; sport--) {
221	res = tcp_bind(s,sport);
222	if (res == 0) break;
223	}
224
225    if (sport == 513) {
226	ui_showerror(res,"No ports available for RLOGIN");
227	return res;
228	}
229
230    /*
231     * Establish a connection.  Our sockets default to nonblocking
232     * so we want to switch to blocking temporarily to
233     * let the tcp_connect routine do this by itself.
234     */
235
236    tcp_setflags(s,0);
237    res = tcp_connect(s,hostaddr,513);
238    if (res < 0) {
239	ui_showerror(res,"Could not connect to host %I",hostaddr);
240	tcp_close(s);
241	return res;
242	}
243
244
245    /*
246     * Construct the initial RLOGIN sequence to include
247     * our user name and terminal type
248     */
249
250    p = data;
251    *p++ = '\0';
252    p += sprintf((char *)p,"%s",username) + 1;
253    p += sprintf((char *)p,"%s",username) + 1;
254    p += sprintf((char *)p,"vt100/38400") + 1;
255
256    tcp_send(s,PTR2HSADDR(data),p-&data[0]);
257
258    res = tcp_recv(s,PTR2HSADDR(data),1);			/* receive result code */
259    if (res <= 0) {
260	goto remdisc;
261	}
262
263    /*
264     * Switch back to nonblocking I/O for the loop
265     */
266
267    tcp_setflags(s,TCPFLG_NBIO);
268
269    /*
270     * Begin processing loop
271     */
272
273    connflag = TRUE;
274    for (;;) {
275
276	/*
277	 * Test connection status
278	 */
279
280	tcp_status(s,&connflag,&rxdata,NULL);
281	if (connflag != TCPSTATUS_CONNECTED) {
282	    goto remdisc;
283	    }
284
285	/*
286	 * Process received data
287	 */
288
289	if (rxdata != 0) {
290	    res = tcp_recv(s,PTR2HSADDR(data),sizeof(data));
291	    if (res > 0) {
292		console_write(data,res);
293		}
294	    if (res < 0) {
295		ui_showerror(res,"TCP read error");
296		break;
297		}
298	    }
299
300	/*
301	 * Process transmitted data
302	 */
303
304	if (console_status()) {
305	    console_read(data,1);
306	    if (tilde == 1) {
307		if (data[0] == '.') break;
308		tilde = 0;
309		tcp_send(s,PTR2HSADDR(data),1);
310		}
311	    else {
312		if (data[0] == '~') tilde = 1;
313		else tcp_send(s,PTR2HSADDR(data),1);
314		}
315	    }
316
317	/*
318	 * Give the background a chance
319	 */
320
321	POLL();
322	}
323
324    printf("Disconnecting...");
325    tcp_close(s);
326    printf("done.\n");
327    return 0;
328
329remdisc:
330    printf("Remote host is no longer connected.\n");
331    tcp_close(s);
332    return 0;
333}
334
335
336
337static int ui_cmd_connect(ui_cmdline_t *cmd,int argc,char *argv[])
338{
339    int s;
340    uint8_t hostaddr[IP_ADDR_LEN];
341    char *host;
342    char *port;
343    int res;
344    int connflag;
345    int rxdata;
346    uint8_t data[100];
347    int quiet;
348    int discard;
349    int total = 0;
350    int total2 = 0;
351    char b = 0;
352    cfe_timer_t t;
353    char *bigbuf;
354    int nodelay;
355    char *sport = NULL;
356
357    bigbuf = KMALLOC(4096,0);
358    for (res = 0; res < 4096; res++) bigbuf[res] = 'A'+(res%26);
359
360    quiet = cmd_sw_isset(cmd,"-q");
361    discard = cmd_sw_isset(cmd,"-d");
362    nodelay = cmd_sw_isset(cmd,"-nodelay");
363
364    host = cmd_getarg(cmd,0);
365    if (!host) return -1;
366
367    port = cmd_getarg(cmd,1);
368    if (!port) port = "23";
369
370    if (strcmp(port,"discard") == 0) port = "9";
371    else if (strcmp(port,"chargen") == 0) port = "19";
372    else if (strcmp(port,"echo") == 0) port = "7";
373
374    if (isdigit(*host)) {
375	if (parseipaddr(host,hostaddr) < 0) {
376	    xprintf("Invalid IP address: %s\n",host);
377	    return -1;
378	    }
379	}
380    else {
381	res = dns_lookup(host,hostaddr);
382	if (res < 0) {
383	    return ui_showerror(res,"Could not resolve IP address of host %s",host);
384	    }
385	}
386
387
388    s = tcp_socket();
389
390    if (s < 0) {
391	return ui_showerror(s,"Could not create TCP socket");
392	}
393
394    if (cmd_sw_value(cmd,"-srcport",&sport)) {
395	res = tcp_bind(s,atoi(sport));
396	if (res < 0) {
397	    ui_showerror(res,"Could not bind to port %s",sport);
398	    tcp_close(s);
399	    return res;
400	    }
401	}
402
403    res = tcp_connect(s,hostaddr,atoi(port));
404    if (res < 0) {
405	ui_showerror(res,"Could not connect to host %I",hostaddr);
406	tcp_close(s);
407	return res;
408	}
409
410    TIMER_SET(t,CFE_HZ*30);
411    connflag = 0;
412    while (!TIMER_EXPIRED(t)) {
413	POLL();
414	tcp_status(s,&connflag,NULL,NULL);
415	if (connflag == TCPSTATUS_CONNECTING) continue;
416	break;
417	}
418
419    if (connflag != TCPSTATUS_CONNECTED) {
420	printf("Could not connect to remote host\n");
421	tcp_close(s);
422	return -1;
423	}
424    else {
425	printf("Connected to remote host.\n");
426	}
427
428
429    if (nodelay) tcp_setflags(s,TCPFLG_NODELAY);
430
431    connflag = TRUE;
432    for (;;) {
433	tcp_status(s,&connflag,&rxdata,NULL);
434	if (connflag != TCPSTATUS_CONNECTED) {
435	    printf("Remote host is no longer connected.\n");
436	    break;
437	    }
438	if (rxdata != 0) {
439	    res = tcp_recv(s,PTR2HSADDR(data),sizeof(data));
440	    if (res > 0) {
441		if (quiet) {
442		    total += res;
443		    if (total > 1000000) {
444			total -= 1000000;
445			printf(".");
446			}
447		    }
448		else {
449		    console_write(data,res);
450		    }
451		}
452	    if (res < 0) {
453		ui_showerror(res,"TCP read error");
454		}
455	    }
456	if (console_status()) {
457	    console_read(data,1);
458	    if (data[0] == 1) break;
459	    else if (data[0] == 3) break;
460	    else if (data[0] == 4) {
461		for (res = 0; res < 100; res++) data[res] = 'A'+(res%26);
462		tcp_send(s,PTR2HSADDR(data),100);
463		}
464	    else if (data[0] == 5) tcp_send(s,PTR2HSADDR(bigbuf),2048);
465	    else if (data[0] == 2) tcp_debug(s,0);
466	    else tcp_send(s,PTR2HSADDR(data),1);
467	    }
468	if (discard) {
469	    res = rand() % sizeof(data);
470	    memset(data,b,res);
471	    b++;
472	    res = tcp_send(s,PTR2HSADDR(data),res);
473	    if (res > 0) {
474		total2 += res;
475		if (total2 > 1000000) {
476		    total2 -= 1000000;
477		    printf("+");
478		    }
479		}
480
481	    }
482
483	POLL();
484	}
485
486    printf("Disconnecting...");
487    tcp_close(s);
488    printf("done.\n");
489
490    KFREE(bigbuf);
491
492    return 0;
493}
494
495
496static int ui_cmd_listen(ui_cmdline_t *cmd,int argc,char *argv[])
497{
498    int s;
499    char *port;
500    int res;
501    int connflag;
502    int rxdata;
503    uint8_t data[100];
504    int quiet;
505    int discard;
506    int total = 0;
507    int total2 = 0;
508    char b = 0;
509    char *bigbuf;
510    uint16_t p;
511    uint16_t remport;
512    uint8_t remaddr[IP_ADDR_LEN];
513    int nodelay;
514
515    bigbuf = KMALLOC(4096,0);
516    for (res = 0; res < 4096; res++) bigbuf[res] = 'A'+(res%26);
517
518    quiet = cmd_sw_isset(cmd,"-q");
519    discard = cmd_sw_isset(cmd,"-d");
520    nodelay = cmd_sw_isset(cmd,"-nodelay");
521
522    port = cmd_getarg(cmd,0);
523    if (!port) port = "1234";
524    p = atoi(port);
525
526    s = tcp_socket();
527
528    if (s < 0) {
529	return ui_showerror(s,"Could not create TCP socket");
530	}
531
532    res = tcp_listen(s,p);
533    if (res < 0) {
534	ui_showerror(res,"Could not set socket to listen");
535	tcp_close(s);
536	return res;
537	}
538
539    printf("Listening...");
540    connflag = FALSE;
541    for (;;) {
542	if (console_status()) break;
543	tcp_status(s,&connflag,NULL,NULL);
544	if (connflag == TCPSTATUS_CONNECTED) break;
545	POLL();
546	}
547
548    if (connflag != TCPSTATUS_CONNECTED) {
549	printf("No connection received from remote host\n");
550	tcp_close(s);
551	return -1;
552	}
553
554    tcp_peeraddr(s,remaddr,&remport);
555    printf("Connection from port %u on %I\n",remport,remaddr);
556
557    if (nodelay) tcp_setflags(s,TCPFLG_NODELAY);
558
559    connflag = TRUE;
560    for (;;) {
561	tcp_status(s,&connflag,&rxdata,NULL);
562	if (connflag != TCPSTATUS_CONNECTED) {
563	    printf("Remote host is no longer connected.\n");
564	    break;
565	    }
566	if (rxdata != 0) {
567	    res = tcp_recv(s,PTR2HSADDR(data),sizeof(data));
568	    if (res > 0) {
569		if (quiet) {
570		    total += res;
571		    if (total > 1000000) {
572			total -= 1000000;
573			printf(".");
574			}
575		    }
576		else {
577		    console_write(data,res);
578		    }
579		}
580	    if (res < 0) {
581		ui_showerror(res,"TCP read error");
582		}
583	    }
584	if (console_status()) {
585	    console_read(data,1);
586	    if (data[0] == 1) break;
587	    if (data[0] == 3) break;
588	    if (data[0] == 4) {
589		for (res = 0; res < 100; res++) data[res] = 'A'+(res%26);
590		tcp_send(s,PTR2HSADDR(data),100);
591		}
592	    if (data[0] == 5) tcp_send(s,PTR2HSADDR(bigbuf),2048);
593	    if (data[0] == 2) tcp_debug(s,0);
594	    else tcp_send(s,PTR2HSADDR(data),1);
595	    }
596	if (discard) {
597	    res = rand() % sizeof(data);
598	    memset(data,b,res);
599	    b++;
600	    res = tcp_send(s,PTR2HSADDR(data),res);
601	    if (res > 0) {
602		total2 += res;
603		if (total2 > 1000000) {
604		    total2 -= 1000000;
605		    printf("+");
606		    }
607		}
608
609	    }
610
611	POLL();
612	}
613
614
615    printf("Disconnecting...");
616    tcp_close(s);
617    printf("done.\n");
618
619    KFREE(bigbuf);
620
621    return 0;
622}
623
624
625static int ui_cmd_tcpconstest(ui_cmdline_t *cmd,int argc,char *argv[])
626{
627    char *x;
628    int fh;
629    int res;
630    uint8_t data[100];
631
632    x = cmd_getarg(cmd,0);
633    if (!x) return ui_showusage(cmd);
634
635    fh = cfe_open(x);
636    if (fh < 0) return ui_showerror(fh,"Could not open device %s",x);
637
638    for (;;) {
639	if (console_status()) break;
640	res = cfe_read(fh,PTR2HSADDR(data),sizeof(data));
641	if (res < 0) {
642	    ui_showerror(res,"could not read data");
643	    break;
644	    }
645	console_write(data,res);
646	}
647
648    cfe_close(fh);
649
650    return 0;
651}
652
653static int ui_cmd_ttcp(ui_cmdline_t *cmd,int argc,char *argv[])
654{
655    int s;
656    uint8_t hostaddr[IP_ADDR_LEN];
657    char *host;
658    int res;
659    int totalbytes = 0;
660    int totalbufs = 0;
661    cfe_timer_t start_time;
662    cfe_timer_t stop_time;
663    cfe_timer_t t;
664    int connflag;
665    char *bigbuf;
666    int nodelay;
667    int numbuf;
668    int buflen;
669    int txmode,rxmode;
670    uint16_t port;
671
672    char *x;
673
674    if (cmd_sw_value(cmd,"-n",&x)) numbuf = atoi(x);
675    else numbuf = 2048;
676
677    if (cmd_sw_value(cmd,"-l",&x)) buflen = atoi(x);
678    else buflen = 2048;
679
680    if (cmd_sw_value(cmd,"-p",&x)) port = atoi(x);
681    else port = 5001;
682
683    if ((numbuf == 0) || (buflen == 0)) return ui_showusage(cmd);
684
685
686    bigbuf = KMALLOC(buflen,0);
687    for (res = 0; res < buflen; res++) bigbuf[res] = 'A'+(res%26);
688
689    txmode = cmd_sw_isset(cmd,"-t");
690    rxmode = cmd_sw_isset(cmd,"-r");
691
692    if (!(txmode ^ rxmode)) {
693	return ui_showerror(-1,"You must specify one of -t or -r");
694	}
695
696    nodelay = cmd_sw_isset(cmd,"-D");
697
698    if (txmode) {
699	host = cmd_getarg(cmd,0);
700	if (!host) return ui_showusage(cmd);
701
702	if (isdigit(*host)) {
703	    if (parseipaddr(host,hostaddr) < 0) {
704		return ui_showerror(-1,"Invalid IP address: %s\n",host);
705		}
706	    }
707	else {
708	    res = dns_lookup(host,hostaddr);
709	    if (res < 0) {
710		return ui_showerror(res,"Could not resolve IP address of host %s",host);
711		}
712	    }
713	}
714
715
716    s = tcp_socket();
717
718    if (s < 0) {
719	return ui_showerror(s,"Could not create TCP socket");
720	}
721
722
723    if (txmode) {
724	res = tcp_connect(s,hostaddr,port);
725	if (res < 0) {
726	    ui_showerror(res,"Could not connect to host %I",hostaddr);
727	    tcp_close(s);
728	    return res;
729	    }
730
731	TIMER_SET(t,CFE_HZ*30);
732	connflag = 0;
733	while (!TIMER_EXPIRED(t)) {
734	    POLL();
735	    tcp_status(s,&connflag,NULL,NULL);
736	    if (connflag == TCPSTATUS_CONNECTING) continue;
737	    break;
738	    }
739
740	if (connflag != TCPSTATUS_CONNECTED) {
741	    printf("Could not connect to remote host\n");
742	    tcp_close(s);
743	    return -1;
744	    }
745	else {
746	    printf("Connected to remote host.\n");
747	    }
748	}
749
750    if (rxmode) {
751	printf("Waiting for connection on port %d: ",port);
752	tcp_listen(s,port);
753	for (;;) {
754	    if (console_status()) break;
755	    tcp_status(s,&connflag,NULL,NULL);
756	    if (connflag == TCPSTATUS_CONNECTED) break;
757	    POLL();
758	    }
759	if (connflag != TCPSTATUS_CONNECTED) {
760	    printf("No connection received from remote host\n");
761	    tcp_close(s);
762	    return -1;
763	    }
764	printf("done.\n");
765	}
766
767
768    if (nodelay) tcp_setflags(s,TCPFLG_NODELAY);	/* also sets blocking */
769    else tcp_setflags(s,0);
770
771    start_time = cfe_ticks;
772
773    if (rxmode) {
774	while (1) {
775	    POLL();
776	    res = tcp_recv(s,PTR2HSADDR(bigbuf),buflen);
777	    if (res != buflen) break;
778	    totalbytes += res;
779	    totalbufs++;
780	    }
781	}
782    else {
783	while (numbuf > 0) {
784	    POLL();
785	    res = tcp_send(s,PTR2HSADDR(bigbuf),buflen);
786	    if (res != buflen) break;
787	    numbuf--;
788	    totalbytes += res;
789	    totalbufs++;
790	    }
791	}
792
793    stop_time = cfe_ticks;
794
795    tcp_close(s);
796
797    if ((res < 0) && !rxmode) {
798	ui_showerror(res,"Network I/O error");
799	}
800    else {
801	printf("%d bytes transferred via %d calls in %lld ticks\n",
802	       totalbytes,totalbufs,stop_time-start_time);
803	}
804
805
806    KFREE(bigbuf);
807
808    return 0;
809
810}
811
812#endif	 /* CFG_TCP */
813