source: rtems/cpukit/libmisc/shell/main_ping.c @ 68e1ccc4

5
Last change on this file since 68e1ccc4 was 6cdaa85, checked in by Sebastian Huber <sebastian.huber@…>, on 10/04/18 at 18:16:45

shell: Use #include "..." for local header files

Update #3375.

  • Property mode set to 100644
File size: 51.1 KB
Line 
1#ifdef __rtems__
2#define __need_getopt_newlib
3#include <getopt.h>
4#endif
5/*
6 * Copyright (c) 1989, 1993
7 *      The Regents of the University of California.  All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Mike Muuss.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#if !__rtems__
38#ifndef lint
39static const char copyright[] =
40"@(#) Copyright (c) 1989, 1993\n\
41        The Regents of the University of California.  All rights reserved.\n";
42#endif /* not lint */
43
44#ifndef lint
45static char sccsid[] = "@(#)ping.c      8.1 (Berkeley) 6/5/93";
46#endif /* not lint */
47#endif
48#include <sys/cdefs.h>
49__FBSDID("$FreeBSD$");
50
51/*
52 *                      P I N G . C
53 *
54 * Using the Internet Control Message Protocol (ICMP) "ECHO" facility,
55 * measure round-trip-delays and packet loss across network paths.
56 *
57 * Author -
58 *      Mike Muuss
59 *      U. S. Army Ballistic Research Laboratory
60 *      December, 1983
61 *
62 * Status -
63 *      Public Domain.  Distribution Unlimited.
64 * Bugs -
65 *      More statistics could always be gathered.
66 *      This program has to run SUID to ROOT to access the ICMP socket.
67 */
68
69#include <sys/param.h>          /* NB: we rely on this for <sys/types.h> */
70#include <sys/socket.h>
71#include <sys/sysctl.h>
72#include <sys/time.h>
73#include <sys/uio.h>
74
75#include <netinet/in.h>
76#include <netinet/in_systm.h>
77#include <netinet/ip.h>
78#include <netinet/ip_icmp.h>
79#include <netinet/ip_var.h>
80#include <arpa/inet.h>
81
82#ifdef IPSEC
83#include <netipsec/ipsec.h>
84#endif /*IPSEC*/
85
86#include <ctype.h>
87//#include "err.h"
88#include <errno.h>
89#if !defined(__rtems__)
90#include <math.h>
91#endif
92#include <netdb.h>
93#include <signal.h>
94#include <stdio.h>
95#include <stdlib.h>
96#include <string.h>
97//#include <sysexits.h>
98#include <unistd.h>
99
100#include "err.h"
101#include "sysexits.h"
102#include <sys/select.h>
103#ifdef __rtems__
104#include <rtems/shell.h>
105#endif /* __rtems__ */
106
107#define INADDR_LEN      ((int)sizeof(in_addr_t))
108#define TIMEVAL_LEN     ((int)sizeof(struct tv32))
109#define MASK_LEN        (ICMP_MASKLEN - ICMP_MINLEN)
110#define TS_LEN          (ICMP_TSLEN - ICMP_MINLEN)
111#define DEFDATALEN      56              /* default data length */
112#define FLOOD_BACKOFF   20000           /* usecs to back off if F_FLOOD mode */
113                                        /* runs out of buffer space */
114#define MAXIPLEN        (sizeof(struct ip) + MAX_IPOPTLEN)
115#define MAXICMPLEN      (ICMP_ADVLENMIN + MAX_IPOPTLEN)
116#define MAXWAIT         10000           /* max ms to wait for response */
117#define MAXALARM        (60 * 60)       /* max seconds for alarm timeout */
118#define MAXTOS          255
119
120#define A(bit)          rcvd_tbl[(bit)>>3]      /* identify byte in array */
121#define B(bit)          (1 << ((bit) & 0x07))   /* identify bit in byte */
122#define SET(bit)        (A(bit) |= B(bit))
123#define CLR(bit)        (A(bit) &= (~B(bit)))
124#define TST(bit)        (A(bit) & B(bit))
125
126struct tv32 {
127        int32_t tv32_sec;
128        int32_t tv32_usec;
129};
130
131/* various options */
132#if !__rtems__
133int options;
134#endif
135#define F_FLOOD         0x0001
136#define F_INTERVAL      0x0002
137#define F_NUMERIC       0x0004
138#define F_PINGFILLED    0x0008
139#define F_QUIET         0x0010
140#define F_RROUTE        0x0020
141#define F_SO_DEBUG      0x0040
142#define F_SO_DONTROUTE  0x0080
143#define F_VERBOSE       0x0100
144#define F_QUIET2        0x0200
145#define F_NOLOOP        0x0400
146#define F_MTTL          0x0800
147#define F_MIF           0x1000
148#define F_AUDIBLE       0x2000
149#ifdef IPSEC
150#ifdef IPSEC_POLICY_IPSEC
151#define F_POLICY        0x4000
152#endif /*IPSEC_POLICY_IPSEC*/
153#endif /*IPSEC*/
154#define F_TTL           0x8000
155#define F_MISSED        0x10000
156#define F_ONCE          0x20000
157#define F_HDRINCL       0x40000
158#define F_MASK          0x80000
159#define F_TIME          0x100000
160#define F_SWEEP         0x200000
161#define F_WAITTIME      0x400000
162
163/*
164 * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
165 * number of received sequence numbers we can keep track of.  Change 128
166 * to 8192 for complete accuracy...
167 */
168#define MAX_DUP_CHK     (8 * 128)
169#if !__rtems__
170int mx_dup_ck = MAX_DUP_CHK;
171char rcvd_tbl[MAX_DUP_CHK / 8];
172
173struct sockaddr_in whereto;     /* who to ping */
174int datalen = DEFDATALEN;
175int maxpayload;
176int s;                          /* socket file descriptor */
177u_char outpackhdr[IP_MAXPACKET], *outpack;
178#endif
179char BBELL = '\a';              /* characters written for MISSED and AUDIBLE */
180char BSPACE = '\b';             /* characters written for flood */
181char DOT = '.';
182#if !__rtems__
183char *hostname;
184char *shostname;
185int ident;                      /* process id to identify our packets */
186int uid;                        /* cached uid for micro-optimization */
187u_char icmp_type = ICMP_ECHO;
188u_char icmp_type_rsp = ICMP_ECHOREPLY;
189int phdr_len = 0;
190int send_len;
191
192/* counters */
193long nmissedmax;                /* max value of ntransmitted - nreceived - 1 */
194long npackets;                  /* max packets to transmit */
195long nreceived;                 /* # of packets we got back */
196long nrepeats;                  /* number of duplicates */
197long ntransmitted;              /* sequence # for outbound packets = #sent */
198long snpackets;                 /* max packets to transmit in one sweep */
199long snreceived;                /* # of packets we got back in this sweep */
200long sntransmitted;             /* # of packets we sent in this sweep */
201int sweepmax;                   /* max value of payload in sweep */
202int sweepmin = 0;               /* start value of payload in sweep */
203int sweepincr = 1;              /* payload increment in sweep */
204int interval = 1000;            /* interval between packets, ms */
205int waittime = MAXWAIT;         /* timeout for each packet */
206long nrcvtimeout = 0;           /* # of packets we got back after waittime */
207
208/* timing */
209int timing;                     /* flag to do timing */
210double tmin = 999999999.0;      /* minimum round trip time */
211double tmax = 0.0;              /* maximum round trip time */
212double tsum = 0.0;              /* sum of all times, for doing average */
213double tsumsq = 0.0;            /* sum of all times squared, for std. dev. */
214
215volatile sig_atomic_t finish_up;  /* nonzero if we've been told to finish up */
216volatile sig_atomic_t siginfo_p;
217
218static void fill(char *, char *);
219static u_short in_cksum(u_short *, int);
220static void check_status(void);
221static void finish(void) __dead2;
222static void pinger(void);
223static char *pr_addr(struct in_addr);
224static char *pr_ntime(n_time);
225static void pr_icmph(struct icmp *);
226static void pr_iph(struct ip *);
227static void pr_pack(char *, int, struct sockaddr_in *, struct timeval *);
228static void pr_retip(struct ip *);
229static void status(int);
230static void stopit(int);
231static void tvsub(struct timeval *, struct timeval *);
232static void usage(void) __dead2;
233#endif
234
235#if __rtems__
236#define CMSG_SPACE(l)   (_ALIGN(sizeof(struct cmsghdr)) + _ALIGN(l))
237#define CMSG_LEN(l)     (_ALIGN(sizeof(struct cmsghdr)) + (l))
238typedef struct
239{
240  int options;
241  int mx_dup_ck;
242  char rcvd_tbl[MAX_DUP_CHK / 8];
243  struct sockaddr_in whereto;
244  int datalen;
245  int maxpayload;
246  int s;
247  u_char outpackhdr[IP_MAXPACKET];
248  u_char *outpack;
249  char *hostname;
250  char *shostname;
251  int ident;
252  int uid;
253  u_char icmp_type;
254  u_char icmp_type_rsp;
255  int phdr_len;
256  int send_len;
257  long nmissedmax;
258  long npackets;
259  long nreceived;
260  long nrepeats;
261  long ntransmitted;
262  long snpackets;
263  long snreceived;
264  long sntransmitted;
265  int sweepmax;
266  int sweepmin;
267  int sweepincr;
268  int interval;
269  int waittime;
270  long nrcvtimeout;
271  int timing;
272  double tmin;
273  double tmax;
274  double tsum;
275  double tsumsq;
276  volatile sig_atomic_t finish_up;
277  volatile sig_atomic_t siginfo_p;
278
279  /* main */
280  u_char packet[IP_MAXPACKET] __aligned(4);
281
282  /* pr_pack */
283        int old_rrlen;
284        char old_rr[MAX_IPOPTLEN];
285
286  int exit_code;
287  jmp_buf exit_jmp;
288} rtems_shell_globals_t;
289
290#define options_ globals->options
291#define mx_dup_ck globals->mx_dup_ck
292#define rcvd_tbl globals->rcvd_tbl
293#define whereto globals->whereto
294#define datalen globals->datalen
295#define maxpayload globals->maxpayload
296#define s globals->s
297#define outpackhdr globals->outpackhdr
298#define outpack globals->outpack
299#define hostname globals->hostname
300#define shostname globals->shostname
301#define ident globals->ident
302#define uid globals->uid
303#define icmp_type_ globals->icmp_type
304#define icmp_type_rsp globals->icmp_type_rsp
305#define phdr_len globals->phdr_len
306#define send_len globals->send_len
307#define nmissedmax globals->nmissedmax
308#define npackets globals->npackets
309#define nreceived globals->nreceived
310#define nrepeats globals->nrepeats
311#define ntransmitted globals->ntransmitted
312#define snpackets globals->snpackets
313#define snreceived globals->snreceived
314#define sntransmitted globals->sntransmitted
315#define sweepmax globals->sweepmax
316#define sweepmin globals->sweepmin
317#define sweepincr globals->sweepincr
318#define interval globals->interval
319#define waittime globals->waittime
320#define nrcvtimeout globals->nrcvtimeout
321#define timing globals->timing
322#define tmin globals->tmin
323#define tmax globals->tmax
324#define tsum globals->tsum
325#define tsumsq globals->tsumsq
326#define finish_up globals->finish_up
327#define siginfo_p globals->siginfo_p
328
329#define old_rrlen globals->old_rrlen
330#define old_rr globals->old_rr
331
332#define packet_ globals->packet
333
334static u_short in_cksum(u_short *, int);
335static char *pr_ntime(n_time);
336static void pr_icmph(struct icmp *);
337static void pr_iph(struct ip *);
338static void pr_retip(struct ip *);
339static void stopit(int);
340static void tvsub(struct timeval *, struct timeval *);
341
342#define fill(_a1, _a2)  g_fill(_a1, _a2, globals)
343static void g_fill(char *_a1, char *_a2, rtems_shell_globals_t* globals);
344
345#define check_status() g_check_status(globals)
346static void g_check_status(rtems_shell_globals_t* globals);
347
348#define finish() g_finish(globals)
349static void g_finish(rtems_shell_globals_t* globals) __dead2;
350
351#define pinger() g_pinger(globals)
352static void g_pinger(rtems_shell_globals_t* globals);
353
354#define pr_addr(_a1) g_pr_addr(_a1, globals)
355static char *g_pr_addr(struct in_addr, rtems_shell_globals_t* globals);
356
357#define pr_pack(_a1, _a2, _a3, _a4) g_pr_pack(_a1, _a2, _a3, _a4, globals)
358static void g_pr_pack(char *, int, struct sockaddr_in *, struct timeval *, rtems_shell_globals_t* globals);
359
360#define usage() g_usage(globals)
361static void g_usage(rtems_shell_globals_t* globals) __dead2;
362
363static void
364rtems_shell_ping_exit (rtems_shell_globals_t* globals, int code)
365{
366  globals->exit_code = code;
367  longjmp (globals->exit_jmp, 1);
368}
369
370#define exit(_c) rtems_shell_ping_exit (globals, _c)
371#define _exit(_c) exit(_c)
372
373static int main_ping(int argc, char *const *argv, rtems_shell_globals_t* globals);
374static int rtems_shell_main_ping(int argc, char *argv[])
375{
376  rtems_shell_globals_t* globals = malloc(sizeof(rtems_shell_globals_t));
377  if (!globals)
378  {
379    printf("error: no memory\n");
380    return 1;
381  }
382  memset (globals, 0, sizeof (rtems_shell_globals_t));
383  npackets = 5;
384  datalen = DEFDATALEN;
385  icmp_type_ = ICMP_ECHO;
386  icmp_type_rsp = ICMP_ECHOREPLY;
387  phdr_len = 0;
388  sweepmin = 0;
389  sweepincr = 1;
390  interval = 1000;
391  waittime = MAXWAIT;
392  nrcvtimeout = 0;
393  tmin = 999999999.0;
394  tmax = 0.0;
395  tsum = 0.0;
396  tsumsq = 0.0;
397  globals->exit_code = 1;
398  if (setjmp (globals->exit_jmp) == 0)
399    return main_ping (argc, argv, globals);
400  return globals->exit_code;
401}
402#endif
403
404
405
406int
407#ifdef __rtems__
408main_ping(argc, argv, globals)
409#else
410main(argc, argv)
411#endif
412        int argc;
413        char *const *argv;
414  rtems_shell_globals_t* globals;
415{
416        struct sockaddr_in from, sock_in;
417        struct in_addr ifaddr;
418        struct timeval last, intvl;
419        struct iovec iov;
420        struct ip *ip;
421        struct msghdr msg;
422        struct sigaction si_sa;
423        size_t sz;
424#if !__rtems__
425        u_char *datap, packet[IP_MAXPACKET] __aligned(4);
426#else
427        u_char *datap;
428#endif
429        char *ep, *source, *target, *payload;
430        struct hostent *hp;
431#ifdef IPSEC_POLICY_IPSEC
432        char *policy_in, *policy_out;
433#endif
434        struct sockaddr_in *to;
435        double t;
436        u_long alarmtimeout, ultmp;
437        int almost_done, ch, df, hold, i, icmp_len, mib[4], preload, sockerrno,
438            tos, ttl;
439        char ctrl[CMSG_SPACE(sizeof(struct timeval))];
440        char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN];
441#ifdef IP_OPTIONS
442        char rspace[MAX_IPOPTLEN];      /* record route space */
443#endif
444        unsigned char loop, mttl;
445#ifdef __rtems__
446        struct getopt_data getopt_reent;
447#define optarg getopt_reent.optarg
448#define optind getopt_reent.optind
449#define opterr getopt.reent.opterr
450#define optopt getopt.reent.optopt
451#endif
452
453        payload = source = NULL;
454#ifdef IPSEC_POLICY_IPSEC
455        policy_in = policy_out = NULL;
456#endif
457
458        /*
459         * Do the stuff that we need root priv's for *first*, and
460         * then drop our setuid bit.  Save error reporting for
461         * after arg parsing.
462         */
463        s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
464        sockerrno = errno;
465
466        setuid(getuid());
467        uid = getuid();
468
469        alarmtimeout = df = preload = tos = 0;
470
471        outpack = outpackhdr + sizeof(struct ip);
472#ifdef __rtems__
473        memset(&getopt_reent, 0, sizeof(getopt_data));
474        while ((ch = getopt_r(argc, argv,
475#else
476        while ((ch = getopt(argc, argv,
477#endif
478                "Aac:DdfG:g:h:I:i:Ll:M:m:nop:QqRrS:s:T:t:vW:z:"
479#ifdef IPSEC
480#ifdef IPSEC_POLICY_IPSEC
481                "P:"
482#endif /*IPSEC_POLICY_IPSEC*/
483#endif /*IPSEC*/
484#ifdef __rtems__
485                , &getopt_reent
486#endif
487                )) != -1)
488        {
489                switch(ch) {
490                case 'A':
491                        options_ |= F_MISSED;
492                        break;
493                case 'a':
494                        options_ |= F_AUDIBLE;
495                        break;
496                case 'c':
497                        ultmp = strtoul(optarg, &ep, 0);
498                        if (*ep || ep == optarg || ultmp > LONG_MAX || !ultmp)
499                                errx(&globals->exit_jmp, EX_USAGE,
500                                    "invalid count of packets to transmit: `%s'",
501                                    optarg);
502                        npackets = ultmp;
503                        break;
504                case 'D':
505                        options_ |= F_HDRINCL;
506                        df = 1;
507                        break;
508                case 'd':
509                        options_ |= F_SO_DEBUG;
510                        break;
511                case 'f':
512                        if (uid) {
513                                errno = EPERM;
514                                err(&globals->exit_jmp, EX_NOPERM, "-f flag");
515                        }
516                        options_ |= F_FLOOD;
517                        setbuf(stdout, (char *)NULL);
518                        break;
519                case 'G': /* Maximum packet size for ping sweep */
520                        ultmp = strtoul(optarg, &ep, 0);
521                        if (*ep || ep == optarg)
522                                errx(&globals->exit_jmp, EX_USAGE, "invalid packet size: `%s'",
523                                    optarg);
524                        if (uid != 0 && ultmp > DEFDATALEN) {
525                                errno = EPERM;
526                                err(&globals->exit_jmp, EX_NOPERM,
527                                    "packet size too large: %lu > %u",
528                                    ultmp, DEFDATALEN);
529                        }
530                        options_ |= F_SWEEP;
531                        sweepmax = ultmp;
532                        break;
533                case 'g': /* Minimum packet size for ping sweep */
534                        ultmp = strtoul(optarg, &ep, 0);
535                        if (*ep || ep == optarg)
536                                errx(&globals->exit_jmp, EX_USAGE, "invalid packet size: `%s'",
537                                    optarg);
538                        if (uid != 0 && ultmp > DEFDATALEN) {
539                                errno = EPERM;
540                                err(&globals->exit_jmp, EX_NOPERM,
541                                    "packet size too large: %lu > %u",
542                                    ultmp, DEFDATALEN);
543                        }
544                        options_ |= F_SWEEP;
545                        sweepmin = ultmp;
546                        break;
547                case 'h': /* Packet size increment for ping sweep */
548                        ultmp = strtoul(optarg, &ep, 0);
549                        if (*ep || ep == optarg || ultmp < 1)
550                                errx(&globals->exit_jmp, EX_USAGE, "invalid increment size: `%s'",
551                                    optarg);
552                        if (uid != 0 && ultmp > DEFDATALEN) {
553                                errno = EPERM;
554                                err(&globals->exit_jmp, EX_NOPERM,
555                                    "packet size too large: %lu > %u",
556                                    ultmp, DEFDATALEN);
557                        }
558                        options_ |= F_SWEEP;
559                        sweepincr = ultmp;
560                        break;
561                case 'I':               /* multicast interface */
562                        if (inet_aton(optarg, &ifaddr) == 0)
563                                errx(&globals->exit_jmp, EX_USAGE,
564                                    "invalid multicast interface: `%s'",
565                                    optarg);
566                        options_ |= F_MIF;
567                        break;
568                case 'i':               /* wait between sending packets */
569                        t = strtod(optarg, &ep) * 1000.0;
570                        if (*ep || ep == optarg || t > (double)INT_MAX)
571                                errx(&globals->exit_jmp, EX_USAGE, "invalid timing interval: `%s'",
572                                    optarg);
573                        options_ |= F_INTERVAL;
574                        interval = (int)t;
575                        if (uid && interval < 1000) {
576                                errno = EPERM;
577                                err(&globals->exit_jmp, EX_NOPERM, "-i interval too short");
578                        }
579                        break;
580                case 'L':
581                        options_ |= F_NOLOOP;
582                        loop = 0;
583                        break;
584                case 'l':
585                        ultmp = strtoul(optarg, &ep, 0);
586                        if (*ep || ep == optarg || ultmp > INT_MAX)
587                                errx(&globals->exit_jmp, EX_USAGE,
588                                    "invalid preload value: `%s'", optarg);
589                        if (uid) {
590                                errno = EPERM;
591                                err(&globals->exit_jmp, EX_NOPERM, "-l flag");
592                        }
593                        preload = ultmp;
594                        break;
595                case 'M':
596                        switch(optarg[0]) {
597                        case 'M':
598                        case 'm':
599                                options_ |= F_MASK;
600                                break;
601                        case 'T':
602                        case 't':
603                                options_ |= F_TIME;
604                                break;
605                        default:
606                                errx(&globals->exit_jmp, EX_USAGE, "invalid message: `%c'", optarg[0]);
607                                break;
608                        }
609                        break;
610                case 'm':               /* TTL */
611                        ultmp = strtoul(optarg, &ep, 0);
612                        if (*ep || ep == optarg || ultmp > MAXTTL)
613                                errx(&globals->exit_jmp, EX_USAGE, "invalid TTL: `%s'", optarg);
614                        ttl = ultmp;
615                        options_ |= F_TTL;
616                        break;
617                case 'n':
618                        options_ |= F_NUMERIC;
619                        break;
620                case 'o':
621                        options_ |= F_ONCE;
622                        break;
623#ifdef IPSEC
624#ifdef IPSEC_POLICY_IPSEC
625                case 'P':
626                        options_ |= F_POLICY;
627                        if (!strncmp("in", optarg, 2))
628                                policy_in = strdup(optarg);
629                        else if (!strncmp("out", optarg, 3))
630                                policy_out = strdup(optarg);
631                        else
632                                errx(&globals->exit_jmp, 1, "invalid security policy");
633                        break;
634#endif /*IPSEC_POLICY_IPSEC*/
635#endif /*IPSEC*/
636                case 'p':               /* fill buffer with user pattern */
637                        options_ |= F_PINGFILLED;
638                        payload = optarg;
639                        break;
640                case 'Q':
641                        options_ |= F_QUIET2;
642                        break;
643                case 'q':
644                        options_ |= F_QUIET;
645                        break;
646                case 'R':
647                        options_ |= F_RROUTE;
648                        break;
649                case 'r':
650                        options_ |= F_SO_DONTROUTE;
651                        break;
652                case 'S':
653                        source = optarg;
654                        break;
655                case 's':               /* size of packet to send */
656                        ultmp = strtoul(optarg, &ep, 0);
657                        if (*ep || ep == optarg)
658                                errx(&globals->exit_jmp, EX_USAGE, "invalid packet size: `%s'",
659                                    optarg);
660                        if (uid != 0 && ultmp > DEFDATALEN) {
661                                errno = EPERM;
662                                err(&globals->exit_jmp, EX_NOPERM,
663                                    "packet size too large: %lu > %u",
664                                    ultmp, DEFDATALEN);
665                        }
666                        datalen = ultmp;
667                        break;
668                case 'T':               /* multicast TTL */
669                        ultmp = strtoul(optarg, &ep, 0);
670                        if (*ep || ep == optarg || ultmp > MAXTTL)
671                                errx(&globals->exit_jmp, EX_USAGE, "invalid multicast TTL: `%s'",
672                                    optarg);
673                        mttl = ultmp;
674                        options_ |= F_MTTL;
675                        break;
676                case 't':
677                        alarmtimeout = strtoul(optarg, &ep, 0);
678                        if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX))
679                                errx(&globals->exit_jmp, EX_USAGE, "invalid timeout: `%s'",
680                                    optarg);
681                        if (alarmtimeout > MAXALARM)
682                                errx(&globals->exit_jmp, EX_USAGE, "invalid timeout: `%s' > %d",
683                                    optarg, MAXALARM);
684                        alarm((int)alarmtimeout);
685                        break;
686                case 'v':
687                        options_ |= F_VERBOSE;
688                        break;
689                case 'W':               /* wait ms for answer */
690                        t = strtod(optarg, &ep);
691                        if (*ep || ep == optarg || t > (double)INT_MAX)
692                                errx(&globals->exit_jmp, EX_USAGE, "invalid timing interval: `%s'",
693                                    optarg);
694                        options_ |= F_WAITTIME;
695                        waittime = (int)t;
696                        break;
697                case 'z':
698                        options_ |= F_HDRINCL;
699                        ultmp = strtoul(optarg, &ep, 0);
700                        if (*ep || ep == optarg || ultmp > MAXTOS)
701                                errx(&globals->exit_jmp, EX_USAGE, "invalid TOS: `%s'", optarg);
702                        tos = ultmp;
703                        break;
704                default:
705                        usage();
706
707                }
708        }
709
710        if (argc - optind != 1)
711                usage();
712
713        target = argv[optind];
714
715        switch (options_ & (F_MASK|F_TIME)) {
716        case 0: break;
717        case F_MASK:
718                icmp_type_ = ICMP_MASKREQ;
719                icmp_type_rsp = ICMP_MASKREPLY;
720                phdr_len = MASK_LEN;
721                if (!(options_ & F_QUIET))
722                        (void)printf("ICMP_MASKREQ\n");
723                break;
724        case F_TIME:
725                icmp_type_ = ICMP_TSTAMP;
726                icmp_type_rsp = ICMP_TSTAMPREPLY;
727                phdr_len = TS_LEN;
728                if (!(options_ & F_QUIET))
729                        (void)printf("ICMP_TSTAMP\n");
730                break;
731        default:
732                errx(&globals->exit_jmp, EX_USAGE, "ICMP_TSTAMP and ICMP_MASKREQ are exclusive.");
733                break;
734        }
735        icmp_len = sizeof(struct ip) + ICMP_MINLEN + phdr_len;
736        if (options_ & F_RROUTE)
737                icmp_len += MAX_IPOPTLEN;
738        maxpayload = IP_MAXPACKET - icmp_len;
739        if (datalen > maxpayload)
740                errx(&globals->exit_jmp, EX_USAGE, "packet size too large: %d > %d", datalen,
741                    maxpayload);
742        send_len = icmp_len + datalen;
743        datap = &outpack[ICMP_MINLEN + phdr_len + TIMEVAL_LEN];
744        if (options_ & F_PINGFILLED) {
745                fill((char *)datap, payload);
746        }
747        if (source) {
748                bzero((char *)&sock_in, sizeof(sock_in));
749                sock_in.sin_family = AF_INET;
750                if (inet_aton(source, &sock_in.sin_addr) != 0) {
751                        shostname = source;
752                } else {
753                        hp = gethostbyname2(source, AF_INET);
754                        if (!hp)
755                                errx(&globals->exit_jmp, EX_NOHOST, "cannot resolve %s: %s",
756                                    source, hstrerror(h_errno));
757
758                        sock_in.sin_len = sizeof sock_in;
759                        if ((unsigned)hp->h_length > sizeof(sock_in.sin_addr) ||
760                            hp->h_length < 0)
761                                errx(&globals->exit_jmp, 1, "gethostbyname2: illegal address");
762                        memcpy(&sock_in.sin_addr, hp->h_addr_list[0],
763                            sizeof(sock_in.sin_addr));
764                        (void)strncpy(snamebuf, hp->h_name,
765                            sizeof(snamebuf) - 1);
766                        snamebuf[sizeof(snamebuf) - 1] = '\0';
767                        shostname = snamebuf;
768                }
769                if (bind(s, (struct sockaddr *)&sock_in, sizeof sock_in) == -1)
770                        err(&globals->exit_jmp, 1, "bind");
771        }
772
773        bzero(&whereto, sizeof(whereto));
774        to = &whereto;
775        to->sin_family = AF_INET;
776        to->sin_len = sizeof *to;
777        if (inet_aton(target, &to->sin_addr) != 0) {
778                hostname = target;
779        } else {
780                hp = gethostbyname2(target, AF_INET);
781                if (!hp)
782                        errx(&globals->exit_jmp, EX_NOHOST, "cannot resolve %s: %s",
783                            target, hstrerror(h_errno));
784
785                if ((unsigned)hp->h_length > sizeof(to->sin_addr))
786                        errx(&globals->exit_jmp, 1, "gethostbyname2 returned an illegal address");
787                memcpy(&to->sin_addr, hp->h_addr_list[0], sizeof to->sin_addr);
788                (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
789                hnamebuf[sizeof(hnamebuf) - 1] = '\0';
790                hostname = hnamebuf;
791        }
792
793        if (options_ & F_FLOOD && options_ & F_INTERVAL)
794                errx(&globals->exit_jmp, EX_USAGE, "-f and -i: incompatible options");
795
796        if (options_ & F_FLOOD && IN_MULTICAST(ntohl(to->sin_addr.s_addr)))
797                errx(&globals->exit_jmp, EX_USAGE,
798                    "-f flag cannot be used with multicast destination");
799        if (options_ & (F_MIF | F_NOLOOP | F_MTTL)
800            && !IN_MULTICAST(ntohl(to->sin_addr.s_addr)))
801                errx(&globals->exit_jmp, EX_USAGE,
802                    "-I, -L, -T flags cannot be used with unicast destination");
803
804        if (datalen >= TIMEVAL_LEN)     /* can we time transfer */
805                timing = 1;
806
807        if (!(options_ & F_PINGFILLED))
808                for (i = TIMEVAL_LEN; i < datalen; ++i)
809                        *datap++ = i;
810
811        ident = getpid() & 0xFFFF;
812
813        if (s < 0) {
814                errno = sockerrno;
815                err(&globals->exit_jmp, EX_OSERR, "socket");
816        }
817        hold = 1;
818        if (options_ & F_SO_DEBUG)
819                (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
820                    sizeof(hold));
821        if (options_ & F_SO_DONTROUTE)
822                (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
823                    sizeof(hold));
824#ifdef IPSEC
825#ifdef IPSEC_POLICY_IPSEC
826        if (options_ & F_POLICY) {
827                char *buf;
828                if (policy_in != NULL) {
829                        buf = ipsec_set_policy(policy_in, strlen(policy_in));
830                        if (buf == NULL)
831                                errx(&globals->exit_jmp, EX_CONFIG, "%s", ipsec_strerror());
832                        if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
833                                        buf, ipsec_get_policylen(buf)) < 0)
834                                err(EX_CONFIG,
835                                    "ipsec policy cannot be configured");
836                        free(buf);
837                }
838
839                if (policy_out != NULL) {
840                        buf = ipsec_set_policy(policy_out, strlen(policy_out));
841                        if (buf == NULL)
842                                errx(&globals->exit_jmp, EX_CONFIG, "%s", ipsec_strerror());
843                        if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
844                                        buf, ipsec_get_policylen(buf)) < 0)
845                                err(EX_CONFIG,
846                                    "ipsec policy cannot be configured");
847                        free(buf);
848                }
849        }
850#endif /*IPSEC_POLICY_IPSEC*/
851#endif /*IPSEC*/
852
853        if (options_ & F_HDRINCL) {
854                ip = (struct ip*)outpackhdr;
855                if (!(options_ & (F_TTL | F_MTTL))) {
856                        mib[0] = CTL_NET;
857                        mib[1] = PF_INET;
858                        mib[2] = IPPROTO_IP;
859                        mib[3] = IPCTL_DEFTTL;
860                        sz = sizeof(ttl);
861                        if (sysctl(mib, 4, &ttl, &sz, NULL, 0) == -1)
862                                err(&globals->exit_jmp, 1, "sysctl(net.inet.ip.ttl)");
863                }
864                setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold));
865                ip->ip_v = IPVERSION;
866                ip->ip_hl = sizeof(struct ip) >> 2;
867                ip->ip_tos = tos;
868                ip->ip_id = 0;
869                ip->ip_off = df ? IP_DF : 0;
870                ip->ip_ttl = ttl;
871                ip->ip_p = IPPROTO_ICMP;
872                ip->ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY;
873                ip->ip_dst = to->sin_addr;
874        }
875        /* record route option */
876        if (options_ & F_RROUTE) {
877#ifdef IP_OPTIONS
878                bzero(rspace, sizeof(rspace));
879                rspace[IPOPT_OPTVAL] = IPOPT_RR;
880                rspace[IPOPT_OLEN] = sizeof(rspace) - 1;
881                rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
882                rspace[sizeof(rspace) - 1] = IPOPT_EOL;
883                if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
884                    sizeof(rspace)) < 0)
885                        err(&globals->exit_jmp, EX_OSERR, "setsockopt IP_OPTIONS");
886#else
887                errx(&globals->exit_jmp, EX_UNAVAILABLE,
888                    "record route not available in this implementation");
889#endif /* IP_OPTIONS */
890        }
891
892        if (options_ & F_TTL) {
893                if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl,
894                    sizeof(ttl)) < 0) {
895                        err(&globals->exit_jmp, EX_OSERR, "setsockopt IP_TTL");
896                }
897        }
898        if (options_ & F_NOLOOP) {
899                if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop,
900                    sizeof(loop)) < 0) {
901                        err(&globals->exit_jmp, EX_OSERR, "setsockopt IP_MULTICAST_LOOP");
902                }
903        }
904        if (options_ & F_MTTL) {
905                if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &mttl,
906                    sizeof(mttl)) < 0) {
907                        err(&globals->exit_jmp, EX_OSERR, "setsockopt IP_MULTICAST_TTL");
908                }
909        }
910        if (options_ & F_MIF) {
911                if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr,
912                    sizeof(ifaddr)) < 0) {
913                        err(&globals->exit_jmp, EX_OSERR, "setsockopt IP_MULTICAST_IF");
914                }
915        }
916#ifdef SO_TIMESTAMP
917        { int on = 1;
918        if (setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0)
919                err(&globals->exit_jmp, EX_OSERR, "setsockopt SO_TIMESTAMP");
920        }
921#endif
922        if (sweepmax) {
923                if (sweepmin >= sweepmax)
924                        errx(&globals->exit_jmp, EX_USAGE, "Maximum packet size must be greater than the minimum packet size");
925
926                if (datalen != DEFDATALEN)
927                        errx(&globals->exit_jmp, EX_USAGE, "Packet size and ping sweep are mutually exclusive");
928
929                if (npackets > 0) {
930                        snpackets = npackets;
931                        npackets = 0;
932                } else
933                        snpackets = 1;
934                datalen = sweepmin;
935                send_len = icmp_len + sweepmin;
936        }
937        if (options_ & F_SWEEP && !sweepmax)
938                errx(&globals->exit_jmp, EX_USAGE, "Maximum sweep size must be specified");
939
940        /*
941         * When pinging the broadcast address, you can get a lot of answers.
942         * Doing something so evil is useful if you are trying to stress the
943         * ethernet, or just want to fill the arp cache to get some stuff for
944         * /etc/ethers.  But beware: RFC 1122 allows hosts to ignore broadcast
945         * or multicast pings if they wish.
946         */
947
948        /*
949         * XXX receive buffer needs undetermined space for mbuf overhead
950         * as well.
951         */
952        hold = IP_MAXPACKET + 128;
953        (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
954            sizeof(hold));
955        if (uid == 0)
956                (void)setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&hold,
957                    sizeof(hold));
958
959        if (to->sin_family == AF_INET) {
960                (void)printf("PING %s (%s)", hostname,
961                    inet_ntoa(to->sin_addr));
962                if (source)
963                        (void)printf(" from %s", shostname);
964                if (sweepmax)
965                        (void)printf(": (%d ... %d) data bytes\n",
966                            sweepmin, sweepmax);
967                else
968                        (void)printf(": %d data bytes\n", datalen);
969
970        } else {
971                if (sweepmax)
972                        (void)printf("PING %s: (%d ... %d) data bytes\n",
973                            hostname, sweepmin, sweepmax);
974                else
975                        (void)printf("PING %s: %d data bytes\n", hostname, datalen);
976        }
977
978        /*
979         * Use sigaction() instead of signal() to get unambiguous semantics,
980         * in particular with SA_RESTART not set.
981         */
982
983        sigemptyset(&si_sa.sa_mask);
984        si_sa.sa_flags = 0;
985
986        si_sa.sa_handler = stopit;
987        if (sigaction(SIGINT, &si_sa, 0) == -1) {
988                err(&globals->exit_jmp, EX_OSERR, "sigaction SIGINT");
989        }
990
991#ifdef SIGINFO
992        si_sa.sa_handler = status;
993        if (sigaction(SIGINFO, &si_sa, 0) == -1) {
994                err(EX_OSERR, "sigaction");
995        }
996#endif
997
998        if (alarmtimeout > 0) {
999                si_sa.sa_handler = stopit;
1000                if (sigaction(SIGALRM, &si_sa, 0) == -1)
1001                        err(&globals->exit_jmp, EX_OSERR, "sigaction SIGALRM");
1002        }
1003
1004        bzero(&msg, sizeof(msg));
1005        msg.msg_name = (caddr_t)&from;
1006        msg.msg_iov = &iov;
1007        msg.msg_iovlen = 1;
1008#ifdef SO_TIMESTAMP
1009        msg.msg_control = (caddr_t)ctrl;
1010#endif
1011        iov.iov_base = packet_;
1012        iov.iov_len = IP_MAXPACKET;
1013
1014        if (preload == 0)
1015                pinger();               /* send the first ping */
1016        else {
1017                if (npackets != 0 && preload > npackets)
1018                        preload = npackets;
1019                while (preload--)       /* fire off them quickies */
1020                        pinger();
1021        }
1022        (void)gettimeofday(&last, NULL);
1023
1024        if (options_ & F_FLOOD) {
1025                intvl.tv_sec = 0;
1026                intvl.tv_usec = 10000;
1027        } else {
1028                intvl.tv_sec = interval / 1000;
1029                intvl.tv_usec = interval % 1000 * 1000;
1030        }
1031
1032        almost_done = 0;
1033        while (!finish_up) {
1034                struct timeval now, timeout;
1035                fd_set rfds;
1036                int cc, n;
1037
1038                check_status();
1039                if ((unsigned)s >= FD_SETSIZE)
1040                        errx(&globals->exit_jmp, EX_OSERR, "descriptor too large");
1041                FD_ZERO(&rfds);
1042                FD_SET(s, &rfds);
1043                (void)gettimeofday(&now, NULL);
1044                timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
1045                timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
1046                while (timeout.tv_usec < 0) {
1047                        timeout.tv_usec += 1000000;
1048                        timeout.tv_sec--;
1049                }
1050                while (timeout.tv_usec >= 1000000) {
1051                        timeout.tv_usec -= 1000000;
1052                        timeout.tv_sec++;
1053                }
1054                if (timeout.tv_sec < 0)
1055                        timeout.tv_sec = timeout.tv_usec = 0;
1056                n = select(s + 1, &rfds, NULL, NULL, &timeout);
1057                if (n < 0)
1058                        continue;       /* Must be EINTR. */
1059                if (n == 1) {
1060                        struct timeval *tv = NULL;
1061#ifdef SO_TIMESTAMP
1062                        struct cmsghdr *cmsg = (struct cmsghdr *)&ctrl;
1063
1064                        msg.msg_controllen = sizeof(ctrl);
1065#endif
1066
1067        bzero(&msg, sizeof(msg));
1068        msg.msg_name = (caddr_t)&from;
1069        msg.msg_iov = &iov;
1070        msg.msg_iovlen = 1;
1071#ifdef SO_TIMESTAMP
1072        msg.msg_control = (caddr_t)ctrl;
1073#endif
1074        iov.iov_base = packet_;
1075        iov.iov_len = IP_MAXPACKET;
1076
1077                        msg.msg_namelen = sizeof(from);
1078                        if ((cc = recvmsg(s, &msg, 0)) < 0) {
1079                                if (errno == EINTR)
1080                                        continue;
1081                                warn("recvmsg");
1082                                continue;
1083                        }
1084#ifdef SO_TIMESTAMP
1085                        if (cmsg->cmsg_level == SOL_SOCKET &&
1086                            cmsg->cmsg_type == SCM_TIMESTAMP &&
1087                            cmsg->cmsg_len == CMSG_LEN(sizeof *tv)) {
1088                                /* Copy to avoid alignment problems: */
1089                                memcpy(&now, CMSG_DATA(cmsg), sizeof(now));
1090                                tv = &now;
1091                        }
1092#endif
1093                        if (tv == NULL) {
1094                                (void)gettimeofday(&now, NULL);
1095                                tv = &now;
1096                        }
1097                        pr_pack((char *)packet_, cc, &from, tv);
1098                        if ((options_ & F_ONCE && nreceived) ||
1099                            (npackets && nreceived >= npackets))
1100                                break;
1101                }
1102                if (n == 0 || options_ & F_FLOOD) {
1103                        if (sweepmax && sntransmitted == snpackets) {
1104                                for (i = 0; i < sweepincr ; ++i)
1105                                        *datap++ = i;
1106                                datalen += sweepincr;
1107                                if (datalen > sweepmax)
1108                                        break;
1109                                send_len = icmp_len + datalen;
1110                                sntransmitted = 0;
1111                        }
1112                        if (!npackets || ntransmitted < npackets)
1113                                pinger();
1114                        else {
1115                                if (almost_done)
1116                                        break;
1117                                almost_done = 1;
1118                                intvl.tv_usec = 0;
1119                                if (nreceived) {
1120                                        intvl.tv_sec = 2 * tmax / 1000;
1121                                        if (!intvl.tv_sec)
1122                                                intvl.tv_sec = 1;
1123                                } else {
1124                                        intvl.tv_sec = waittime / 1000;
1125                                        intvl.tv_usec = waittime % 1000 * 1000;
1126                                }
1127                        }
1128                        (void)gettimeofday(&last, NULL);
1129                        if (ntransmitted - nreceived - 1 > nmissedmax) {
1130                                nmissedmax = ntransmitted - nreceived - 1;
1131                                if (options_ & F_MISSED)
1132                                        (void)write(STDOUT_FILENO, &BBELL, 1);
1133                        }
1134                }
1135        }
1136        finish();
1137#ifdef __rtems__
1138        /* RTEMS shell programs return -- they do not exit */
1139        if (nreceived)
1140                return(0);
1141        else
1142                return(2);
1143#endif
1144        /* NOTREACHED */
1145        exit(0);        /* Make the compiler happy */
1146}
1147
1148/*
1149 * stopit --
1150 *      Set the global bit that causes the main loop to quit.
1151 * Do NOT call finish() from here, since finish() does far too much
1152 * to be called from a signal handler.
1153 */
1154void
1155stopit(sig)
1156        int sig __unused;
1157{
1158#if !__rtems__
1159        /*
1160         * When doing reverse DNS lookups, the finish_up flag might not
1161         * be noticed for a while.  Just exit if we get a second SIGINT.
1162         */
1163        if (!(options_ & F_NUMERIC) && finish_up)
1164                _exit(nreceived ? 0 : 2);
1165        finish_up = 1;
1166#endif
1167}
1168
1169/*
1170 * pinger --
1171 *      Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
1172 * will be added on by the kernel.  The ID field is our UNIX process ID,
1173 * and the sequence number is an ascending integer.  The first TIMEVAL_LEN
1174 * bytes of the data portion are used to hold a UNIX "timeval" struct in
1175 * host byte-order, to compute the round-trip time.
1176 */
1177static void
1178g_pinger(globals)
1179  rtems_shell_globals_t* globals;
1180{
1181        struct timeval now;
1182        struct tv32 tv32;
1183        struct ip *ip;
1184        struct icmp *icp;
1185        int cc, i;
1186        u_char *packet;
1187
1188        packet = outpack;
1189        icp = (struct icmp *)outpack;
1190        icp->icmp_type = icmp_type_;
1191        icp->icmp_code = 0;
1192        icp->icmp_cksum = 0;
1193        icp->icmp_seq = htons(ntransmitted);
1194        icp->icmp_id = ident;                   /* ID */
1195
1196        CLR(ntransmitted % mx_dup_ck);
1197
1198        if ((options_ & F_TIME) || timing) {
1199                (void)gettimeofday(&now, NULL);
1200
1201                tv32.tv32_sec = htonl(now.tv_sec);
1202                tv32.tv32_usec = htonl(now.tv_usec);
1203                if (options_ & F_TIME)
1204                        icp->icmp_otime = htonl((now.tv_sec % (24*60*60))
1205                                * 1000 + now.tv_usec / 1000);
1206                if (timing)
1207                        bcopy((void *)&tv32,
1208                            (void *)&outpack[ICMP_MINLEN + phdr_len],
1209                            sizeof(tv32));
1210        }
1211
1212        cc = ICMP_MINLEN + phdr_len + datalen;
1213
1214        /* compute ICMP checksum here */
1215        icp->icmp_cksum = in_cksum((u_short *)icp, cc);
1216
1217        if (options_ & F_HDRINCL) {
1218                cc += sizeof(struct ip);
1219                ip = (struct ip *)outpackhdr;
1220                ip->ip_len = cc;
1221                ip->ip_sum = in_cksum((u_short *)outpackhdr, cc);
1222                packet = outpackhdr;
1223        }
1224        i = sendto(s, (char *)packet, cc, 0, (struct sockaddr *)&whereto,
1225            sizeof(whereto));
1226
1227        if (i < 0 || i != cc)  {
1228                if (i < 0) {
1229                        if (options_ & F_FLOOD && errno == ENOBUFS) {
1230                                usleep(FLOOD_BACKOFF);
1231                                return;
1232                        }
1233                        warn("sendto");
1234                } else {
1235                        warn("%s: partial write: %d of %d bytes",
1236                             hostname, i, cc);
1237                }
1238        }
1239        ntransmitted++;
1240        sntransmitted++;
1241        if (!(options_ & F_QUIET) && options_ & F_FLOOD)
1242                (void)write(STDOUT_FILENO, &DOT, 1);
1243}
1244
1245/*
1246 * pr_pack --
1247 *      Print out the packet, if it came from us.  This logic is necessary
1248 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
1249 * which arrive ('tis only fair).  This permits multiple copies of this
1250 * program to be run without having intermingled output (or statistics!).
1251 */
1252static void
1253g_pr_pack(buf, cc, from, tv, globals)
1254        char *buf;
1255        int cc;
1256        struct sockaddr_in *from;
1257        struct timeval *tv;
1258  rtems_shell_globals_t* globals;
1259{
1260        struct in_addr ina;
1261        u_char *cp, *dp;
1262        struct icmp *icp;
1263        struct ip *ip;
1264        const void *tp;
1265        double triptime;
1266        int dupflag, hlen, i, j, recv_len, seq;
1267#if !__rtems__
1268        static int old_rrlen;
1269        static char old_rr[MAX_IPOPTLEN];
1270#endif
1271
1272        /* Check the IP header */
1273        ip = (struct ip *)buf;
1274        hlen = ip->ip_hl << 2;
1275        recv_len = cc;
1276        if (cc < hlen + ICMP_MINLEN) {
1277                if (options_ & F_VERBOSE)
1278                        warn("packet too short (%d bytes) from %s", cc,
1279                             inet_ntoa(from->sin_addr));
1280                return;
1281        }
1282
1283        /* Now the ICMP part */
1284        cc -= hlen;
1285        icp = (struct icmp *)(buf + hlen);
1286        if (icp->icmp_type == icmp_type_rsp) {
1287                if (icp->icmp_id != ident)
1288                        return;                 /* 'Twas not our ECHO */
1289                ++nreceived;
1290                triptime = 0.0;
1291                if (timing) {
1292                        struct timeval tv1;
1293                        struct tv32 tv32;
1294#ifndef icmp_data
1295                        tp = &icp->icmp_ip;
1296#else
1297                        tp = icp->icmp_data;
1298#endif
1299                        tp = (const char *)tp + phdr_len;
1300
1301                        if (cc - ICMP_MINLEN - phdr_len >= (int) sizeof(tv1)) {
1302                                /* Copy to avoid alignment problems: */
1303                                memcpy(&tv32, tp, sizeof(tv32));
1304                                tv1.tv_sec = ntohl(tv32.tv32_sec);
1305                                tv1.tv_usec = ntohl(tv32.tv32_usec);
1306                                tvsub(tv, &tv1);
1307                                triptime = ((double)tv->tv_sec) * 1000.0 +
1308                                    ((double)tv->tv_usec) / 1000.0;
1309                                tsum += triptime;
1310                                tsumsq += triptime * triptime;
1311                                if (triptime < tmin)
1312                                        tmin = triptime;
1313                                if (triptime > tmax)
1314                                        tmax = triptime;
1315                        } else
1316                                timing = 0;
1317                }
1318
1319                seq = ntohs(icp->icmp_seq);
1320
1321                if (TST(seq % mx_dup_ck)) {
1322                        ++nrepeats;
1323                        --nreceived;
1324                        dupflag = 1;
1325                } else {
1326                        SET(seq % mx_dup_ck);
1327                        dupflag = 0;
1328                }
1329
1330                if (options_ & F_QUIET)
1331                        return;
1332
1333                if (options_ & F_WAITTIME && triptime > waittime) {
1334                        ++nrcvtimeout;
1335                        return;
1336                }
1337
1338                if (options_ & F_FLOOD)
1339                        (void)write(STDOUT_FILENO, &BSPACE, 1);
1340                else {
1341                        (void)printf("%d bytes from %s: icmp_seq=%u", cc,
1342                           inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
1343                           seq);
1344                        (void)printf(" ttl=%d", ip->ip_ttl);
1345                        if (timing)
1346                                (void)printf(" time=%.3f ms", triptime);
1347                        if (dupflag)
1348                                (void)printf(" (DUP!)");
1349                        if (options_ & F_AUDIBLE)
1350                                (void)write(STDOUT_FILENO, &BBELL, 1);
1351                        if (options_ & F_MASK) {
1352                                /* Just prentend this cast isn't ugly */
1353                                (void)printf(" mask=%s",
1354                                        pr_addr(*(struct in_addr *)&(icp->icmp_mask)));
1355                        }
1356                        if (options_ & F_TIME) {
1357                                (void)printf(" tso=%s", pr_ntime(icp->icmp_otime));
1358                                (void)printf(" tsr=%s", pr_ntime(icp->icmp_rtime));
1359                                (void)printf(" tst=%s", pr_ntime(icp->icmp_ttime));
1360                        }
1361                        if (recv_len != send_len) {
1362                                (void)printf(
1363                                     "\nwrong total length %d instead of %d",
1364                                     recv_len, send_len);
1365                        }
1366                        /* check the data */
1367                        cp = (u_char*)&icp->icmp_data[phdr_len];
1368                        dp = &outpack[ICMP_MINLEN + phdr_len];
1369                        cc -= ICMP_MINLEN + phdr_len;
1370                        i = 0;
1371                        if (timing) {   /* don't check variable timestamp */
1372                                cp += TIMEVAL_LEN;
1373                                dp += TIMEVAL_LEN;
1374                                cc -= TIMEVAL_LEN;
1375                                i += TIMEVAL_LEN;
1376                        }
1377                        for (; i < datalen && cc > 0; ++i, ++cp, ++dp, --cc) {
1378                                if (*cp != *dp) {
1379        (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
1380            i, *dp, *cp);
1381                                        (void)printf("\ncp:");
1382                                        cp = (u_char*)&icp->icmp_data[0];
1383                                        for (i = 0; i < datalen; ++i, ++cp) {
1384                                                if ((i % 16) == 8)
1385                                                        (void)printf("\n\t");
1386                                                (void)printf("%2x ", *cp);
1387                                        }
1388                                        (void)printf("\ndp:");
1389                                        cp = &outpack[ICMP_MINLEN];
1390                                        for (i = 0; i < datalen; ++i, ++cp) {
1391                                                if ((i % 16) == 8)
1392                                                        (void)printf("\n\t");
1393                                                (void)printf("%2x ", *cp);
1394                                        }
1395                                        break;
1396                                }
1397                        }
1398                }
1399        } else {
1400                /*
1401                 * We've got something other than an ECHOREPLY.
1402                 * See if it's a reply to something that we sent.
1403                 * We can compare IP destination, protocol,
1404                 * and ICMP type and ID.
1405                 *
1406                 * Only print all the error messages if we are running
1407                 * as root to avoid leaking information not normally
1408                 * available to those not running as root.
1409                 */
1410#ifndef icmp_data
1411                struct ip *oip = &icp->icmp_ip;
1412#else
1413                struct ip *oip = (struct ip *)icp->icmp_data;
1414#endif
1415                struct icmp *oicmp = (struct icmp *)(oip + 1);
1416
1417                if (((options_ & F_VERBOSE) && uid == 0) ||
1418                    (!(options_ & F_QUIET2) &&
1419                     (oip->ip_dst.s_addr == whereto.sin_addr.s_addr) &&
1420                     (oip->ip_p == IPPROTO_ICMP) &&
1421                     (oicmp->icmp_type == ICMP_ECHO) &&
1422                     (oicmp->icmp_id == ident))) {
1423                    (void)printf("%d bytes from %s: ", cc,
1424                        pr_addr(from->sin_addr));
1425                    pr_icmph(icp);
1426                } else
1427                    return;
1428        }
1429
1430        /* Display any IP options */
1431        cp = (u_char *)buf + sizeof(struct ip);
1432
1433        for (; hlen > (int)sizeof(struct ip); --hlen, ++cp)
1434                switch (*cp) {
1435                case IPOPT_EOL:
1436                        hlen = 0;
1437                        break;
1438                case IPOPT_LSRR:
1439                case IPOPT_SSRR:
1440                        (void)printf(*cp == IPOPT_LSRR ?
1441                            "\nLSRR: " : "\nSSRR: ");
1442                        j = cp[IPOPT_OLEN] - IPOPT_MINOFF + 1;
1443                        hlen -= 2;
1444                        cp += 2;
1445                        if (j >= INADDR_LEN &&
1446                            j <= hlen - (int)sizeof(struct ip)) {
1447                                for (;;) {
1448                                        bcopy(++cp, &ina.s_addr, INADDR_LEN);
1449                                        if (ina.s_addr == 0)
1450                                                (void)printf("\t0.0.0.0");
1451                                        else
1452                                                (void)printf("\t%s",
1453                                                     pr_addr(ina));
1454                                        hlen -= INADDR_LEN;
1455                                        cp += INADDR_LEN - 1;
1456                                        j -= INADDR_LEN;
1457                                        if (j < INADDR_LEN)
1458                                                break;
1459                                        (void)putchar('\n');
1460                                }
1461                        } else
1462                                (void)printf("\t(truncated route)\n");
1463                        break;
1464                case IPOPT_RR:
1465                        j = cp[IPOPT_OLEN];             /* get length */
1466                        i = cp[IPOPT_OFFSET];           /* and pointer */
1467                        hlen -= 2;
1468                        cp += 2;
1469                        if (i > j)
1470                                i = j;
1471                        i = i - IPOPT_MINOFF + 1;
1472                        if (i < 0 || i > (hlen - (int)sizeof(struct ip))) {
1473                                old_rrlen = 0;
1474                                continue;
1475                        }
1476                        if (i == old_rrlen
1477                            && !bcmp((char *)cp, old_rr, i)
1478                            && !(options_ & F_FLOOD)) {
1479                                (void)printf("\t(same route)");
1480                                hlen -= i;
1481                                cp += i;
1482                                break;
1483                        }
1484                        old_rrlen = i;
1485                        bcopy((char *)cp, old_rr, i);
1486                        (void)printf("\nRR: ");
1487                        if (i >= INADDR_LEN &&
1488                            i <= hlen - (int)sizeof(struct ip)) {
1489                                for (;;) {
1490                                        bcopy(++cp, &ina.s_addr, INADDR_LEN);
1491                                        if (ina.s_addr == 0)
1492                                                (void)printf("\t0.0.0.0");
1493                                        else
1494                                                (void)printf("\t%s",
1495                                                     pr_addr(ina));
1496                                        hlen -= INADDR_LEN;
1497                                        cp += INADDR_LEN - 1;
1498                                        i -= INADDR_LEN;
1499                                        if (i < INADDR_LEN)
1500                                                break;
1501                                        (void)putchar('\n');
1502                                }
1503                        } else
1504                                (void)printf("\t(truncated route)");
1505                        break;
1506                case IPOPT_NOP:
1507                        (void)printf("\nNOP");
1508                        break;
1509                default:
1510                        (void)printf("\nunknown option %x", *cp);
1511                        break;
1512                }
1513        if (!(options_ & F_FLOOD)) {
1514                (void)putchar('\n');
1515                (void)fflush(stdout);
1516        }
1517}
1518
1519/*
1520 * in_cksum --
1521 *      Checksum routine for Internet Protocol family headers (C Version)
1522 */
1523u_short
1524in_cksum(addr, len)
1525        u_short *addr;
1526        int len;
1527{
1528        int nleft, sum;
1529        u_short *w;
1530        union {
1531                u_short us;
1532                u_char  uc[2];
1533        } last;
1534        u_short answer;
1535
1536        nleft = len;
1537        sum = 0;
1538        w = addr;
1539
1540        /*
1541         * Our algorithm is simple, using a 32 bit accumulator (sum), we add
1542         * sequential 16 bit words to it, and at the end, fold back all the
1543         * carry bits from the top 16 bits into the lower 16 bits.
1544         */
1545        while (nleft > 1)  {
1546                sum += *w++;
1547                nleft -= 2;
1548        }
1549
1550        /* mop up an odd byte, if necessary */
1551        if (nleft == 1) {
1552                last.uc[0] = *(u_char *)w;
1553                last.uc[1] = 0;
1554                sum += last.us;
1555        }
1556
1557        /* add back carry outs from top 16 bits to low 16 bits */
1558        sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
1559        sum += (sum >> 16);                     /* add carry */
1560        answer = ~sum;                          /* truncate to 16 bits */
1561        return(answer);
1562}
1563
1564/*
1565 * tvsub --
1566 *      Subtract 2 timeval structs:  out = out - in.  Out is assumed to
1567 * be >= in.
1568 */
1569static void
1570tvsub(out, in)
1571        struct timeval *out, *in;
1572{
1573
1574        if ((out->tv_usec -= in->tv_usec) < 0) {
1575                --out->tv_sec;
1576                out->tv_usec += 1000000;
1577        }
1578        out->tv_sec -= in->tv_sec;
1579}
1580
1581/*
1582 * status --
1583 *      Print out statistics when SIGINFO is received.
1584 */
1585
1586#if !defined(__rtems__)
1587static void
1588status(sig)
1589        int sig __unused;
1590{
1591        siginfo_p = 1;
1592}
1593#endif
1594
1595static void
1596g_check_status(globals)
1597  rtems_shell_globals_t* globals;
1598{
1599        if (siginfo_p) {
1600                siginfo_p = 0;
1601                (void)fprintf(stderr, "\r%ld/%ld packets received (%.1f%%)",
1602                    nreceived, ntransmitted,
1603                    ntransmitted ? nreceived * 100.0 / ntransmitted : 0.0);
1604                if (nreceived && timing)
1605                        (void)fprintf(stderr, " %.3f min / %.3f avg / %.3f max",
1606                            tmin, tsum / (nreceived + nrepeats), tmax);
1607                (void)fprintf(stderr, "\n");
1608        }
1609}
1610
1611/*
1612 * finish --
1613 *      Print out statistics, and give up.
1614 */
1615static void
1616g_finish(globals)
1617  rtems_shell_globals_t* globals;
1618{
1619
1620        (void)signal(SIGINT, SIG_IGN);
1621        (void)signal(SIGALRM, SIG_IGN);
1622        (void)putchar('\n');
1623        (void)fflush(stdout);
1624        (void)printf("--- %s ping statistics ---\n", hostname);
1625        (void)printf("%ld packets transmitted, ", ntransmitted);
1626        (void)printf("%ld packets received, ", nreceived);
1627        if (nrepeats)
1628                (void)printf("+%ld duplicates, ", nrepeats);
1629        if (ntransmitted) {
1630                if (nreceived > ntransmitted)
1631                        (void)printf("-- somebody's printing up packets!");
1632                else
1633                        (void)printf("%.1f%% packet loss",
1634                            ((ntransmitted - nreceived) * 100.0) /
1635                            ntransmitted);
1636        }
1637        if (nrcvtimeout)
1638                (void)printf(", %ld packets out of wait time", nrcvtimeout);
1639        (void)putchar('\n');
1640        if (nreceived && timing) {
1641                double n = nreceived + nrepeats;
1642                double avg = tsum / n;
1643#if defined(__rtems__)
1644                (void) printf(
1645                    "round-trip min/avg/max/stddev = %.3f/%.3f/%.3f ms\n",
1646                    tmin, avg, tmax);
1647#else
1648                double vari = tsumsq / n - avg * avg;
1649                (void)printf(
1650                    "round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms\n",
1651                    tmin, avg, tmax, sqrt(vari));
1652#endif
1653        }
1654        if (nreceived)
1655                exit(0);
1656        else
1657                exit(2);
1658  while (1);
1659}
1660
1661#ifdef notdef
1662static char *ttab[] = {
1663        "Echo Reply",           /* ip + seq + udata */
1664        "Dest Unreachable",     /* net, host, proto, port, frag, sr + IP */
1665        "Source Quench",        /* IP */
1666        "Redirect",             /* redirect type, gateway, + IP  */
1667        "Echo",
1668        "Time Exceeded",        /* transit, frag reassem + IP */
1669        "Parameter Problem",    /* pointer + IP */
1670        "Timestamp",            /* id + seq + three timestamps */
1671        "Timestamp Reply",      /* " */
1672        "Info Request",         /* id + sq */
1673        "Info Reply"            /* " */
1674};
1675#endif
1676
1677/*
1678 * pr_icmph --
1679 *      Print a descriptive string about an ICMP header.
1680 */
1681static void
1682pr_icmph(icp)
1683        struct icmp *icp;
1684{
1685
1686        switch(icp->icmp_type) {
1687        case ICMP_ECHOREPLY:
1688                (void)printf("Echo Reply\n");
1689                /* XXX ID + Seq + Data */
1690                break;
1691        case ICMP_UNREACH:
1692                switch(icp->icmp_code) {
1693                case ICMP_UNREACH_NET:
1694                        (void)printf("Destination Net Unreachable\n");
1695                        break;
1696                case ICMP_UNREACH_HOST:
1697                        (void)printf("Destination Host Unreachable\n");
1698                        break;
1699                case ICMP_UNREACH_PROTOCOL:
1700                        (void)printf("Destination Protocol Unreachable\n");
1701                        break;
1702                case ICMP_UNREACH_PORT:
1703                        (void)printf("Destination Port Unreachable\n");
1704                        break;
1705                case ICMP_UNREACH_NEEDFRAG:
1706                        (void)printf("frag needed and DF set (MTU %d)\n",
1707                                        ntohs(icp->icmp_nextmtu));
1708                        break;
1709                case ICMP_UNREACH_SRCFAIL:
1710                        (void)printf("Source Route Failed\n");
1711                        break;
1712                case ICMP_UNREACH_FILTER_PROHIB:
1713                        (void)printf("Communication prohibited by filter\n");
1714                        break;
1715                default:
1716                        (void)printf("Dest Unreachable, Bad Code: %d\n",
1717                            icp->icmp_code);
1718                        break;
1719                }
1720                /* Print returned IP header information */
1721#ifndef icmp_data
1722                pr_retip(&icp->icmp_ip);
1723#else
1724                pr_retip((struct ip *)icp->icmp_data);
1725#endif
1726                break;
1727        case ICMP_SOURCEQUENCH:
1728                (void)printf("Source Quench\n");
1729#ifndef icmp_data
1730                pr_retip(&icp->icmp_ip);
1731#else
1732                pr_retip((struct ip *)icp->icmp_data);
1733#endif
1734                break;
1735        case ICMP_REDIRECT:
1736                switch(icp->icmp_code) {
1737                case ICMP_REDIRECT_NET:
1738                        (void)printf("Redirect Network");
1739                        break;
1740                case ICMP_REDIRECT_HOST:
1741                        (void)printf("Redirect Host");
1742                        break;
1743                case ICMP_REDIRECT_TOSNET:
1744                        (void)printf("Redirect Type of Service and Network");
1745                        break;
1746                case ICMP_REDIRECT_TOSHOST:
1747                        (void)printf("Redirect Type of Service and Host");
1748                        break;
1749                default:
1750                        (void)printf("Redirect, Bad Code: %d", icp->icmp_code);
1751                        break;
1752                }
1753                (void)printf("(New addr: %s)\n", inet_ntoa(icp->icmp_gwaddr));
1754#ifndef icmp_data
1755                pr_retip(&icp->icmp_ip);
1756#else
1757                pr_retip((struct ip *)icp->icmp_data);
1758#endif
1759                break;
1760        case ICMP_ECHO:
1761                (void)printf("Echo Request\n");
1762                /* XXX ID + Seq + Data */
1763                break;
1764        case ICMP_TIMXCEED:
1765                switch(icp->icmp_code) {
1766                case ICMP_TIMXCEED_INTRANS:
1767                        (void)printf("Time to live exceeded\n");
1768                        break;
1769                case ICMP_TIMXCEED_REASS:
1770                        (void)printf("Frag reassembly time exceeded\n");
1771                        break;
1772                default:
1773                        (void)printf("Time exceeded, Bad Code: %d\n",
1774                            icp->icmp_code);
1775                        break;
1776                }
1777#ifndef icmp_data
1778                pr_retip(&icp->icmp_ip);
1779#else
1780                pr_retip((struct ip *)icp->icmp_data);
1781#endif
1782                break;
1783        case ICMP_PARAMPROB:
1784                (void)printf("Parameter problem: pointer = 0x%02x\n",
1785                    icp->icmp_hun.ih_pptr);
1786#ifndef icmp_data
1787                pr_retip(&icp->icmp_ip);
1788#else
1789                pr_retip((struct ip *)icp->icmp_data);
1790#endif
1791                break;
1792        case ICMP_TSTAMP:
1793                (void)printf("Timestamp\n");
1794                /* XXX ID + Seq + 3 timestamps */
1795                break;
1796        case ICMP_TSTAMPREPLY:
1797                (void)printf("Timestamp Reply\n");
1798                /* XXX ID + Seq + 3 timestamps */
1799                break;
1800        case ICMP_IREQ:
1801                (void)printf("Information Request\n");
1802                /* XXX ID + Seq */
1803                break;
1804        case ICMP_IREQREPLY:
1805                (void)printf("Information Reply\n");
1806                /* XXX ID + Seq */
1807                break;
1808        case ICMP_MASKREQ:
1809                (void)printf("Address Mask Request\n");
1810                break;
1811        case ICMP_MASKREPLY:
1812                (void)printf("Address Mask Reply\n");
1813                break;
1814        case ICMP_ROUTERADVERT:
1815                (void)printf("Router Advertisement\n");
1816                break;
1817        case ICMP_ROUTERSOLICIT:
1818                (void)printf("Router Solicitation\n");
1819                break;
1820        default:
1821                (void)printf("Bad ICMP type: %d\n", icp->icmp_type);
1822        }
1823}
1824
1825/*
1826 * pr_iph --
1827 *      Print an IP header with options.
1828 */
1829static void
1830pr_iph(ip)
1831        struct ip *ip;
1832{
1833        u_char *cp;
1834        int hlen;
1835
1836        hlen = ip->ip_hl << 2;
1837        cp = (u_char *)ip + 20;         /* point to options */
1838
1839        (void)printf("Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst\n");
1840        (void)printf(" %1x  %1x  %02x %04x %04x",
1841            ip->ip_v, ip->ip_hl, ip->ip_tos, ntohs(ip->ip_len),
1842            ntohs(ip->ip_id));
1843        (void)printf("   %1lx %04lx",
1844            (u_long) (ntohl(ip->ip_off) & 0xe000) >> 13,
1845            (u_long) ntohl(ip->ip_off) & 0x1fff);
1846        (void)printf("  %02x  %02x %04x", ip->ip_ttl, ip->ip_p,
1847                                                            ntohs(ip->ip_sum));
1848        (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
1849        (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
1850        /* dump any option bytes */
1851        while (hlen-- > 20) {
1852                (void)printf("%02x", *cp++);
1853        }
1854        (void)putchar('\n');
1855}
1856
1857/*
1858 * pr_addr --
1859 *      Return an ascii host address as a dotted quad and optionally with
1860 * a hostname.
1861 */
1862static char *
1863g_pr_addr(ina, globals)
1864        struct in_addr ina;
1865  rtems_shell_globals_t* globals;
1866{
1867        struct hostent *hp;
1868        static char buf[16 + 3 + MAXHOSTNAMELEN];
1869
1870        if ((options_ & F_NUMERIC) ||
1871            !(hp = gethostbyaddr((char *)&ina, 4, AF_INET)))
1872                return inet_ntoa(ina);
1873        else
1874                (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name,
1875                    inet_ntoa(ina));
1876        return(buf);
1877}
1878
1879/*
1880 * pr_retip --
1881 *      Dump some info on a returned (via ICMP) IP packet.
1882 */
1883static void
1884pr_retip(ip)
1885        struct ip *ip;
1886{
1887        u_char *cp;
1888        int hlen;
1889
1890        pr_iph(ip);
1891        hlen = ip->ip_hl << 2;
1892        cp = (u_char *)ip + hlen;
1893
1894        if (ip->ip_p == 6)
1895                (void)printf("TCP: from port %u, to port %u (decimal)\n",
1896                    (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
1897        else if (ip->ip_p == 17)
1898                (void)printf("UDP: from port %u, to port %u (decimal)\n",
1899                        (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
1900}
1901
1902static char *
1903pr_ntime (n_time timestamp)
1904{
1905        static char buf[10];
1906        int hour, min, sec;
1907
1908        sec = ntohl(timestamp) / 1000;
1909        hour = sec / 60 / 60;
1910        min = (sec % (60 * 60)) / 60;
1911        sec = (sec % (60 * 60)) % 60;
1912
1913        (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d", hour, min, sec);
1914
1915        return (buf);
1916}
1917
1918static void
1919g_fill(bp, patp, globals)
1920        char *bp, *patp;
1921  rtems_shell_globals_t* globals;
1922{
1923        char *cp;
1924        int pat[16];
1925        u_int ii, jj, kk;
1926
1927        for (cp = patp; *cp; cp++) {
1928                if (!isxdigit((int)*cp))
1929                        errx(&globals->exit_jmp, EX_USAGE,
1930                            "patterns must be specified as hex digits");
1931
1932        }
1933        ii = sscanf(patp,
1934            "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1935            &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
1936            &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
1937            &pat[13], &pat[14], &pat[15]);
1938
1939        if (ii > 0)
1940                for (kk = 0; kk <= maxpayload - (TIMEVAL_LEN + ii); kk += ii)
1941                        for (jj = 0; jj < ii; ++jj)
1942                                bp[jj + kk] = pat[jj];
1943        if (!(options_ & F_QUIET)) {
1944                (void)printf("PATTERN: 0x");
1945                for (jj = 0; jj < ii; ++jj)
1946                        (void)printf("%02x", bp[jj] & 0xFF);
1947                (void)printf("\n");
1948        }
1949}
1950
1951#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
1952#define SECOPT          " [-P policy]"
1953#else
1954#define SECOPT          ""
1955#endif
1956static void
1957g_usage(globals)
1958  rtems_shell_globals_t* globals;
1959{
1960        (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
1961"usage: ping [-AaDdfnoQqRrv] [-c count] [-G sweepmaxsize] [-g sweepminsize]",
1962"            [-h sweepincrsize] [-i wait] [-l preload] [-M mask | time] [-m ttl]",
1963"           " SECOPT " [-p pattern] [-S src_addr] [-s packetsize] [-t timeout]",
1964"            [-W waittime] [-z tos] host",
1965"       ping [-AaDdfLnoQqRrv] [-c count] [-I iface] [-i wait] [-l preload]",
1966"            [-M mask | time] [-m ttl]" SECOPT " [-p pattern] [-S src_addr]",
1967"            [-s packetsize] [-T ttl] [-t timeout] [-W waittime]",
1968"            [-z tos] mcast-group");
1969        exit(EX_USAGE);
1970  while (1);
1971}
1972
1973#if __rtems__
1974  rtems_shell_cmd_t rtems_shell_PING_Command = {
1975    "ping",                        /* name */
1976    "ping [args]",                 /* usage */
1977    "network",                     /* topic */
1978    rtems_shell_main_ping,         /* command */
1979    NULL,                          /* alias */
1980    NULL                           /* next */
1981  };
1982#endif
Note: See TracBrowser for help on using the repository browser.