home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 20 / AACD20.BIN / AACD / Programming / TTCP_SDK / ping / ping.c < prev    next >
Encoding:
Text File  |  1996-07-28  |  36.9 KB  |  1,369 lines

  1.  /*
  2.  * ping.c -- network connectivity testing tool
  3.  */
  4.  
  5. /*
  6.     NAME
  7.         ping - send ICMP ECHO_REQUEST packets to network hosts
  8.  
  9.     SYNOPSIS
  10.         ping [-dfnqrv] [-c count] [-i wait] [-l preload] [-p pattern]
  11.              [-s packetsize]  host
  12.  
  13.     DESCRIPTION
  14.         Ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to
  15.         elicit an ICMP ECHO_RESPONSE from a host or gateway.  ECHO_REQUEST
  16.         datagrams (``pings'') have an IP and ICMP header, followed by a
  17.         ``struct timeval'' and then an arbitrary number of ``pad'' bytes
  18.         used to fill out the packet.  The options are as follows: Other
  19.         options are:
  20.  
  21.         -c count
  22.                 Stop after sending (and receiving) count ECHO_RESPONSE
  23.                 packets.
  24.  
  25.         -d      Set the SO_DEBUG option on the socket being used.
  26.  
  27.         -f      Flood ping.  Outputs packets as fast as they come back or
  28.                 one hundred times per second, whichever is more.  For every
  29.                 ECHO_REQUEST sent a period ``.'' is printed, while for ever
  30.                 ECHO_REPLY received a backspace is printed.  This provides a
  31.                 rapid display of how many packets are being dropped.  Only
  32.                 the super-user may use this option.  This can be very hard
  33.                 on a network and should be used with caution.
  34.  
  35.         -i wait
  36.                 Wait wait seconds between sending each packet. The default
  37.                 is to wait for one second between each packet.  This option
  38.                 is incompatible with the -f option.
  39.  
  40.         -l preload
  41.                 If preload is specified, ping sends that many packets as
  42.                 fast as possible before falling into its normal mode of
  43.                 behavior.
  44.  
  45.         -n      Numeric output only.  No attempt will be made to lookup
  46.                 symbolic names for host addresses.
  47.  
  48.         -p pattern
  49.                 You may specify up to 16 ``pad'' bytes to fill out the
  50.                 packet you send.  This is useful for diagnosing
  51.                 data-dependent problems in a network.  For example, ``-p
  52.                 ff'' will cause the sent packet to be filled with all ones.
  53.  
  54.         -q      Quiet output.  Nothing is displayed except the summary lines
  55.                 at startup time and when finished.
  56.  
  57.         -r      Bypass the normal routing tables and send directly to a host
  58.                 on an attached network.  If the host is not on a
  59.                 directly-attached network, an error is returned.  This
  60.                 option can be used to ping a local host through an interface
  61.                 that has no route through it.
  62.  
  63.         -s packetsize
  64.                 Specifies the number of data bytes to be sent.  The default
  65.                 is 56, which translates into 64 ICMP data bytes when
  66.                 combined with the 8 bytes of ICMP header data.
  67.  
  68.         -v      Verbose output.  ICMP packets other than ECHO_RESPONSE that
  69.                 are received are listed.
  70.  
  71.         When using ping for fault isolation, it should first be run on the
  72.         local host, to verify that the local network interface is up and
  73.         running.  Then, hosts and gateways further and further away should
  74.         be ``pinged''.  Round-trip times and packet loss statistics are
  75.         computed.  If duplicate packets are received, they are not included
  76.         in the packet loss calculation, although the round trip time of
  77.         these packets is used in calculating the minimum/average/maximum
  78.         round-trip time numbers.  When the specified number of packets have
  79.         been sent (and received) or if the program is terminated with a
  80.         SIGINT, a brief summary is displayed.
  81.  
  82.         This program is intended for use in network testing, measurement and
  83.         management.  Because of the load it can impose on the network, it is
  84.         unwise to use ping during normal operations or from automated
  85.         scripts.
  86.  
  87.     ICMP PACKET DETAILS
  88.         An IP header without options is 20 bytes.  An ICMP ECHO_REQUEST
  89.         packet contains an additional 8 bytes worth of ICMP header followed
  90.         by an arbitrary amount of data.  When a packetsize is given, this
  91.         indicated the size of this extra piece of data (the default is 56).
  92.         Thus the amount of data received inside of an IP packet of type ICMP
  93.         ECHO_REPLY will always be 8 bytes more than the requested data space
  94.         (the ICMP header).
  95.  
  96.         If the data space is at least eight bytes large, ping uses the first
  97.         eight bytes of this space to include a timestamp which it uses in
  98.         the computation of round trip times.  If less than eight bytes of
  99.         pad are specified, no round trip times are given.
  100.  
  101.     DUPLICATE AND DAMAGED PACKETS
  102.         Ping will report duplicate and damaged packets.  Duplicate packets
  103.         should never occur, and seem to be caused by inappropriate
  104.         link-level retransmissions.  Duplicates may occur in many situations
  105.         and are rarely (if ever) a good sign, although the presence of low
  106.         levels of duplicates may not always be cause for alarm.
  107.  
  108.         Damaged packets are obviously serious cause for alarm and often
  109.         indicate broken hardware somewhere in the ping packet's path (in the
  110.         network or in the hosts).
  111.  
  112.     TRYING DIFFERENT DATA PATTERNS
  113.         The (inter)network layer should never treat packets differently
  114.         depending on the data contained in the data portion.  Unfortunately,
  115.         data-dependent problems have been known to sneak into networks and
  116.         remain undetected for long periods of time.  In many cases the
  117.         particular pattern that will have problems is something that doesn't
  118.         have sufficient ``transitions'', such as all ones or all zeros, or a
  119.         pattern right at the edge, such as almost all zeros.  It isn't
  120.         necessarily enough to specify a data pattern of all zeros (for
  121.         example) on the command line because the pattern that is of interest
  122.         is at the data link level, and the relationship between what you
  123.         type and what the controllers transmit can be complicated.
  124.  
  125.         This means that if you have a data-dependent problem you will
  126.         probably have to do a lot of testing to find it.  If you are lucky,
  127.         you may manage to find a file that either can't be sent across your
  128.         network or that takes much longer to transfer than other similar
  129.         length files.  You can then examine this file for repeated patterns
  130.         that you can test using the -p option of ping.
  131.  
  132.     TTL DETAILS
  133.         The TTL value of an IP packet represents the maximum number of IP
  134.         routers that the packet can go through before being thrown away.  In
  135.         current practice you can expect each router in the Internet to
  136.         decrement the TTL field by exactly one.
  137.  
  138.         The TCP/IP specification states that the TTL field for TCP packets
  139.         should be set to 60, but many systems use smaller values (4.3 BSD
  140.         uses 30, 4.2 used 15). The Termite TCP uses normally TTL value 30.
  141.  
  142.         The maximum possible value of this field is 255, and most systems
  143.         set the TTL field of ICMP ECHO_REQUEST packets to 255.  This is why
  144.         you will find you can ``ping'' some hosts, but not reach them with
  145.         telnet or ftp.
  146.  
  147.         In normal operation ping prints the ttl value from the packet it re-
  148.         ceives.  When a remote system receives a ping packet, it can do one
  149.         of three things with the TTL field in its response:
  150.  
  151.         ·   Not change it; this is what Berkeley Unix systems did before the
  152.             4.3BSD-Tahoe release.  In this case the TTL value in the
  153.             received packet will be 255 minus the number of routers in the
  154.             round-trip path.
  155.  
  156.         ·   Set it to 255; this is what TermiteTCP and current Berkeley Unix
  157.             systems do.  In this case the TTL value in the received packet
  158.             will be 255 minus the number of routers in the path from the
  159.             remote system to the pinging host.
  160.  
  161.         ·   Set it to some other value.  Some machines use the same value
  162.             for ICMP packets that they use for TCP packets, for example
  163.             either 30 or 60.  Others may use completely wild values.
  164.  
  165.     NOTE  
  166.         Flood pinging is not recommended in general, and flood pinging the
  167.         broadcast address should only be done under very controlled
  168.         conditions.
  169.  
  170.  
  171.     AUTHOR
  172.         Mike Muuss, U. S. Army Ballistic Research Laboratory, December, 1983
  173.  
  174.         The ping command appeared in 4.3BSD.
  175.  
  176. *****************************************************************************
  177. * */
  178.  
  179. /*
  180.  *            P I N G . C
  181.  *
  182.  * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
  183.  * measure round-trip-delays and packet loss across network paths.
  184.  *
  185.  * Author -
  186.  *    Mike Muuss
  187.  *    U. S. Army Ballistic Research Laboratory
  188.  *    December, 1983
  189.  *
  190.  * Status -
  191.  *    Public Domain.  Distribution Unlimited.
  192.  */
  193.  
  194. #include <exec/types.h>
  195. #include <sys/types.h>
  196. #include "ping_rev.h"
  197. #include <proto/tsocket.h>
  198. #include <pragmas/tsocket_pragmas.h>
  199. #define ioctl IoctlSocket
  200.  
  201. #include <sys/param.h>
  202. #include <sys/socket.h>
  203. #include <sys/time.h>
  204.  
  205. #ifdef __SASC
  206. #include <fcntl.h>
  207. #include <signal.h>
  208. #else
  209. #include <sys/file.h>
  210. #include <sys/signal.h>
  211. #endif
  212.  
  213. #include <netinet/in_systm.h>
  214. #include <netinet/in.h>
  215. #include <netinet/ip.h>
  216. #include <netinet/ip_icmp.h>
  217. #include <netinet/ip_var.h>
  218. #include <netdb.h>
  219. #include <arpa/inet.h>
  220. #include <unistd.h>
  221. #include <stdio.h>
  222. #include <ctype.h>
  223. #include <errno.h>
  224. #include <string.h>
  225. #include <stdlib.h>
  226.  
  227. #define    DEFDATALEN    (64 - 8)    /* default data length */
  228. #define    MAXIPLEN    60
  229. #define    MAXICMPLEN    76
  230. #define    MAXPACKET    (65536 - 60 - 8)/* max packet size */
  231. #define    MAXWAIT        10        /* max seconds to wait for response */
  232. #define    NROUTES        9        /* number of record route slots */
  233.  
  234. #define    A(bit)        rcvd_tbl[(bit)>>3]    /* identify byte in array */
  235. #define    B(bit)        (1 << ((bit) & 0x07))    /* identify bit in byte */
  236. #define    SET(bit)    (A(bit) |= B(bit))
  237. #define    CLR(bit)    (A(bit) &= (~B(bit)))
  238. #define    TST(bit)    (A(bit) & B(bit))
  239.  
  240. /* various options */
  241. int options;
  242. #define    F_FLOOD        0x001
  243. #define    F_INTERVAL    0x002
  244. #define    F_NUMERIC    0x004
  245. #define    F_PINGFILLED    0x008
  246. #define    F_QUIET        0x010
  247. #define    F_RROUTE    0x020
  248. #define    F_SO_DEBUG    0x040
  249. #define    F_SO_DONTROUTE    0x080
  250. #define    F_VERBOSE    0x100
  251. #define F_LOOSEROUTE    0x200
  252.  
  253. #ifndef LONG_MAX
  254. #define LONG_MAX 0xffffffff
  255. #endif
  256.  
  257. /*
  258.  * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
  259.  * number of received sequence numbers we can keep track of.  Change 128
  260.  * to 8192 for complete accuracy...
  261.  */
  262. #define    MAX_DUP_CHK    (8 * 128)
  263. int mx_dup_ck = MAX_DUP_CHK;
  264. char rcvd_tbl[MAX_DUP_CHK / 8];
  265.  
  266. struct sockaddr whereto;    /* who to ping */
  267. int datalen = DEFDATALEN;
  268. int s = -1;            /* socket file descriptor */
  269. u_char *outpack;
  270. char BSPACE = '\b';        /* characters written for flood */
  271. char DOT = '.';
  272. char *hostname;
  273. long ident;            /* process id to identify our packets */
  274. int optind = 1;
  275.  
  276. /* counters */
  277. long npackets;            /* max packets to transmit */
  278. long nreceived;            /* # of packets we got back */
  279. long nrepeats;            /* number of duplicates */
  280. long ntransmitted;        /* sequence # for outbound packets = #sent */
  281. int interval = 1;        /* interval between packets */
  282.  
  283. /* timing */
  284. int timing;            /* flag to do timing */
  285. long tmin = 999999;           /* minimum round trip time */
  286. long tmax;            /* maximum round trip time */
  287. u_long tsum;            /* sum of all times, for doing average */
  288.  
  289. char *pr_addr(u_long l);
  290. void catcher(void), pinger(void), finish(void), usage(void);
  291. void pr_pack(char *buf,    int cc,    struct sockaddr_in *from);
  292. void pr_icmph(struct icmp *icp);
  293. void pr_iph(struct ip *ip);
  294. void pr_retip(struct ip *ip);
  295. void fill(char *bp, char *patp);
  296. int in_cksum(u_short *addr, int len);
  297. void tvsub(register struct timeval *out, register struct timeval *in);
  298.  
  299. #ifdef AMIGA
  300. /*
  301.  * Other Amiga dependent stuff
  302.  */
  303. #ifdef __SASC
  304. #include <clib/exec_protos.h>
  305. #include <pragmas/exec_sysbase_pragmas.h>
  306. extern struct ExecBase *SysBase;
  307. /* Disable ^C signaling */
  308. void __regargs __chkabort(void) {}
  309. #else
  310. #include <clib/exec_protos.h>
  311. #endif
  312. #include <proto/timer.h>
  313. #include <dos/dos.h>
  314.  
  315. #define getpid(x) ((ULONG)FindTask(NULL)) /* This is only for ident... */
  316.  
  317. struct Library *TSocketBase = NULL;
  318. struct MsgPort *timerport = NULL;
  319. struct timerequest *timermsg = NULL;
  320. BOOL notopen = TRUE;
  321. #define TimerBase (timermsg->tr_node.io_Device)
  322.  
  323. void
  324. clean_timer(void)
  325. {
  326.   if (timermsg) {
  327.     if (!notopen) {
  328.       if (!CheckIO((struct IORequest*)timermsg)) {
  329.     AbortIO((struct IORequest*)timermsg);
  330.     WaitIO((struct IORequest*)timermsg);
  331.       }
  332.       CloseDevice((struct IORequest*)timermsg);
  333.       notopen = TRUE;
  334.     }
  335.     DeleteIORequest(timermsg);
  336.     timermsg = NULL;
  337.   }
  338.   if (timerport) {
  339.     DeleteMsgPort(timerport);
  340.     timerport = NULL;
  341.   }
  342. }
  343. #endif
  344.  
  345. main(argc, argv)
  346.     int argc;
  347.     char **argv;
  348. {
  349.   extern int errno, optind;
  350.   extern char *optarg;
  351.   struct timeval timeout;
  352.   struct hostent *hp;
  353.   struct sockaddr_in *to;
  354.   struct protoent *proto;
  355.   register int i;
  356.   int ch = 0, fdmask, hold, packlen, preload;
  357.   u_char *datap, *packet;
  358.   char *target, hnamebuf[MAXHOSTNAMELEN];
  359. #ifdef IP_OPTIONS
  360.   u_char rspace[3 + 4 * NROUTES + 1]; /* record route space */
  361. #endif
  362. #ifdef AMIGA
  363.   ULONG timermask;
  364. #endif
  365.  
  366.   TSocketBase = OpenLibrary("tsocket.library", 0);
  367.   if ( !TSocketBase )
  368.   {
  369.     puts("no socket library");
  370.     exit(1);
  371.   }    
  372.  
  373.   outpack = malloc(MAXPACKET);
  374.   if (outpack == NULL) {
  375.     perror("ping");
  376.     CloseLibrary(TSocketBase);
  377.     exit(1);
  378.   }
  379.   preload = 0;
  380.   datap = &outpack[8 + sizeof(struct timeval)];
  381. /*  while ((ch = getopt(argc, argv, "c:dfh:i:l:np:qrs:v")) != EOF)  */
  382.     while (0) /***************************** fix this *****************/
  383.     switch(ch) {
  384.     case 'c':
  385.       npackets = atoi(optarg);
  386.       if (npackets <= 0) {
  387.     (void)fprintf(stderr, "ping: bad number of packets to transmit.\n");
  388.         CloseLibrary(TSocketBase);
  389.     exit(1);
  390.       }
  391.       break;
  392.     case 'd':
  393.       options |= F_SO_DEBUG;
  394.       break;
  395.     case 'f':
  396. #ifndef AMIGA
  397.       if (getuid()) {
  398.     (void)fprintf(stderr, "ping: %s\n", strerror(EPERM));
  399.         CloseLibrary(TSocketBase);
  400.     exit(1);
  401.       }
  402. #endif
  403.       options |= F_FLOOD;
  404.       setbuf(stdout, (char *)NULL);
  405.       break;
  406.     case 'i':            /* wait between sending packets */
  407.       interval = atoi(optarg);
  408.       if (interval <= 0) {
  409.     (void)fprintf(stderr, "ping: bad timing interval.\n");
  410.         CloseLibrary(TSocketBase);
  411.     exit(1);
  412.       }
  413.       options |= F_INTERVAL;
  414.       break;
  415.     case 'L':
  416.       options |= F_LOOSEROUTE;
  417.       break;
  418.     case 'l':
  419.       preload = atoi(optarg);
  420.       if (preload < 0) {
  421.     (void)fprintf(stderr, "ping: bad preload value.\n");
  422.         CloseLibrary(TSocketBase);
  423.     exit(1);
  424.       }
  425.       break;
  426.     case 'n':
  427.       options |= F_NUMERIC;
  428.       break;
  429.     case 'p':            /* fill buffer with user pattern */
  430.       options |= F_PINGFILLED;
  431.       fill((char *)datap, optarg);
  432.       break;
  433.     case 'q':
  434.       options |= F_QUIET;
  435.       break;
  436.     case 'R':
  437.       options |= F_RROUTE;
  438.       break;
  439.     case 'r':
  440.       options |= F_SO_DONTROUTE;
  441.       break;
  442.     case 's':            /* size of packet to send */
  443.       datalen = atoi(optarg);
  444.       if (datalen > MAXPACKET) {
  445.     (void)fprintf(stderr, "ping: packet size too large.\n");
  446.         CloseLibrary(TSocketBase);
  447.     exit(1);
  448.       }
  449.       if (datalen <= 0) {
  450.     (void)fprintf(stderr, "ping: illegal packet size.\n");
  451.         CloseLibrary(TSocketBase);
  452.     exit(1);
  453.       }
  454.       break;
  455.     case 'v':
  456.       options |= F_VERBOSE;
  457.       break;
  458.     default:
  459.       usage();
  460.     }
  461.   argc -= optind;
  462.   argv += optind;
  463.  
  464.   if (argc < 1 || (options & F_LOOSEROUTE) == 0 && argc > 1)
  465.     usage();
  466.  
  467.   if ((options & (F_LOOSEROUTE | F_RROUTE)) == (F_LOOSEROUTE | F_RROUTE)) {
  468.     fprintf(stderr, "ping: -L and -R options cannot be used concurrently\n");
  469.     CloseLibrary(TSocketBase);
  470.     exit(1);
  471.   }
  472.  
  473.   {
  474.     u_char *cp = rspace;
  475.  
  476.     if (options & F_LOOSEROUTE) {
  477. #ifdef IP_OPTIONS
  478.       rspace[IPOPT_OPTVAL] = IPOPT_LSRR;
  479.       rspace[IPOPT_OLEN] = 3;
  480.       rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
  481.       cp = rspace + IPOPT_OFFSET + 1;
  482. #else
  483.       (void)fprintf(stderr, "ping: source routing not "
  484.             "available in this implementation.\n");
  485.       CloseLibrary(TSocketBase);
  486.       exit(1);
  487. #endif                /* IP_OPTIONS */
  488.     }
  489.  
  490.     while (target = *argv++) {
  491.       bzero((char *)&whereto, sizeof(struct sockaddr));
  492.       to = (struct sockaddr_in *)&whereto;
  493. #ifdef _SOCKADDR_LEN
  494.       to->sin_len = sizeof(*to);
  495. #endif
  496.       to->sin_family = AF_INET;
  497.       to->sin_addr.s_addr = inet_addr(target);
  498.       if (to->sin_addr.s_addr != (u_int)-1)
  499.     hostname = target;
  500.       else {
  501.     hp = gethostbyname(target);
  502.     if (!hp) {
  503.       fprintf(stderr, "ping: unknown host %s\n", target);
  504.           CloseLibrary(TSocketBase);
  505.       exit(1);
  506.     }
  507.     to->sin_family = hp->h_addrtype;
  508.     bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
  509.     (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
  510.     hostname = hnamebuf;
  511.       }
  512.  
  513. #ifdef IP_OPTIONS
  514.       if (options & F_LOOSEROUTE) {
  515.     if (rspace + sizeof(rspace) - 4 < cp) {
  516.       fprintf(stderr, "ping: too many hops for "
  517.           "source routing %s\n", target);
  518.           CloseLibrary(TSocketBase);
  519.       exit(1);
  520.     }
  521.     *cp++ = (to->sin_addr.s_addr >> 24);
  522.     *cp++ = (to->sin_addr.s_addr >> 16);
  523.     *cp++ = (to->sin_addr.s_addr >> 8);
  524.     *cp++ = (to->sin_addr.s_addr >> 0);
  525.     rspace[IPOPT_OLEN] += 4;
  526.       }
  527. #endif
  528.     }
  529.   }
  530.  
  531.   if (options & F_FLOOD && options & F_INTERVAL) {
  532.     (void)fprintf(stderr, "ping: -f and -i incompatible options.\n");
  533.     CloseLibrary(TSocketBase);
  534.     exit(1);
  535.   }
  536.  
  537.   if (datalen >= sizeof(struct timeval)) /* can we time transfer */
  538.     timing = 1;
  539.   packlen = datalen + MAXIPLEN + MAXICMPLEN;
  540.   if (!(packet = (u_char *)malloc((u_int)packlen))) {
  541.     (void)fprintf(stderr, "ping: out of memory.\n");
  542.     CloseLibrary(TSocketBase);
  543.     exit(1);
  544.   }
  545.   if (!(options & F_PINGFILLED))
  546.     for (i = 8; i < datalen; ++i)
  547.       *datap++ = i;
  548.  
  549.   ident = getpid() & 0xFFFF;
  550.  
  551.   if (!(proto = getprotobyname("icmp"))) {
  552.     (void)fprintf(stderr, "ping: unknown protocol icmp.\n");
  553.     CloseLibrary(TSocketBase);
  554.     exit(1);
  555.   }
  556.  
  557. #ifdef AMIGA
  558.   atexit(clean_timer);
  559.  
  560.   timerport = CreateMsgPort();
  561.   if (!timerport) {
  562.     (void)fprintf(stderr, "ping: could not create timer port.\n");
  563.     CloseLibrary(TSocketBase);
  564.     exit(1);
  565.   }
  566.   timermask = 1<<timerport->mp_SigBit;
  567.  
  568.   timermsg = CreateIORequest(timerport, sizeof(*timermsg));
  569.   if (!timermsg) {
  570.     (void)fprintf(stderr, "ping: could not create timer message.\n");
  571.     CloseLibrary(TSocketBase);
  572.     exit(1);
  573.   }
  574.  
  575.   if (notopen = OpenDevice("timer.device", UNIT_MICROHZ,
  576.          (struct IORequest *)timermsg, 0)) {
  577.     (void)fprintf(stderr, "ping: could not open timer device.\n");
  578.     CloseLibrary(TSocketBase);
  579.     exit(1);
  580.   }
  581.  
  582.   timermsg->tr_node.io_Command = TR_ADDREQUEST;
  583.   timermsg->tr_time.tv_secs = 1L;
  584.   timermsg->tr_time.tv_micro = 0L;
  585.   /* don't confuse CheckIO */
  586.   timermsg->tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
  587.   SetSocketSignals(timermask | SIGBREAKF_CTRL_C, 0L, 0L);
  588. #endif
  589.  
  590.   if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
  591.     perror("ping: socket");
  592.     CloseLibrary(TSocketBase);
  593.     exit(1);
  594.   }
  595.   hold = 1;
  596.   if (options & F_SO_DEBUG)
  597.     (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
  598.              sizeof(hold));
  599.   if (options & F_SO_DONTROUTE)
  600.     (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
  601.              sizeof(hold));
  602.  
  603. #ifdef IP_OPTIONS
  604.   if (options & F_LOOSEROUTE) {
  605.     /* pad to long word */
  606.     rspace[rspace[IPOPT_OLEN]] = IPOPT_EOL;
  607.     if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
  608.            rspace[IPOPT_OLEN] + 1) < 0) {
  609.       perror("ping: source routing");
  610.       CloseLibrary(TSocketBase);
  611.       exit(1);
  612.     }
  613.   }
  614. #endif
  615.  
  616.   /* record route option */
  617.   if (options & F_RROUTE) {
  618. #ifdef IP_OPTIONS
  619.     rspace[IPOPT_OPTVAL] = IPOPT_RR;
  620.     rspace[IPOPT_OLEN] = sizeof(rspace)-1;
  621.     rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
  622.     rspace[rspace[IPOPT_OLEN]] = IPOPT_EOL;
  623.     if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
  624.            sizeof(rspace)) < 0) {
  625.       perror("ping: record route");
  626.       CloseLibrary(TSocketBase);
  627.       exit(1);
  628.     }
  629. #else
  630.     (void)fprintf(stderr,
  631.           "ping: record route not available in this implementation.\n");
  632.     CloseLibrary(TSocketBase);
  633.     exit(1);
  634. #endif                /* IP_OPTIONS */
  635.   }
  636.  
  637.   /*
  638.    * When pinging the broadcast address, you can get a lot of answers.
  639.    * Doing something so evil is useful if you are trying to stress the
  640.    * ethernet, or just want to fill the arp cache to get some stuff for
  641.    * /etc/ethers.
  642.    */
  643.   hold = 48 * 1024;
  644.   (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
  645.            sizeof(hold));
  646.  
  647.   if (to->sin_family == AF_INET)
  648.     (void)printf("PING %s (%s): %d data bytes\n", hostname,
  649.          inet_ntoa(*/*(struct in_addr *)*/&to->sin_addr.s_addr),
  650.          datalen);
  651.   else
  652.     (void)printf("PING %s: %d data bytes\n", hostname, datalen);
  653.  
  654. #ifndef AMIGA
  655.   (void)signal(SIGINT, finish);
  656.   (void)signal(SIGALRM, catcher);
  657. #endif
  658.  
  659.   while (preload--)        /* fire off them quickies */
  660.     pinger();
  661.  
  662.   if ((options & F_FLOOD) == 0)
  663.     catcher();            /* start things going */
  664.  
  665.   for (;;) {
  666.     struct sockaddr_in from;
  667.     register int cc;
  668.     int fromlen;
  669.  
  670. #ifdef AMIGA
  671.     /* Check for special signals */
  672.     ULONG sm = SetSignal(0L, timermask | SIGBREAKF_CTRL_C);
  673.     if (sm & SIGBREAKF_CTRL_C)
  674.       finish();
  675.     if (sm & timermask && GetMsg(timerport))
  676.       catcher();
  677. #endif
  678.  
  679.     if (options & F_FLOOD) {
  680.       pinger();
  681.       timeout.tv_sec = 0;
  682.       timeout.tv_usec = 10000;
  683.       fdmask = 1 << s;
  684.       if (select(s + 1, (fd_set *)&fdmask, (fd_set *)NULL,
  685.          (fd_set *)NULL, &timeout) < 1)
  686.     continue;
  687.     }
  688.     fromlen = sizeof(from);
  689.     if ((cc = recvfrom(s, (char *)packet, packlen, 0,
  690.                (caddr_t)&from, &fromlen)) < 0) {
  691.       if (errno == EINTR)
  692.     continue;
  693.       perror("ping: recvfrom");
  694.       continue;
  695.     }
  696.     pr_pack((char *)packet, cc, &from);
  697.     if (npackets && nreceived >= npackets)
  698.       break;
  699.   }
  700.   finish();
  701.   /* NOTREACHED */
  702. }
  703.  
  704. /*
  705.  * catcher --
  706.  *    This routine causes another PING to be transmitted, and then
  707.  * schedules another SIGALRM for 1 second from now.
  708.  *
  709.  * bug --
  710.  *    Our sense of time will slowly skew (i.e., packets will not be
  711.  * launched exactly at 1-second intervals).  This does not affect the
  712.  * quality of the delay and loss statistics.
  713.  *
  714.  * notes --
  715.  *      This routine uses timer.device in Amiga implementation instead
  716.  * of SIGALRM.
  717.  */
  718. void
  719. catcher()
  720. {
  721. #ifdef AMIGA
  722.   static int waittime = 0;
  723.  
  724.   if (waittime)
  725.     finish();
  726.  
  727.   pinger();
  728.  
  729.   if (!npackets || ntransmitted < npackets) {
  730.     timermsg->tr_time.tv_sec = interval;
  731.     SendIO((struct IORequest*)timermsg);
  732.   } else {
  733.     if (nreceived) {
  734.       waittime = 2 * tmax / 1000;
  735.       if (!waittime)
  736.     waittime = 1;
  737.     } else
  738.       waittime = MAXWAIT;
  739.     timermsg->tr_time.tv_sec = waittime;
  740.     SendIO((struct IORequest*)timermsg);
  741.   }
  742. #else
  743.     int waittime;
  744.  
  745.     pinger();
  746.     (void)signal(SIGALRM, catcher);
  747.     if (!npackets || ntransmitted < npackets)
  748.         alarm((u_int)interval);
  749.     else {
  750.         if (nreceived) {
  751.             waittime = 2 * tmax / 1000;
  752.             if (!waittime)
  753.                 waittime = 1;
  754.         } else
  755.             waittime = MAXWAIT;
  756.         (void)signal(SIGALRM, finish);
  757.         (void)alarm((u_int)waittime);
  758.     }
  759. #endif
  760. }
  761.  
  762. /*
  763.  * pinger --
  764.  *     Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
  765.  * will be added on by the kernel.  The ID field is our process ID,
  766.  * and the sequence number is an ascending integer.  The first 8 bytes
  767.  * of the data portion are used to hold a UNIX "timeval" struct in native
  768.  * byte-order, to compute the round-trip time.
  769.  */
  770. void
  771. pinger()
  772. {
  773.     register struct icmp *icp;
  774.     register int cc;
  775.     int i;
  776.  
  777.     icp = (struct icmp *)outpack;
  778.     icp->icmp_type = ICMP_ECHO;
  779.     icp->icmp_code = 0;
  780.     icp->icmp_cksum = 0;
  781.     icp->icmp_seq = ntransmitted++;
  782.     icp->icmp_id = ident;            /* ID */
  783.  
  784.     CLR(icp->icmp_seq % mx_dup_ck);
  785.  
  786.     if (timing)
  787. #ifdef AMIGA
  788.         (void)ReadEClock((struct EClockVal *)&outpack[8]);
  789. #else
  790.         (void)gettimeofday((struct timeval *)&outpack[8],
  791.             (struct timezone *)NULL);
  792. #endif
  793.     cc = datalen + 8;            /* skips ICMP portion */
  794.  
  795.     /* compute ICMP checksum here */
  796.     icp->icmp_cksum = in_cksum((u_short *)icp, cc);
  797.  
  798.     i = sendto(s, (char *)outpack, cc, 0, (caddr_t)&whereto,
  799.         sizeof(struct sockaddr));
  800.  
  801.     if (i < 0 || i != cc)  {
  802.         if (i < 0)
  803.             perror("ping: sendto");
  804.         (void)printf("ping: wrote %s %d chars, ret=%d\n",
  805.             hostname, cc, i);
  806.     }
  807.     if (!(options & F_QUIET) && options & F_FLOOD)
  808.         (void)write(1, &DOT, 1);
  809. }
  810.  
  811. /*
  812.  * pr_pack --
  813.  *    Print out the packet, if it came from us.  This logic is necessary
  814.  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
  815.  * which arrive ('tis only fair).  This permits multiple copies of this
  816.  * program to be run without having intermingled output (or statistics!).
  817.  */
  818. void
  819. pr_pack(buf, cc, from)
  820.     char *buf;
  821.     int cc;
  822.     struct sockaddr_in *from;
  823. {
  824.     register struct icmp *icp;
  825.     register u_long l;
  826.     register int i, j;
  827.     register u_char *cp,*dp;
  828.     static int old_rrlen;
  829.     static char old_rr[MAX_IPOPTLEN];
  830.     struct ip *ip;
  831.     struct timeval tv, *tp;
  832.     long triptime;
  833.     int hlen, dupflag;
  834.  
  835. #ifdef AMIGA
  836.     ULONG efreq = ReadEClock((struct EClockVal *)&tv);
  837. #else
  838.     (void)gettimeofday(&tv, (struct timezone *)NULL);
  839. #endif
  840.     /* Check the IP header */
  841.     ip = (struct ip *)buf;
  842.     hlen = ip->ip_hl << 2;
  843.     if (cc < hlen + ICMP_MINLEN) {
  844.         if (options & F_VERBOSE)
  845.             (void)fprintf(stderr,
  846.               "ping: packet too short (%d bytes) from %s\n", cc,
  847.               inet_ntoa(*/*(struct in_addr *)*/&from->sin_addr.s_addr));
  848.         return;
  849.     }
  850.  
  851.     /* Now the ICMP part */
  852.     cc -= hlen;
  853.     icp = (struct icmp *)(buf + hlen);
  854.     if (icp->icmp_type == ICMP_ECHOREPLY) {
  855.         if (icp->icmp_id != ident)
  856.             return;            /* 'Twas not our ECHO */
  857.         ++nreceived;
  858.         if (timing) {
  859. #ifndef icmp_data
  860.             tp = (struct timeval *)&icp->icmp_ip;
  861. #else
  862.             tp = (struct timeval *)icp->icmp_data;
  863. #endif
  864. #ifdef AMIGA
  865.             /* EClockVal is actually a unsigned long long */
  866.             if (tv.tv_micro < tp->tv_micro)
  867.               tv.tv_sec--;
  868.             tv.tv_micro -= tp->tv_micro;
  869.             tv.tv_secs  -= tp->tv_secs;
  870.             triptime = tv.tv_micro / (efreq / 1000);
  871.             if (tv.tv_secs)
  872.               triptime += tv.tv_sec * 250 * ((1<<30) / efreq);
  873. #else
  874.             tvsub(&tv, tp);
  875.             triptime = tv.tv_sec * 1000 + (tv.tv_usec / 1000);
  876. #endif
  877.             tsum += triptime;
  878.             if (triptime < tmin)
  879.                 tmin = triptime;
  880.             if (triptime > tmax)
  881.                 tmax = triptime;
  882.         }
  883.  
  884.         if (TST(icp->icmp_seq % mx_dup_ck)) {
  885.             ++nrepeats;
  886.             --nreceived;
  887.             dupflag = 1;
  888.         } else {
  889.             SET(icp->icmp_seq % mx_dup_ck);
  890.             dupflag = 0;
  891.         }
  892.  
  893.         if (options & F_QUIET)
  894.             return;
  895.  
  896.         if (options & F_FLOOD)
  897.             (void)write(1, &BSPACE, 1);
  898.         else {
  899.             (void)printf("%d bytes from %s: icmp_seq=%u", cc,
  900.                inet_ntoa(*/*(struct in_addr *)*/&from->sin_addr.s_addr),
  901.                icp->icmp_seq);
  902.             (void)printf(" ttl=%d", ip->ip_ttl);
  903.             if (timing)
  904.                 (void)printf(" time=%ld ms", triptime);
  905.             if (dupflag)
  906.                 (void)printf(" (DUP!)");
  907.             /* check the data */
  908.             cp = (u_char*)&icp->icmp_data[8];
  909.             dp = &outpack[8 + sizeof(struct timeval)];
  910.             for (i = 8; i < datalen; ++i, ++cp, ++dp) {
  911.                 if (*cp != *dp) {
  912.     (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
  913.         i, *dp, *cp);
  914.                     cp = (u_char*)&icp->icmp_data[0];
  915.                     for (i = 8; i < datalen; ++i, ++cp) {
  916.                         if ((i % 32) == 8)
  917.                             (void)printf("\n\t");
  918.                         (void)printf("%x ", *cp);
  919.                     }
  920.                     break;
  921.                 }
  922.             }
  923.         }
  924.     } else {
  925.         /* We've got something other than an ECHOREPLY */
  926.         if (!(options & F_VERBOSE))
  927.             return;
  928.         (void)printf("%d bytes from %s: ", cc,
  929.             pr_addr(from->sin_addr.s_addr));
  930.         pr_icmph(icp);
  931.     }
  932.  
  933.     /* Display any IP options */
  934.     /* The LSRR and RR len handling was broken (?) //ppessi */
  935.     cp = (u_char *)buf + sizeof(struct ip);
  936.  
  937.     for (; hlen > (int)sizeof(struct ip); --hlen, ++cp)
  938.         switch (*cp) {
  939.         case IPOPT_EOL:
  940.             hlen = 0;
  941.             break;
  942.         case IPOPT_LSRR:
  943.         case IPOPT_SSRR:
  944.             (void)printf(*cp == IPOPT_LSRR ?
  945.                      "\nLSRR: " : "\nSSRR: ");
  946.             j = *++cp;
  947.             ++cp;
  948.             hlen -= j;
  949.             if (j > IPOPT_MINOFF)
  950.                 for (;;) {
  951.                     l = *++cp;
  952.                     l = (l<<8) + *++cp;
  953.                     l = (l<<8) + *++cp;
  954.                     l = (l<<8) + *++cp;
  955.                     if (l == 0)
  956.                         (void)printf("\t0.0.0.0");
  957.                     else
  958.                         (void)printf("\t%s", pr_addr(l));
  959.                     j -= 4;
  960.                     if (j < IPOPT_MINOFF)
  961.                         break;
  962.                     (void)putchar('\n');
  963.                 }
  964.             break;
  965.         case IPOPT_RR:
  966.             j = *++cp;        /* get length */
  967.             i = *++cp;        /* and pointer */
  968.             hlen -= j;
  969.             if (i > j)
  970.                 i = j;
  971.             i -= IPOPT_MINOFF;
  972.             if (i <= 0)
  973.                 continue;
  974.             if (i == old_rrlen
  975.                 && cp == (u_char *)buf + sizeof(struct ip) + 2
  976.                 && !bcmp((char *)cp, old_rr, i)
  977.                 && !(options & F_FLOOD)) {
  978.                 (void)printf("\t(same route)");
  979.                 i = ((i + 3) / 4) * 4;
  980.                 cp += i;
  981.                 break;
  982.             }
  983.             old_rrlen = i;
  984.             bcopy((char *)cp, old_rr, i);
  985.             (void)printf("\nRR: ");
  986.             for (;;) {
  987.                 l = *++cp;
  988.                 l = (l<<8) + *++cp;
  989.                 l = (l<<8) + *++cp;
  990.                 l = (l<<8) + *++cp;
  991.                 if (l == 0)
  992.                     (void)printf("\t0.0.0.0");
  993.                 else
  994.                     (void)printf("\t%s", pr_addr(l));
  995.                 i -= 4;
  996.                 if (i <= 0)
  997.                     break;
  998.                 (void)putchar('\n');
  999.             }
  1000.             break;
  1001.         case IPOPT_NOP:
  1002.             (void)printf("\nNOP");
  1003.             break;
  1004.         default:
  1005.             (void)printf("\nunknown option %x", *cp);
  1006.             break;
  1007.         }
  1008.     if (!(options & F_FLOOD)) {
  1009.         (void)putchar('\n');
  1010.         (void)fflush(stdout);
  1011.     }
  1012. }
  1013.  
  1014. /*
  1015.  * in_cksum --
  1016.  *    Checksum routine for Internet Protocol family headers (C Version)
  1017.  */
  1018. int
  1019. in_cksum(addr, len)
  1020.     u_short *addr;
  1021.     int len;
  1022. {
  1023.     register int nleft = len;
  1024.     register u_short *w = addr;
  1025.     register int sum = 0;
  1026.     u_short answer = 0;
  1027.  
  1028.     /*
  1029.      * Our algorithm is simple, using a 32 bit accumulator (sum), we add
  1030.      * sequential 16 bit words to it, and at the end, fold back all the
  1031.      * carry bits from the top 16 bits into the lower 16 bits.
  1032.      */
  1033.     while (nleft > 1)  {
  1034.         sum += *w++;
  1035.         nleft -= 2;
  1036.     }
  1037.  
  1038.     /* mop up an odd byte, if necessary */
  1039.     if (nleft == 1) {
  1040.         *(u_char *)(&answer) = *(u_char *)w ;
  1041.         sum += answer;
  1042.     }
  1043.  
  1044.     /* add back carry outs from top 16 bits to low 16 bits */
  1045.     sum = (sum >> 16) + (sum & 0xffff);    /* add hi 16 to low 16 */
  1046.     sum += (sum >> 16);            /* add carry */
  1047.     answer = ~sum;                /* truncate to 16 bits */
  1048.     return(answer);
  1049. }
  1050.  
  1051. /*
  1052.  * tvsub --
  1053.  *    Subtract 2 timeval structs:  out = out - in.  Out is assumed to
  1054.  * be >= in.
  1055.  */
  1056. void
  1057. tvsub(out, in)
  1058.     register struct timeval *out, *in;
  1059. {
  1060.     if ((out->tv_usec -= in->tv_usec) < 0) {
  1061.         --out->tv_sec;
  1062.         out->tv_usec += 1000000;
  1063.     }
  1064.     out->tv_sec -= in->tv_sec;
  1065. }
  1066.  
  1067. /*
  1068.  * finish --
  1069.  *    Print out statistics, and give up.
  1070.  */
  1071. void
  1072. finish()
  1073. {
  1074.     (void)signal(SIGINT, SIG_IGN);
  1075.     (void)putchar('\n');
  1076.     (void)fflush(stdout);
  1077.     (void)printf("--- %s ping statistics ---\n", hostname);
  1078.     (void)printf("%ld packets transmitted, ", ntransmitted);
  1079.     (void)printf("%ld packets received, ", nreceived);
  1080.     if (nrepeats)
  1081.         (void)printf("+%ld duplicates, ", nrepeats);
  1082.     if (ntransmitted)
  1083.         if (nreceived > ntransmitted)
  1084.             (void)printf("-- somebody's printing up packets!");
  1085.         else
  1086.             (void)printf("%d%% packet loss",
  1087.                 (int) (((ntransmitted - nreceived) * 100) /
  1088.                 ntransmitted));
  1089.     (void)putchar('\n');
  1090.     if (nreceived && timing)
  1091.         (void)printf("round-trip min/avg/max = %ld/%lu/%ld ms\n",
  1092.             tmin, tsum / (nreceived + nrepeats), tmax);
  1093.         CloseLibrary(TSocketBase);
  1094.     exit(0);
  1095. }
  1096.  
  1097. #ifdef notdef
  1098. static char *ttab[] = {
  1099.     "Echo Reply",        /* ip + seq + udata */
  1100.     "Dest Unreachable",    /* net, host, proto, port, frag, sr + IP */
  1101.     "Source Quench",    /* IP */
  1102.     "Redirect",        /* redirect type, gateway, + IP  */
  1103.     "Echo",
  1104.     "Time Exceeded",    /* transit, frag reassem + IP */
  1105.     "Parameter Problem",    /* pointer + IP */
  1106.     "Timestamp",        /* id + seq + three timestamps */
  1107.     "Timestamp Reply",    /* " */
  1108.     "Info Request",        /* id + sq */
  1109.     "Info Reply"        /* " */
  1110. };
  1111. #endif
  1112.  
  1113. /*
  1114.  * pr_icmph --
  1115.  *    Print a descriptive string about an ICMP header.
  1116.  */
  1117. void
  1118. pr_icmph(icp)
  1119.     struct icmp *icp;
  1120. {
  1121.     switch(icp->icmp_type) {
  1122.     case ICMP_ECHOREPLY:
  1123.         (void)printf("Echo Reply\n");
  1124.         /* XXX ID + Seq + Data */
  1125.         break;
  1126.     case ICMP_UNREACH:
  1127.         switch(icp->icmp_code) {
  1128.         case ICMP_UNREACH_NET:
  1129.             (void)printf("Destination Net Unreachable\n");
  1130.             break;
  1131.         case ICMP_UNREACH_HOST:
  1132.             (void)printf("Destination Host Unreachable\n");
  1133.             break;
  1134.         case ICMP_UNREACH_PROTOCOL:
  1135.             (void)printf("Destination Protocol Unreachable\n");
  1136.             break;
  1137.         case ICMP_UNREACH_PORT:
  1138.             (void)printf("Destination Port Unreachable\n");
  1139.             break;
  1140.         case ICMP_UNREACH_NEEDFRAG:
  1141.             (void)printf("frag needed and DF set\n");
  1142.             break;
  1143.         case ICMP_UNREACH_SRCFAIL:
  1144.             (void)printf("Source Route Failed\n");
  1145.             break;
  1146.         default:
  1147.             (void)printf("Dest Unreachable, Bad Code: %d\n",
  1148.                 icp->icmp_code);
  1149.             break;
  1150.         }
  1151.         /* Print returned IP header information */
  1152. #ifndef icmp_data
  1153.         pr_retip(&icp->icmp_ip);
  1154. #else
  1155.         pr_retip((struct ip *)icp->icmp_data);
  1156. #endif
  1157.         break;
  1158.     case ICMP_SOURCEQUENCH:
  1159.         (void)printf("Source Quench\n");
  1160. #ifndef icmp_data
  1161.         pr_retip(&icp->icmp_ip);
  1162. #else
  1163.         pr_retip((struct ip *)icp->icmp_data);
  1164. #endif
  1165.         break;
  1166.     case ICMP_REDIRECT:
  1167.         switch(icp->icmp_code) {
  1168.         case ICMP_REDIRECT_NET:
  1169.             (void)printf("Redirect Network");
  1170.             break;
  1171.         case ICMP_REDIRECT_HOST:
  1172.             (void)printf("Redirect Host");
  1173.             break;
  1174.         case ICMP_REDIRECT_TOSNET:
  1175.             (void)printf("Redirect Type of Service and Network");
  1176.             break;
  1177.         case ICMP_REDIRECT_TOSHOST:
  1178.             (void)printf("Redirect Type of Service and Host");
  1179.             break;
  1180.         default:
  1181.             (void)printf("Redirect, Bad Code: %d", icp->icmp_code);
  1182.             break;
  1183.         }
  1184.         (void)printf("(New addr: 0x%08lx)\n", icp->icmp_gwaddr.s_addr);
  1185. #ifndef icmp_data
  1186.         pr_retip(&icp->icmp_ip);
  1187. #else
  1188.         pr_retip((struct ip *)icp->icmp_data);
  1189. #endif
  1190.         break;
  1191.     case ICMP_ECHO:
  1192.         (void)printf("Echo Request\n");
  1193.         /* XXX ID + Seq + Data */
  1194.         break;
  1195.     case ICMP_TIMXCEED:
  1196.         switch(icp->icmp_code) {
  1197.         case ICMP_TIMXCEED_INTRANS:
  1198.             (void)printf("Time to live exceeded\n");
  1199.             break;
  1200.         case ICMP_TIMXCEED_REASS:
  1201.             (void)printf("Frag reassembly time exceeded\n");
  1202.             break;
  1203.         default:
  1204.             (void)printf("Time exceeded, Bad Code: %d\n",
  1205.                 icp->icmp_code);
  1206.             break;
  1207.         }
  1208. #ifndef icmp_data
  1209.         pr_retip(&icp->icmp_ip);
  1210. #else
  1211.         pr_retip((struct ip *)icp->icmp_data);
  1212. #endif
  1213.         break;
  1214.     case ICMP_PARAMPROB:
  1215.         (void)printf("Parameter problem: pointer = 0x%02x\n",
  1216.             icp->icmp_hun.ih_pptr);
  1217. #ifndef icmp_data
  1218.         pr_retip(&icp->icmp_ip);
  1219. #else
  1220.         pr_retip((struct ip *)icp->icmp_data);
  1221. #endif
  1222.         break;
  1223.     case ICMP_TSTAMP:
  1224.         (void)printf("Timestamp\n");
  1225.         /* XXX ID + Seq + 3 timestamps */
  1226.         break;
  1227.     case ICMP_TSTAMPREPLY:
  1228.         (void)printf("Timestamp Reply\n");
  1229.         /* XXX ID + Seq + 3 timestamps */
  1230.         break;
  1231.     case ICMP_IREQ:
  1232.         (void)printf("Information Request\n");
  1233.         /* XXX ID + Seq */
  1234.         break;
  1235.     case ICMP_IREQREPLY:
  1236.         (void)printf("Information Reply\n");
  1237.         /* XXX ID + Seq */
  1238.         break;
  1239. #ifdef ICMP_MASKREQ
  1240.     case ICMP_MASKREQ:
  1241.         (void)printf("Address Mask Request\n");
  1242.         break;
  1243. #endif
  1244. #ifdef ICMP_MASKREPLY
  1245.     case ICMP_MASKREPLY:
  1246.         (void)printf("Address Mask Reply\n");
  1247.         break;
  1248. #endif
  1249.     default:
  1250.         (void)printf("Bad ICMP type: %d\n", icp->icmp_type);
  1251.     }
  1252. }
  1253.  
  1254. /*
  1255.  * pr_iph --
  1256.  *    Print an IP header with options.
  1257.  */
  1258. void
  1259. pr_iph(ip)
  1260.     struct ip *ip;
  1261. {
  1262.     int hlen;
  1263.     u_char *cp;
  1264.  
  1265.     hlen = ip->ip_hl << 2;
  1266.     cp = (u_char *)ip + 20;        /* point to options */
  1267.  
  1268.     (void)printf("Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst Data\n");
  1269.     (void)printf(" %1x  %1x  %02x %04x %04x",
  1270.         ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);
  1271.     (void)printf("   %1x %04x", ((ip->ip_off) & 0xe000) >> 13,
  1272.         (ip->ip_off) & 0x1fff);
  1273.     (void)printf("  %02x  %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum);
  1274.     (void)printf(" %s ", inet_ntoa(*/*(struct in_addr *)*/&ip->ip_src.s_addr));
  1275.     (void)printf(" %s ", inet_ntoa(*/*(struct in_addr *)*/&ip->ip_dst.s_addr));
  1276.     /* dump and option bytes */
  1277.     while (hlen-- > 20) {
  1278.         (void)printf("%02x", *cp++);
  1279.     }
  1280.     (void)putchar('\n');
  1281. }
  1282.  
  1283. /*
  1284.  * pr_addr --
  1285.  *    Return an ascii host address as a dotted quad and optionally with
  1286.  * a hostname.
  1287.  */
  1288. char *
  1289. pr_addr(l)
  1290.     u_long l;
  1291. {
  1292.     struct hostent *hp;
  1293.     static char buf[80];
  1294.  
  1295.     if ((options & F_NUMERIC) ||
  1296.         !(hp = gethostbyaddr((char *)&l, 4, AF_INET)))
  1297.         (void)sprintf(buf, "%s", inet_ntoa(*/*(struct in_addr *)*/&l));
  1298.     else
  1299.         (void)sprintf(buf, "%s (%s)", hp->h_name,
  1300.             inet_ntoa(*/*(struct in_addr *)*/&l));
  1301.     return(buf);
  1302. }
  1303.  
  1304. /*
  1305.  * pr_retip --
  1306.  *    Dump some info on a returned (via ICMP) IP packet.
  1307.  */
  1308. void
  1309. pr_retip(ip)
  1310.     struct ip *ip;
  1311. {
  1312.     int hlen;
  1313.     u_char *cp;
  1314.  
  1315.     pr_iph(ip);
  1316.     hlen = ip->ip_hl << 2;
  1317.     cp = (u_char *)ip + hlen;
  1318.  
  1319.     if (ip->ip_p == 6)
  1320.         (void)printf("TCP: from port %u, to port %u (decimal)\n",
  1321.             (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
  1322.     else if (ip->ip_p == 17)
  1323.         (void)printf("UDP: from port %u, to port %u (decimal)\n",
  1324.             (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
  1325. }
  1326.  
  1327. void
  1328. fill(bp, patp)
  1329.     char *bp, *patp;
  1330. {
  1331.     register int ii, jj, kk;
  1332.     int pat[16];
  1333.     char *cp;
  1334.  
  1335.     for (cp = patp; *cp; cp++)
  1336.         if (!isxdigit(*cp)) {
  1337.             (void)fprintf(stderr,
  1338.                 "ping: patterns must be specified as hex digits.\n");
  1339.                         CloseLibrary(TSocketBase);
  1340.             exit(1);
  1341.         }
  1342.     ii = sscanf(patp,
  1343.         "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
  1344.         &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
  1345.         &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
  1346.         &pat[13], &pat[14], &pat[15]);
  1347.  
  1348.     if (ii > 0)
  1349.         for (kk = 0; kk <= MAXPACKET - (8 + ii); kk += ii)
  1350.             for (jj = 0; jj < ii; ++jj)
  1351.                 bp[jj + kk] = pat[jj];
  1352.     if (!(options & F_QUIET)) {
  1353.         (void)printf("PATTERN: 0x");
  1354.         for (jj = 0; jj < ii; ++jj)
  1355.             (void)printf("%02x", bp[jj] & 0xFF);
  1356.         (void)printf("\n");
  1357.     }
  1358. }
  1359.  
  1360. void
  1361. usage()
  1362. {
  1363.     (void)fprintf(stderr,
  1364.         "usage: ping [-Rdfnqrv] [-c count] [-i wait] [-l preload]\n"
  1365.               "\t[-p pattern] [-s packetsize] [-L [hosts]] host\n");
  1366.         CloseLibrary(TSocketBase);
  1367.     exit(1);
  1368. }
  1369.