1
0
Files
irix-657m-src/stand/arcs/lib/libsk/cmd/ping_cmd.c
2022-09-29 17:59:04 +03:00

429 lines
10 KiB
C

#ident "lib/libsc/cmd/ping_cmd.c: $Revision: 1.12 $"
/*
* ping server at NETADDR
*/
#include <arcs/io.h>
#include <arcs/errno.h>
#include <arcs/eiob.h>
#include <arcs/time.h>
struct mbuf; /* local definitions to quiet irix net headers */
struct ifnet;
#include <sys/param.h>
#include <net/in_systm.h>
#include <net/in.h>
#include <net/ip.h>
#include <netinet/ip_icmp.h>
#include <net/ip_var.h>
#include <net/udp.h>
#include <net/udp_var.h>
#include <saio.h>
#include <saioctl.h>
#include <net/socket.h>
#include <net/arp.h>
#include <net/ei.h>
#include <libsc.h>
#include <libsk.h>
#ifdef SN0
#include <pgdrv.h>
#endif
#define TRUE 1
#define FALSE 0
#define DATALEN 64-8 /* UDP DATA */
#define PACKLEN DATALEN+60+76 /* MAXIP + MAXICMP */
#define FLOOD_INTERVAL 10000 /* 10 ms, for us_delay () */
#define ONE_SECOND 1000000 /* 1 second, for us_delay() */
#define DEFAULT_COUNT 4 /* 4 pings, no more */
static unsigned ping_interval;
static unsigned floodmode;
static unsigned ping_count;
/* socket and file related variables */
#define cei(x) ((struct ether_info *)(x->iob.DevPtr))
static struct sockaddr_in whereto;
static char obuf[PACKLEN];
static char ibuf[PACKLEN];
#if SN0
#ifdef SN_PDI
static char *NetworkName =
"/dev/network/0" ;
#else
static char *NetworkName =
"/xwidget/alias_bridge0/pci/master_ioc3/ef/" ;
#endif
#else
static char *NetworkName = "network(0)";
#endif
extern char netaddr_default[];
int in_cksum(u_short *addr, int len);
/*ARGSUSED*/
int
ping(int argc, char **argv, char **envp, struct cmd_table *bunk2)
{
struct sockaddr_in *to = (struct sockaddr_in *) &whereto;
register char *bp, *cp;
struct in_addr myiaddr, piaddr;
ULONG fd, err;
struct icmp *icp;
int flags = 0;
int iter = 1;
int cc;
struct eiob *io;
FSBLOCK * fsb;
ping_interval = ONE_SECOND;
ping_count = DEFAULT_COUNT;
floodmode = FALSE;
while (--argc > 0) {
argv++;
if (!*argv) /* allow empty argv slots */
continue;
if ((*argv)[0] == '-') /* flag variables */
{
flags++;
switch ((*argv)[1]) {
case 'f': /* enable flood mode */
floodmode = TRUE;
ping_interval = FLOOD_INTERVAL;
break;
case 'c': /* change default number of pings */
if (--argc <= 0)
return(1);
atobu(*++argv, &ping_count);
break;
case 'i': /* change default interval in seconds */
if (--argc <= 0)
return(1);
atobu(*++argv, &ping_interval);
ping_interval *= ONE_SECOND;
break;
default: /* exit if bad flag */
printf("%s is an unknown flag!!!\n", flags, argv[0]);
return(1);
}
printf("flag %d was %s\n", flags, argv[0]);
}
else /* no more flags */
{
break;
}
}
if (argc != 1) /* must be a net address, and only one, left */
return(1);
bp = *argv; /* should be ID of target machine */
/*
* figure out if target has a valid IA address
* these routines adapted from libsc/cmd/bootp.c
*/
piaddr.s_addr = 0; /* clear address */
piaddr = inet_addr(bp); /* parse string */
if (ntohl(piaddr.s_addr) == (unsigned)-1)
{
printf("%s is not a valid Internet address\n", bp);
return(1);
}
/*
* now figure out the IA address of this machine
*/
myiaddr.s_addr = 0;
if ((cp = getenv("netaddr")) != NULL && *cp != '\0')
{
/*
* If Internet address is set in the environment, then
* configure the interface for that IP address.
*/
myiaddr = inet_addr(cp);
if (!strcmp(cp, netaddr_default))
{
printf("%s%s%s",
"Warning: 'netaddr' is set to the default address ", netaddr_default,
".\nUse 'setenv' to reset it to an Internet address on your network.\n");
}
if (ntohl(myiaddr.s_addr) == (unsigned)-1)
{
printf("$netaddr is not a valid Internet address\n");
return(1);
}
}
/*
* both target and this machine have valid IA addresses, so do
* whatever setup necessary
*/
bzero((char *)&whereto, sizeof(struct sockaddr));
/*
printf("Opening %s ...\n", NetworkName);
*/
if ((err = Open(NetworkName, OpenReadWrite, &fd)) != ESUCCESS) {
printf("Error in opening file %s (err = %d)\n",
err, NetworkName);
goto ExitPt;
}
/* get pointer to ioblock */
io = get_eiob(fd);
fsb = &io->fsb;
/*
* 3152 is an arbitrary port number, stolen from symmon
* bind this port and the network address to the open file
*/
/* bind port number */
io->iob.IoctlCmd = (IOCTL_CMD)(__psint_t)NIOCBIND;
io->iob.IoctlArg = (IOCTL_ARG)htons((u_short)3152);
if ((err = _ifioctl(&(io->iob))) != ESUCCESS)
{
printf("Error in binding (err = %d)\n", err);
goto ExitPt;
}
/* bind network address */
io->iob.FunctionCode = FC_IOCTL;
io->iob.IoctlCmd = (IOCTL_CMD)(__psint_t)NIOCSIFADDR;
io->iob.IoctlArg = (IOCTL_ARG)&myiaddr;
if ((err = _ifioctl(&(io->iob))) != ESUCCESS) {
printf("Unable to set interface address\n");
goto ExitPt;
}
/*
* Set the destination
*/
to->sin_family = AF_INET;
to->sin_port = IPPORT_ECHO;
bcopy((const void *)&piaddr.s_addr,(caddr_t)&to->sin_addr,
sizeof(struct in_addr));
/* stolen from libsk/lib/arcsio.c BindSource() - don't want to
* build whole library in debug mode to get this
*/
cei(io)->ei_dstaddr.sin_addr.s_addr = to->sin_addr.s_addr;
cei(io)->ei_dstaddr.sin_port = to->sin_port;
cei(io)->ei_dstaddr.sin_family = to->sin_family;
bcopy((const void *)&cei(io)->ei_dstaddr,
(caddr_t)&cei(io)->ei_gateaddr, sizeof(struct sockaddr_in));
/* print the output info */
printf("PING (%s): %d data bytes\n",
inet_ntoa(piaddr), DATALEN);
/*
* loop through the pings
*/
while ((ping_count) || (floodmode))
{
/* zero data in buffers, just in case */
bzero(obuf, DATALEN+8);
bzero(ibuf, DATALEN+8);
/* build packet - stolen from irix/cmd/bsd/ping.c
* this is a phony icmp header - the real icmp header is wrapped
* around this by the low level code - but the info is useful for
* validation purposes.
*/
{
TIMEINFO *tod;
icp = (struct icmp *)obuf;
icp->icmp_type = ICMP_ECHO;
icp->icmp_code = 0;
icp->icmp_cksum = 0;
icp->icmp_seq = htons((u_short)(iter));
icp->icmp_id = cpuid() & 0xFFFF; /* ID - using cpu as process */
cc = DATALEN+8; /* skips ICMP portion */
/* Copy in TOD info */
tod = GetTime();
bcopy(tod,&obuf[8],sizeof(TIMEINFO));
/* Compute ICMP checksum here */
icp->icmp_cksum = in_cksum( (u_short *)icp, cc );
}
/* send packet */
/*
* set-up device independent iob parameters
*/
fsb->IO->Address = obuf;
fsb->IO->Count = DATALEN+8;
DEVWRITE(fsb);
/*
* attempt to receive reply
*/
fsb->IO->Count = PACKLEN;
fsb->IO->Address = ibuf;
do {
_scandevs(); /* allow for console interrupts */
#if SN0
/* Do this again, since _scandevs calling epoll()
* could have messed with Function code.
*/
fsb->IO->Count = PACKLEN;
fsb->IO->Address = ibuf;
#endif
} while ((cc = DEVREAD(fsb)) <= 0);
/* print result */
{
TIMEINFO *tod, *got;
unsigned short csum;
unsigned delta;
icp = (struct icmp *) ibuf;
cc = DATALEN+8; /* skips ICMP portion */
/*
* Now the ICMP part
* just returned data and not real ICMP header, but we still
* can use it to validate data bounce, calculate elapsed time,
* and such
*/
if (icp->icmp_type == ICMP_ECHO)
{
if( icp->icmp_id != (cpuid() & 0xFFFF))
{
printf("ECHO reply to unknown process\n");
goto END_RESULT;
}
if (icp->icmp_seq != iter)
{
printf("wrong sequence number - got %d, expected %d\n",
icp->icmp_seq, iter);
}
/* save recieved cksum and recompute */
csum = icp->icmp_cksum;
icp->icmp_cksum = 0;
if ((icp->icmp_cksum = in_cksum((u_short *)icp, cc)) != csum)
{
printf("wrong checksum - got %d, expected %d\n",
csum, icp->icmp_cksum);
}
/*
* figure out trip time
* Despite Field Name, "Milliseconds" is really 16 bit
* uS free-running counter. Hmm.
*/
tod = GetTime();
got = (TIMEINFO *)&ibuf[8];
if (tod->Milliseconds >= got->Milliseconds)
delta = tod->Milliseconds - got->Milliseconds;
else
delta = (tod ->Milliseconds + 0xffff) - got->Milliseconds;
delta /= 1000;
/*
* print out all the nice info - since we don't have access
* to the ip header information without a major hack, we
* just assume that the echo source is the system we sent
* the request to
*/
printf("%d bytes from %s: icmp_seq=%u", cc,
inet_ntoa(piaddr), ntohs((u_short)icp->icmp_seq));
printf(" time=%d ms", delta);
}
else
{
/* We've got something other than ECHO */
printf("%d bytes from %s", cc, inet_ntoa(piaddr));
}
END_RESULT:
/* guarantee newline */
printf("\n");
}
/* wait before pinging again */
us_delay(ping_interval);
iter++;
if(!floodmode)
ping_count--;
err= 0;
}
ExitPt:
Close(fd);
return((int)err);
}
/*
* I N _ C K S U M
*
* Checksum routine for Internet Protocol family headers (C Version)
*
*/
int
in_cksum(u_short *addr, int len)
{
register int nleft = len;
register u_short *w = addr;
register int sum = 0;
u_short answer = 0;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum),
* we add sequential 16 bit words to it, and at the end, fold
* back all the carry bits from the top 16 bits into the lower
* 16 bits.
*/
while( nleft > 1 ) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if( nleft == 1 ) {
*(u_char *)(&answer) = *(u_char *)w ;
sum += answer;
}
/*
* add back carry outs from top 16 bits to low 16 bits
*/
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return (answer);
}