1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  Network commands				File: ui_netcmds.c
5    *
6    *  Network user interface
7    *
8    *  Author:  Mitch Lichtenberg
9    *
10    *********************************************************************
11    *
12    *  Copyright 2000,2001,2002,2003
13    *  Broadcom Corporation. All rights reserved.
14    *
15    *  This software is furnished under license and may be used and
16    *  copied only in accordance with the following terms and
17    *  conditions.  Subject to these conditions, you may download,
18    *  copy, install, use, modify and distribute modified or unmodified
19    *  copies of this software in source and/or binary form.  No title
20    *  or ownership is transferred hereby.
21    *
22    *  1) Any source code used, modified or distributed must reproduce
23    *     and retain this copyright notice and list of conditions
24    *     as they appear in the source file.
25    *
26    *  2) No right is granted to use any trade name, trademark, or
27    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
28    *     name may not be used to endorse or promote products derived
29    *     from this software without the prior written permission of
30    *     Broadcom Corporation.
31    *
32    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
33    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
34    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
35    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
36    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
37    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
38    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
40    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
42    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
43    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
44    *     THE POSSIBILITY OF SUCH DAMAGE.
45    ********************************************************************* */
46
47
48#include "cfe.h"
49
50#include "env_subr.h"
51#include "ui_command.h"
52
53#include "net_enet.h"
54#include "net_ebuf.h"
55#include "net_ether.h"
56
57#include "net_api.h"
58
59#include "cfe_fileops.h"
60
61#define ip_addriszero(a) (((a)[0]|(a)[1]|(a)[2]|(a)[3]) == 0)
62#define isdigit(d) (((d) >= '0') && ((d) <= '9'))
63
64int ui_init_netcmds(void);
65
66#if CFG_NETWORK
67static int ui_cmd_ifconfig(ui_cmdline_t *cmd,int argc,char *argv[]);
68static int ui_cmd_arp(ui_cmdline_t *cmd,int argc,char *argv[]);
69static int ui_cmd_ping(ui_cmdline_t *cmd,int argc,char *argv[]);
70#if CFG_TCP
71extern int ui_init_tcpcmds(void);
72#endif
73#endif
74
75typedef struct netparam_s {
76    const char *str;
77    int num;
78} netparam_t;
79
80#if CFG_NETWORK
81static int ui_ifconfig_lookup(char *name,char *val,const netparam_t *list) ;
82#endif
83
84const static netparam_t loopbacktypes[] = {
85    {"off",ETHER_LOOPBACK_OFF},
86    {"internal",ETHER_LOOPBACK_INT},
87    {"external",ETHER_LOOPBACK_EXT},
88    {0,NULL}};
89
90const static netparam_t speedtypes[] = {
91    {"auto",ETHER_SPEED_AUTO},
92    {"10hdx",ETHER_SPEED_10HDX},
93    {"10fdx",ETHER_SPEED_10FDX},
94    {"100hdx",ETHER_SPEED_100HDX},
95    {"100fdx",ETHER_SPEED_100FDX},
96    {"1000hdx",ETHER_SPEED_1000HDX},
97    {"1000fdx",ETHER_SPEED_1000FDX},
98    {0,NULL}};
99
100
101int ui_init_netcmds(void)
102{
103#if CFG_NETWORK
104    cmd_addcmd("ifconfig",
105	       ui_cmd_ifconfig,
106	       NULL,
107	       "Configure the Ethernet interface",
108	       "ifconfig device [options..]\n\n"
109	       "Activates and configures the specified Ethernet interface and sets its\n"
110               "IP address, netmask, and other parameters.  The -auto switch can be used\n"
111               "to set this information via DHCP.",
112               "-auto;Configure interface automatically via DHCP|"
113               "-off;Deactivate the specified interface|"
114	       "-addr=*;Specifies the IP address of the interface|"
115	       "-mask=*;Specifies the subnet mask for the interface|"
116               "-gw=*;Specifies the gateway address for the interface|"
117               "-dns=*;Specifies the name server address for the interface|"
118               "-domain=*;Specifies the default domain for name service queries|"
119	       "-speed=*;Sets the interface speed (auto,10fdx,10hdx,100fdx,\n"
120	       "100hdx,1000fdx,1000hdx)|"
121	       "-loopback=*;Sets the loopback mode (off,internal,external)  "
122	       "External\nloopback causes the phy to be placed in loopback mode|"
123               "-hwaddr=*;Sets the hardware address (overrides environment)");
124
125    cmd_addcmd("arp",
126	       ui_cmd_arp,
127	       NULL,
128	       "Display or modify the ARP Table",
129	       "arp [-d] [ip-address] [dest-address]\n\n"
130	       "Without any parameters, the arp command will display the contents of the\n"
131               "arp table.  With two parameters, arp can be used to add permanent arp\n"
132               "entries to the table (permanent arp entries do not time out)",
133	       "-d;Delete the specified ARP entry.  If specified, ip-address\n"
134               "may be * to delete all entries.");
135
136    cmd_addcmd("ping",
137	       ui_cmd_ping,
138	       NULL,
139	       "Ping a remote IP host.",
140	       "ping [-t] remote-host\n\n"
141	       "This command sends an ICMP ECHO message to a remote host and waits for \n"
142	       "a reply.  The network interface must be configured and operational for\n"
143	       "this command to work.  If the interface is configured for loopback mode\n"
144	       "the packet will be sent through the network interface, so this command\n"
145	       "can be used for a simple network test.",
146	       "-t;Ping forever, or until the ENTER key is struck|"
147	       "-x;Exit immediately on first error (use with -f or -t)|"
148	       "-f;Flood ping (use carefully!) - ping as fast as possible|"
149	       "-s=*;Specify the number of ICMP data bytes|"
150	       "-c=*;Specify number of packets to echo|"
151	       "-A;don't abort even if key is pressed|"
152	       "-E;Require all packets sent to be returned, for successful return status");
153
154#if CFG_TCP
155    ui_init_tcpcmds();
156#endif
157
158
159#endif
160
161    return 0;
162}
163
164
165#if CFG_NETWORK
166static int ui_ifdown(void)
167{
168    char *devname;
169
170    devname = (char *) net_getparam(NET_DEVNAME);
171    if (devname) {
172	xprintf("Device %s has been deactivated.\n",devname);
173	net_uninit();
174	net_setnetvars();
175	}
176
177    return 0;
178}
179
180static void ui_showifconfig(void)
181{
182    char *devname;
183    uint8_t *addr;
184
185    devname = (char *) net_getparam(NET_DEVNAME);
186    if (devname == NULL) {
187	xprintf("Network interface has not been configured\n");
188	return;
189	}
190
191    xprintf("Device %s: ",devname);
192
193    addr = net_getparam(NET_HWADDR);
194    if (addr) xprintf(" hwaddr %a",addr);
195
196    addr = net_getparam(NET_IPADDR);
197    if (addr) {
198	if (ip_addriszero(addr)) xprintf(", ipaddr not set");
199	else xprintf(", ipaddr %I",addr);
200	}
201
202    addr = net_getparam(NET_NETMASK);
203    if (addr) {
204	if (ip_addriszero(addr)) xprintf(", mask not set");
205	else xprintf(", mask %I",addr);
206	}
207
208    xprintf("\n");
209    xprintf("        ");
210
211    addr = net_getparam(NET_GATEWAY);
212    if (addr) {
213	if (ip_addriszero(addr)) xprintf("gateway not set");
214	else xprintf("gateway %I",addr);
215	}
216
217    addr = net_getparam(NET_NAMESERVER);
218    if (addr) {
219	if (ip_addriszero(addr)) xprintf(", nameserver not set");
220	else xprintf(", nameserver %I",addr);
221	}
222
223    addr = net_getparam(NET_DOMAIN);
224    if (addr) {
225	xprintf(", domain %s",addr);
226	}
227
228    xprintf("\n");
229}
230
231static int ui_ifconfig_auto(ui_cmdline_t *cmd,char *devname)
232{
233    int err;
234    dhcpreply_t *reply = NULL;
235    char *x;
236    uint8_t hwaddr[ENET_ADDR_LEN];
237    int speed = ETHER_SPEED_AUTO;
238
239    net_uninit();
240
241    err = net_init(devname);
242    if (err < 0) {
243	xprintf("Could not activate device %s: %s\n",
244		devname,cfe_errortext(err));
245	return err;
246	}
247
248    if (cmd_sw_value(cmd,"-hwaddr",&x)) {
249	if (enet_parse_hwaddr(x,hwaddr) != 0) {
250	    xprintf("Invalid hardware address: %s\n",x);
251	    net_uninit();
252	    return CFE_ERR_INV_PARAM;
253	    }
254	else {
255	    net_setparam(NET_HWADDR,hwaddr);
256	    }
257	}
258
259    if (cmd_sw_value(cmd,"-speed",&x)) {
260	speed = ui_ifconfig_lookup("-speed",x,speedtypes);
261	if (speed >= 0) {
262	    net_setparam(NET_SPEED,(uint8_t *) &speed);
263	    }
264	else return CFE_ERR_INV_PARAM;
265	}
266
267    err = dhcp_bootrequest(&reply);
268
269    if (err < 0) {
270	xprintf("DHCP registration failed on device %s\n",devname);
271	net_uninit();
272	return CFE_ERR_NETDOWN;
273	}
274
275    net_setparam(NET_IPADDR,reply->dr_ipaddr);
276    net_setparam(NET_NETMASK,reply->dr_netmask);
277    net_setparam(NET_GATEWAY,reply->dr_gateway);
278    net_setparam(NET_NAMESERVER,reply->dr_nameserver);
279    net_setparam(NET_DOMAIN,(uint8_t *)reply->dr_domainname);
280
281    dhcp_set_envvars(reply);
282
283    if (reply) dhcp_free_reply(reply);
284
285    ui_showifconfig();
286    net_setnetvars();
287    return 0;
288}
289
290static int ui_ifconfig_getsw(ui_cmdline_t *cmd,char *swname,char *descr,uint8_t *addr)
291{
292    char *x;
293
294    x = NULL;
295
296    if (cmd_sw_value(cmd,swname,&x) == 0) return 0;
297
298    if ((x == NULL) || (parseipaddr(x,addr) < 0)) {
299	xprintf("Invalid %s: %s\n",descr,x ? x : "(none)");
300	return -1;
301	}
302
303    return 1;
304}
305
306static int ui_ifconfig_lookup(char *name,char *val,const netparam_t *list)
307{
308    const netparam_t *p = list;
309
310    while (p->str) {
311	if (strcmp(p->str,val) == 0) return p->num;
312	p++;
313	}
314
315    xprintf("Invalid parameter for %s: Valid options are: ");
316
317    p = list;
318    while (p->str) {
319	xprintf("%s ",p->str);
320	p++;
321	}
322
323    xprintf("\n");
324    return -1;
325}
326
327
328#define FLG_IPADDR 1
329#define FLG_NETMASK 2
330#define FLG_GATEWAY 4
331#define FLG_NAMESERVER 8
332#define FLG_DOMAIN 16
333#define FLG_LOOPBACK 32
334#define FLG_SPEED 64
335#define FLG_HWADDR 128
336
337static int ui_cmd_ifconfig(ui_cmdline_t *cmd,int argc,char *argv[])
338{
339    char *devname;
340    int flags = 0;
341    uint8_t ipaddr[IP_ADDR_LEN];
342    uint8_t netmask[IP_ADDR_LEN];
343    uint8_t gateway[IP_ADDR_LEN];
344    uint8_t nameserver[IP_ADDR_LEN];
345    uint8_t hwaddr[ENET_ADDR_LEN];
346    int speed = ETHER_SPEED_AUTO;
347    int loopback = ETHER_LOOPBACK_OFF;
348    char *domain = NULL;
349    int res;
350    char *x;
351
352    if (argc < 1) {
353	ui_showifconfig();
354	return 0;
355	}
356
357    devname = cmd_getarg(cmd,0);
358
359    if (cmd_sw_isset(cmd,"-off")) {
360	return ui_ifdown();
361	}
362
363    if (cmd_sw_isset(cmd,"-auto")) {
364	return ui_ifconfig_auto(cmd,devname);
365	}
366
367    res = ui_ifconfig_getsw(cmd,"-addr","interface IP address",ipaddr);
368    if (res < 0) return CFE_ERR_INV_PARAM;
369    if (res > 0) {
370	flags |= FLG_IPADDR;
371	}
372
373    res = ui_ifconfig_getsw(cmd,"-mask","netmask",netmask);
374    if (res < 0) return CFE_ERR_INV_PARAM;
375    if (res > 0) {
376	flags |= FLG_NETMASK;
377	}
378
379    res = ui_ifconfig_getsw(cmd,"-gw","gateway IP address",gateway);
380    if (res < 0) return CFE_ERR_INV_PARAM;
381    if (res > 0) {
382	flags |= FLG_GATEWAY;
383	}
384
385    res = ui_ifconfig_getsw(cmd,"-dns","name server IP address",nameserver);
386    if (res < 0) return CFE_ERR_INV_PARAM;
387    if (res > 0) {
388	flags |= FLG_NAMESERVER;
389	}
390
391    if (cmd_sw_value(cmd,"-domain",&domain)) {
392	if (domain) flags |= FLG_DOMAIN;
393	}
394
395    if (cmd_sw_value(cmd,"-speed",&x)) {
396	speed = ui_ifconfig_lookup("-speed",x,speedtypes);
397	if (speed >= 0) flags |= FLG_SPEED;
398	else return CFE_ERR_INV_PARAM;
399	}
400
401    if (cmd_sw_value(cmd,"-loopback",&x)) {
402	loopback = ui_ifconfig_lookup("-loopback",x,loopbacktypes);
403	if (loopback >= 0) flags |= FLG_LOOPBACK;
404	else return CFE_ERR_INV_PARAM;
405	}
406
407    if (cmd_sw_value(cmd,"-hwaddr",&x)) {
408	if (enet_parse_hwaddr(x,hwaddr) != 0) {
409	    xprintf("Invalid hardware address: %s\n",x);
410	    return CFE_ERR_INV_PARAM;
411	    }
412	else {
413	    flags |= FLG_HWADDR;
414	    }
415	}
416
417    /*
418     * If the network is running and the device name is
419     * different, uninit the net first.
420     */
421
422    x = (char *) net_getparam(NET_DEVNAME);
423
424    if ((x != NULL) && (strcmp(x,devname) != 0)) {
425	net_uninit();
426	}
427
428    /*
429     * Okay, initialize the network if it is not already on.  If it
430     * is OFF, the "net_devname" parameter will be NULL.
431     */
432
433    if (x == NULL) {
434	res = net_init(devname);		/* turn interface on */
435	if (res < 0) {
436	    ui_showerror(res,"Could not activate network interface '%s'",devname);
437	    return res;
438	    }
439	}
440
441    /*
442     * Set the parameters
443     */
444
445    if (flags & FLG_HWADDR)     net_setparam(NET_HWADDR,hwaddr);
446    if (flags & FLG_IPADDR)     net_setparam(NET_IPADDR,ipaddr);
447    if (flags & FLG_NETMASK)    net_setparam(NET_NETMASK,netmask);
448    if (flags & FLG_GATEWAY)    net_setparam(NET_GATEWAY,gateway);
449    if (flags & FLG_NAMESERVER) net_setparam(NET_NAMESERVER,nameserver);
450    if (flags & FLG_DOMAIN)     net_setparam(NET_DOMAIN,(uint8_t *)domain);
451    if (flags & FLG_SPEED)      net_setparam(NET_SPEED,(uint8_t *) &speed);
452    if (flags & FLG_LOOPBACK)   net_setparam(NET_LOOPBACK,(uint8_t *) &loopback);
453
454    ui_showifconfig();
455    net_setnetvars();
456
457    return 0;
458}
459
460
461static int ui_cmd_arp(ui_cmdline_t *cmd,int argc,char *argv[])
462{
463    int idx;
464    uint8_t ipaddr[IP_ADDR_LEN];
465    uint8_t hwaddr[ENET_ADDR_LEN];
466    char *x;
467    int once = 0;
468
469    if (cmd_sw_isset(cmd,"-d")) {
470	if ((x = cmd_getarg(cmd,0)) == NULL) {
471	    return ui_showusage(cmd);
472	    }
473
474	if (strcmp(x,"*") == 0) {
475	    while (arp_enumerate(0,ipaddr,hwaddr) >= 0) {
476		arp_delete(ipaddr);
477		}
478	    }
479	else {
480	    if (parseipaddr(x,ipaddr) < 0) {
481		xprintf("Invalid IP address: %s\n",x);
482		return CFE_ERR_INV_PARAM;
483		}
484	    arp_delete(ipaddr);
485	    }
486	return 0;
487	}
488
489    /*
490     * Get the IP address.  If NULL, display the table.
491     */
492
493    x = cmd_getarg(cmd,0);
494    if (x == NULL) {
495	idx = 0;
496	while (arp_enumerate(idx,ipaddr,hwaddr) >= 0) {
497	    if (once == 0) {
498		xprintf("Hardware Address   IP Address\n");
499		xprintf("-----------------  ---------------\n");
500		once = 1;
501		}
502	    xprintf("%a  %I\n",hwaddr,ipaddr);
503	    idx++;
504	    }
505	if (idx == 0) xprintf("No ARP entries.\n");
506	return 0;
507	}
508
509    if (parseipaddr(x,ipaddr) < 0) {
510	xprintf("Invalid IP address: %s\n",x);
511	return CFE_ERR_INV_PARAM;
512	}
513
514    /*
515     * Get the hardware address.
516     */
517
518    x = cmd_getarg(cmd,1);
519    if (x == NULL) {
520	return ui_showusage(cmd);
521	}
522
523    if (enet_parse_hwaddr(x,hwaddr) < 0) {
524	xprintf("Invalid hardware address: %s\n",x);
525	return CFE_ERR_INV_PARAM;
526	}
527
528    arp_add(ipaddr,hwaddr);
529
530    return 0;
531}
532
533#define IP_HDR_LENGTH    20
534#define ICMP_HDR_LENGTH  8
535#define PING_HDR_LENGTH  (IP_HDR_LENGTH+ICMP_HDR_LENGTH)
536#define MAX_PKT_LENGTH   1500
537
538static int ui_cmd_ping(ui_cmdline_t *cmd,int argc,char *argv[])
539{
540    char *host;
541    uint8_t hostaddr[IP_ADDR_LEN];
542    int res;
543    int seq = 0;
544    int forever = 0;
545    int count = 1;
546    int ttlcount = 1;
547    int countreturned = 0;
548    int size = 56;
549    int flood = 0;
550    int retval = 0;
551    int exitonerror = 0;
552    int needexact = 0;
553    int noabort = 0;
554    char  *x;
555
556    host = cmd_getarg(cmd,0);
557    if (!host) return -1;
558
559    if (cmd_sw_isset(cmd,"-t")) {
560	forever = 1;
561	}
562
563    /* Per traditional Unix usage, the size argument to ping is
564       the number of ICMP data bytes.  The frame on the wire will also
565       include the ethernet, IP and ICMP headers (14, 20, and
566       8 bytes respectively) and ethernet trailer (CRC, 4 bytes). */
567    if (cmd_sw_value(cmd,"-s",&x)) {
568	size = atoi(x);
569	if (size < 0)
570	    size = 0;
571	if (size > MAX_PKT_LENGTH - PING_HDR_LENGTH)
572	    size = MAX_PKT_LENGTH - PING_HDR_LENGTH;
573	}
574
575    if (cmd_sw_isset(cmd,"-f")) {
576	flood = 1;
577	forever = 1;
578	}
579
580    if (cmd_sw_isset(cmd,"-x")) {
581	exitonerror = 1;
582	}
583
584    if (cmd_sw_value(cmd,"-c",&x)) {
585	count = atoi(x);
586	ttlcount = count;
587	forever = 0;
588	}
589
590    if (cmd_sw_isset(cmd,"-A")) {
591	noabort = 1;
592	}
593
594    if (cmd_sw_isset(cmd,"-E")) {
595	needexact = 1;
596	}
597
598    if (isdigit(*host)) {
599	if (parseipaddr(host,hostaddr) < 0) {
600	    xprintf("Invalid IP address: %s\n",host);
601	    return -1;
602	    }
603	}
604    else {
605	res = dns_lookup(host,hostaddr);
606	if (res < 0) {
607	    return ui_showerror(res,"Could not resolve IP address of host %s",host);
608	    }
609	}
610
611    if (forever) xprintf("Press ENTER to stop pinging\n");
612
613    do {
614	res = icmp_ping(hostaddr,seq,size);
615
616	if (res < 0) {
617	    xprintf("Could not transmit echo request\n");
618	    retval = CFE_ERR_IOERR;
619	    break;
620	    }
621	else if (res == 0) {
622	    xprintf("%s (%I) is not responding (seq=%d)\n",host,hostaddr,seq);
623	    retval = CFE_ERR_TIMEOUT;
624	    if (exitonerror) break;
625	    }
626	else {
627	    countreturned++;
628	    if (!flood || ((seq % 10000) == 0)) {
629		if (forever || (ttlcount > 1)) {
630		    xprintf("%s (%I) is alive (seq=%d)\n",host,hostaddr,seq);
631		    }
632		else xprintf("%s (%I) is alive\n",host,hostaddr);
633		}
634	    }
635
636	if ((forever || (count > 1))  && !flood) {
637	    if (res > 0) cfe_sleep(CFE_HZ);
638	    }
639
640	seq++;
641	count--;
642
643	} while ((forever || (count > 0)) && (noabort || !console_status()));
644
645    xprintf("%s (%I): %d packets sent, %d received\n",host,hostaddr,
646	    ttlcount-count,countreturned);
647    return (needexact ? (countreturned != ttlcount) : (countreturned == 0));
648}
649
650#endif
651