]> git.saurik.com Git - apple/network_cmds.git/blobdiff - ping.tproj/ping.c
network_cmds-596.tar.gz
[apple/network_cmds.git] / ping.tproj / ping.c
index 3b1b89cf5570510df245ec003089e0c28d9a1358..58e7f800f23feb5dd7f86b165a451e3184af9063 100644 (file)
@@ -1,3 +1,30 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
 /*
  * Copyright (c) 1989, 1993
  *     The Regents of the University of California.  All rights reserved.
  * SUCH DAMAGE.
  */
 
-#if 0
+#include <sys/cdefs.h>
+
 #ifndef lint
-static const char copyright[] =
+__unused static const char copyright[] =
 "@(#) Copyright (c) 1989, 1993\n\
        The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
-#ifndef lint
-static char sccsid[] = "@(#)ping.c     8.1 (Berkeley) 6/5/93";
-#endif /* not lint */
-#endif
-#include <sys/cdefs.h>
-#ifndef __APPLE__
-__FBSDID("$FreeBSD: /repoman/r/ncvs/src/sbin/ping/ping.c,v 1.105 2004/08/14 17:46:10 stefanf Exp $");
-#endif
-
 /*
  *                     P I N G . C
  *
@@ -76,6 +95,7 @@ __FBSDID("$FreeBSD: /repoman/r/ncvs/src/sbin/ping/ping.c,v 1.105 2004/08/14 17:4
 #include <netinet/ip_icmp.h>
 #include <netinet/ip_var.h>
 #include <arpa/inet.h>
+#include <net/if.h>
 
 #ifdef IPSEC
 #include <netinet6/ipsec.h>
@@ -87,14 +107,17 @@ __FBSDID("$FreeBSD: /repoman/r/ncvs/src/sbin/ping/ping.c,v 1.105 2004/08/14 17:4
 #include <math.h>
 #include <netdb.h>
 #include <signal.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sysexits.h>
 #include <unistd.h>
+#include <ifaddrs.h>
+#include <getopt.h>
 
 #define        INADDR_LEN      ((int)sizeof(in_addr_t))
-#define        TIMEVAL_LEN     ((int)sizeof(struct timeval))
+#define        TIMEVAL_LEN     ((int)sizeof(struct tv32))
 #define        MASK_LEN        (ICMP_MASKLEN - ICMP_MINLEN)
 #define        TS_LEN          (ICMP_TSLEN - ICMP_MINLEN)
 #define        DEFDATALEN      56              /* default data length */
@@ -102,7 +125,7 @@ __FBSDID("$FreeBSD: /repoman/r/ncvs/src/sbin/ping/ping.c,v 1.105 2004/08/14 17:4
                                        /* runs out of buffer space */
 #define        MAXIPLEN        (sizeof(struct ip) + MAX_IPOPTLEN)
 #define        MAXICMPLEN      (ICMP_ADVLENMIN + MAX_IPOPTLEN)
-#define        MAXWAIT         10              /* max seconds to wait for response */
+#define        MAXWAIT         10000           /* max ms to wait for response */
 #define        MAXALARM        (60 * 60)       /* max seconds for alarm timeout */
 #define        MAXTOS          255
 
@@ -112,6 +135,11 @@ __FBSDID("$FreeBSD: /repoman/r/ncvs/src/sbin/ping/ping.c,v 1.105 2004/08/14 17:4
 #define        CLR(bit)        (A(bit) &= (~B(bit)))
 #define        TST(bit)        (A(bit) & B(bit))
 
+struct tv32 {
+       u_int32_t tv32_sec;
+       u_int32_t tv32_usec;
+};
+
 /* various options */
 int options;
 #define        F_FLOOD         0x0001
@@ -139,6 +167,10 @@ int options;
 #define        F_HDRINCL       0x40000
 #define        F_MASK          0x80000
 #define        F_TIME          0x100000
+#define        F_SWEEP         0x200000
+#define        F_WAITTIME      0x400000
+#define        F_CONNECT       0x800000
+#define F_PRTIME       0x1000000
 
 /*
  * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
@@ -165,6 +197,14 @@ u_char icmp_type = ICMP_ECHO;
 u_char icmp_type_rsp = ICMP_ECHOREPLY;
 int phdr_len = 0;
 int send_len;
+char *boundif;
+unsigned int ifscope;
+int nocell;
+int use_sendmsg = 0;
+int use_recvmsg = 0;
+int traffic_class = SO_TC_CTL; /* use control class, by default */
+int net_service_type = -1;
+int no_dup = 0;
 
 /* counters */
 long nmissedmax;               /* max value of ntransmitted - nreceived - 1 */
@@ -172,7 +212,16 @@ long npackets;                     /* max packets to transmit */
 long nreceived;                        /* # of packets we got back */
 long nrepeats;                 /* number of duplicates */
 long ntransmitted;             /* sequence # for outbound packets = #sent */
+long snpackets;                        /* max packets to transmit in one sweep */
+long snreceived;               /* # of packets we got back in this sweep */
+long sntransmitted;            /* # of packets we sent in this sweep */
+int sweepmax;                  /* max value of payload in sweep */
+int sweepmin = 0;              /* start value of payload in sweep */
+int sweepincr = 1;             /* payload increment in sweep */
 int interval = 1000;           /* interval between packets, ms */
+int waittime = MAXWAIT;                /* timeout for each packet */
+long nrcvtimeout = 0;          /* # of packets we got back after waittime */
+int icmp_len = 0;              /* length of the ICMP header */
 
 /* timing */
 int timing;                    /* flag to do timing */
@@ -193,17 +242,33 @@ static char *pr_addr(struct in_addr);
 static char *pr_ntime(n_time);
 static void pr_icmph(struct icmp *);
 static void pr_iph(struct ip *);
-static void pr_pack(char *, int, struct sockaddr_in *, struct timeval *);
+static void pr_pack(char *, int, struct sockaddr_in *, struct timeval *, int);
 static void pr_retip(struct ip *);
 static void status(int);
 static void stopit(int);
-static void tvsub(struct timeval *, struct timeval *);
+static void tvsub(struct timeval *, const struct timeval *);
+static int str2sotc(const char *, bool *);
+static int str2netservicetype(const char *, bool *);
+static u_int8_t str2tos(const char *, bool *);
 static void usage(void) __dead2;
 
+int32_t thiszone;              /* seconds offset from gmt to local time */
+extern int32_t gmt2local(time_t);
+static void pr_currenttime(void);
+
+static int longopt_flag = 0;
+
+#define        LOF_CONNECT     0x01
+#define        LOF_PRTIME      0x02
+
+static const struct option longopts[] = {
+       { "apple-connect", no_argument, &longopt_flag, LOF_CONNECT },
+       { "apple-time", no_argument, &longopt_flag, LOF_PRTIME },
+       { NULL, 0, NULL, 0 }
+};
+
 int
-main(argc, argv)
-       int argc;
-       char *const *argv;
+main(int argc, char *const *argv)
 {
        struct sockaddr_in from, sock_in;
        struct in_addr ifaddr;
@@ -213,7 +278,7 @@ main(argc, argv)
        struct msghdr msg;
        struct sigaction si_sa;
        size_t sz;
-       u_char *datap, packet[IP_MAXPACKET];
+       u_char *datap, packet[IP_MAXPACKET] __attribute__((aligned(4)));
        char *ep, *source, *target, *payload;
        struct hostent *hp;
 #ifdef IPSEC_POLICY_IPSEC
@@ -222,9 +287,9 @@ main(argc, argv)
        struct sockaddr_in *to;
        double t;
        u_long alarmtimeout, ultmp;
-       int almost_done, ch, df, hold, i, icmp_len, mib[4], preload, sockerrno,
+       int almost_done, ch, df, hold, i, mib[4], preload, sockerrno,
            tos, ttl;
-       char ctrl[CMSG_SPACE(sizeof(struct timeval))];
+       char ctrl[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(int))];
        char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN];
 #ifdef IP_OPTIONS
        char rspace[MAX_IPOPTLEN];      /* record route space */
@@ -235,29 +300,29 @@ main(argc, argv)
 #ifdef IPSEC_POLICY_IPSEC
        policy_in = policy_out = NULL;
 #endif
+       bool valid;
 
        /*
         * Do the stuff that we need root priv's for *first*, and
         * then drop our setuid bit.  Save error reporting for
         * after arg parsing.
         */
-       s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+       if (getuid())
+               s = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+       else
+               s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
        sockerrno = errno;
 
-       setuid(getuid());
+       if (setuid(getuid()) != 0)
+               err(EX_NOPERM, "setuid() failed");
        uid = getuid();
 
        alarmtimeout = df = preload = tos = 0;
 
        outpack = outpackhdr + sizeof(struct ip);
-       while ((ch = getopt(argc, argv,
-               "Aac:DdfI:i:Ll:M:m:nop:QqRrS:s:T:t:vz:"
-#ifdef IPSEC
-#ifdef IPSEC_POLICY_IPSEC
-               "P:"
-#endif /*IPSEC_POLICY_IPSEC*/
-#endif /*IPSEC*/
-               )) != -1)
+       while ((ch = getopt_long(argc, argv,
+           "AaB:b:Cc:DdfG:g:h:I:i:k:K:Ll:M:m:noP:p:QqRrS:s:T:t:vW:z:",
+           longopts, NULL)) != -1)
        {
                switch(ch) {
                case 'A':
@@ -266,6 +331,13 @@ main(argc, argv)
                case 'a':
                        options |= F_AUDIBLE;
                        break;
+               case 'B':
+               case 'b':
+                       boundif = optarg;
+                       break;
+               case 'C':
+                       nocell++;
+                       break;
                case 'c':
                        ultmp = strtoul(optarg, &ep, 0);
                        if (*ep || ep == optarg || ultmp > LONG_MAX || !ultmp)
@@ -289,6 +361,54 @@ main(argc, argv)
                        options |= F_FLOOD;
                        setbuf(stdout, (char *)NULL);
                        break;
+               case 'G': /* Maximum packet size for ping sweep */
+                       ultmp = strtoul(optarg, &ep, 0);
+                       if (*ep || ep == optarg)
+                               errx(EX_USAGE, "invalid packet size: `%s'",
+                                   optarg);
+#ifndef __APPLE__
+                       if (uid != 0 && ultmp > DEFDATALEN) {
+                               errno = EPERM;
+                               err(EX_NOPERM,
+                                   "packet size too large: %lu > %u",
+                                   ultmp, DEFDATALEN);
+                       }
+#endif /* __APPLE__ */
+                       options |= F_SWEEP;
+                       sweepmax = ultmp;
+                       break;
+               case 'g': /* Minimum packet size for ping sweep */
+                       ultmp = strtoul(optarg, &ep, 0);
+                       if (*ep || ep == optarg)
+                               errx(EX_USAGE, "invalid packet size: `%s'",
+                                   optarg);
+#ifndef __APPLE__
+                       if (uid != 0 && ultmp > DEFDATALEN) {
+                               errno = EPERM;
+                               err(EX_NOPERM,
+                                   "packet size too large: %lu > %u",
+                                   ultmp, DEFDATALEN);
+                       }
+#endif /* __APPLE__ */
+                       options |= F_SWEEP;
+                       sweepmin = ultmp;
+                       break;
+               case 'h': /* Packet size increment for ping sweep */
+                       ultmp = strtoul(optarg, &ep, 0);
+                       if (*ep || ep == optarg || ultmp < 1)
+                               errx(EX_USAGE, "invalid increment size: `%s'",
+                                   optarg);
+#ifndef __APPLE__
+                       if (uid != 0 && ultmp > DEFDATALEN) {
+                               errno = EPERM;
+                               err(EX_NOPERM,
+                                   "packet size too large: %lu > %u",
+                                   ultmp, DEFDATALEN);
+                       }
+#endif /* __APPLE__ */
+                       options |= F_SWEEP;
+                       sweepincr = ultmp;
+                       break;
                case 'I':               /* multicast interface */
                        if (inet_aton(optarg, &ifaddr) == 0)
                                errx(EX_USAGE,
@@ -303,11 +423,37 @@ main(argc, argv)
                                    optarg);
                        options |= F_INTERVAL;
                        interval = (int)t;
-                       if (uid && interval < 1000) {
+                       if (uid && interval < 100) {
                                errno = EPERM;
                                err(EX_NOPERM, "-i interval too short");
                        }
                        break;
+               case 'k':
+                       if (strcasecmp(optarg, "sendmsg") == 0) {
+                               use_sendmsg++;
+                               break;
+                       }
+                       if (strcasecmp(optarg, "recvmsg") == 0) {
+                               use_recvmsg++;
+                               break;
+                       }
+                       traffic_class = str2sotc(optarg, &valid);
+                       if (valid == false)
+                               errx(EX_USAGE, "bad traffic class: `%s'",
+                                    optarg);
+                       break;
+               case 'K':
+                       if (strcasecmp(optarg, "sendmsg") == 0) {
+                               use_sendmsg++;
+                               break;
+                       }
+                       net_service_type = str2netservicetype(optarg, &valid);
+                       if (valid == false)
+                               errx(EX_USAGE, "bad network service type: `%s'",
+                                    optarg);
+                       /* suppress default traffic class (-k can still be specified after -K) */
+                       traffic_class = -1;
+                       break;
                case 'L':
                        options |= F_NOLOOP;
                        loop = 0;
@@ -351,9 +497,9 @@ main(argc, argv)
                case 'o':
                        options |= F_ONCE;
                        break;
+               case 'P':
 #ifdef IPSEC
 #ifdef IPSEC_POLICY_IPSEC
-               case 'P':
                        options |= F_POLICY;
                        if (!strncmp("in", optarg, 2))
                                policy_in = strdup(optarg);
@@ -361,9 +507,9 @@ main(argc, argv)
                                policy_out = strdup(optarg);
                        else
                                errx(1, "invalid security policy");
-                       break;
 #endif /*IPSEC_POLICY_IPSEC*/
 #endif /*IPSEC*/
+                       break;
                case 'p':               /* fill buffer with user pattern */
                        options |= F_PINGFILLED;
                        payload = optarg;
@@ -395,7 +541,7 @@ main(argc, argv)
                                    "packet size too large: %lu > %u",
                                    ultmp, DEFDATALEN);
                        }
-#endif
+#endif /* __APPLE__ */
                        datalen = ultmp;
                        break;
                case 'T':               /* multicast TTL */
@@ -414,23 +560,47 @@ main(argc, argv)
                        if (alarmtimeout > MAXALARM)
                                errx(EX_USAGE, "invalid timeout: `%s' > %d",
                                    optarg, MAXALARM);
-                       alarm((int)alarmtimeout);
+                       alarm((unsigned int)alarmtimeout);
                        break;
                case 'v':
                        options |= F_VERBOSE;
                        break;
+               case 'W':               /* wait ms for answer */
+                       t = strtod(optarg, &ep);
+                       if (*ep || ep == optarg || t > (double)INT_MAX)
+                               errx(EX_USAGE, "invalid timing interval: `%s'",
+                                   optarg);
+                       options |= F_WAITTIME;
+                       waittime = (int)t;
+                       break;
                case 'z':
                        options |= F_HDRINCL;
-                       ultmp = strtoul(optarg, &ep, 0);
-                       if (*ep || ep == optarg || ultmp > MAXTOS)
+                       tos = str2tos(optarg, &valid);
+                       if (valid == false)
                                errx(EX_USAGE, "invalid TOS: `%s'", optarg);
-                       tos = ultmp;
+                       break;
+               case 0:
+                       switch (longopt_flag) {
+                               case LOF_CONNECT:
+                                       options |= F_CONNECT;
+                                       break;
+                               case LOF_PRTIME:
+                                       options |= F_PRTIME;
+                                       thiszone = gmt2local(0);
+                                       break;
+                               default:
+                                       break;
+                       }
+                       longopt_flag = 0;
                        break;
                default:
                        usage();
                }
        }
 
+       if (boundif != NULL && (ifscope = if_nametoindex(boundif)) == 0)
+               errx(1, "bad interface name");
+
        if (argc - optind != 1)
                usage();
        target = argv[optind];
@@ -484,13 +654,16 @@ main(argc, argv)
                                errx(1, "gethostbyname2: illegal address");
                        memcpy(&sock_in.sin_addr, hp->h_addr_list[0],
                            sizeof(sock_in.sin_addr));
-                       (void)strncpy(snamebuf, hp->h_name,
-                           sizeof(snamebuf) - 1);
-                       snamebuf[sizeof(snamebuf) - 1] = '\0';
+                       (void)strlcpy(snamebuf, hp->h_name,
+                           sizeof(snamebuf));
                        shostname = snamebuf;
                }
                if (bind(s, (struct sockaddr *)&sock_in, sizeof sock_in) == -1)
+#if (DEBUG || DEVELOPMENT)
+                       options |= F_HDRINCL;
+#else
                        err(1, "bind");
+#endif /* DEBUG || DEVELOPMENT */
        }
 
        bzero(&whereto, sizeof(whereto));
@@ -508,11 +681,34 @@ main(argc, argv)
                if ((unsigned)hp->h_length > sizeof(to->sin_addr))
                        errx(1, "gethostbyname2 returned an illegal address");
                memcpy(&to->sin_addr, hp->h_addr_list[0], sizeof to->sin_addr);
-               (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
-               hnamebuf[sizeof(hnamebuf) - 1] = '\0';
+               (void)strlcpy(hnamebuf, hp->h_name, sizeof(hnamebuf));
                hostname = hnamebuf;
        }
 
+       do {
+               struct ifaddrs *ifa_list, *ifa;
+               
+               if (IN_MULTICAST(ntohl(whereto.sin_addr.s_addr)) || whereto.sin_addr.s_addr == INADDR_BROADCAST) {
+                       no_dup = 1;
+                       break;
+               }
+               
+               if (getifaddrs(&ifa_list) == -1)
+                       break;
+               for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
+                       if (ifa->ifa_addr->sa_family != AF_INET)
+                               continue;
+                       if ((ifa->ifa_flags & IFF_BROADCAST) == 0 || ifa->ifa_broadaddr == NULL)
+                               continue;
+                       if (whereto.sin_addr.s_addr != ((struct sockaddr_in*)ifa->ifa_broadaddr)->sin_addr.s_addr)
+                               continue;
+                       no_dup = 1;
+                       break;
+               }
+               
+               freeifaddrs(ifa_list);
+       } while (0);
+       
        if (options & F_FLOOD && options & F_INTERVAL)
                errx(EX_USAGE, "-f and -i: incompatible options");
 
@@ -524,11 +720,8 @@ main(argc, argv)
                errx(EX_USAGE,
                    "-I, -L, -T flags cannot be used with unicast destination");
 
-       if (datalen >= TIMEVAL_LEN)     /* can we time transfer */
-               timing = 1;
-
        if (!(options & F_PINGFILLED))
-               for (i = TIMEVAL_LEN; i < datalen; ++i)
+               for (i = TIMEVAL_LEN; i < MAX(datalen, sweepmax); ++i)
                        *datap++ = i;
 
        ident = getpid() & 0xFFFF;
@@ -538,12 +731,41 @@ main(argc, argv)
                err(EX_OSERR, "socket");
        }
        hold = 1;
+       (void) setsockopt(s, SOL_SOCKET, SO_RECV_ANYIF, (char *)&hold,
+           sizeof(hold));
+       if (ifscope != 0) {
+               if (setsockopt(s, IPPROTO_IP, IP_BOUND_IF,
+                   (char *)&ifscope, sizeof (ifscope)) != 0)
+                       err(EX_OSERR, "setsockopt(IP_BOUND_IF)");
+       }
+       if (nocell) {
+               if (setsockopt(s, IPPROTO_IP, IP_NO_IFT_CELLULAR,
+                   (char *)&nocell, sizeof (nocell)) != 0)
+                       err(EX_OSERR, "setsockopt(IP_NO_IFT_CELLULAR)");
+       }
        if (options & F_SO_DEBUG)
                (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
                    sizeof(hold));
        if (options & F_SO_DONTROUTE)
                (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
                    sizeof(hold));
+       if (use_sendmsg == 0) {
+               if (net_service_type != -1)
+                       if (setsockopt(s, SOL_SOCKET, SO_NET_SERVICE_TYPE,
+                                      (void *)&net_service_type, sizeof (net_service_type)) != 0)
+                               warn("setsockopt(SO_NET_SERVICE_TYPE");
+               if (traffic_class != -1) {
+                       if (setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS,
+                                      (void *)&traffic_class, sizeof (traffic_class)) != 0)
+                               warn("setsockopt(SO_TRAFFIC_CLASS");
+                       
+               }
+       }
+       if (use_recvmsg > 0) {
+               int on = 1;
+               (void) setsockopt(s, SOL_SOCKET, SO_RECV_TRAFFIC_CLASS,
+                   (void *)&on, sizeof (on));
+       }
 #ifdef IPSEC
 #ifdef IPSEC_POLICY_IPSEC
        if (options & F_POLICY) {
@@ -643,6 +865,29 @@ main(argc, argv)
        }
 #endif
 
+       if ((options & F_CONNECT)) {
+               if (connect(s, (struct sockaddr *)&whereto, sizeof whereto) == -1)
+                       err(EX_OSERR, "connect");
+       }
+
+       if (sweepmax) {
+               if (sweepmin >= sweepmax)
+                       errx(EX_USAGE, "Maximum packet size must be greater than the minimum packet size");
+
+               if (datalen != DEFDATALEN)
+                       errx(EX_USAGE, "Packet size and ping sweep are mutually exclusive");
+
+               if (npackets > 0) {
+                       snpackets = npackets;
+                       npackets = 0;
+               } else
+                       snpackets = 1;
+               datalen = sweepmin;
+               send_len = icmp_len + sweepmin;
+       }
+       if (options & F_SWEEP && !sweepmax) 
+               errx(EX_USAGE, "Maximum sweep size must be specified");
+
        /*
         * When pinging the broadcast address, you can get a lot of answers.
         * Doing something so evil is useful if you are trying to stress the
@@ -667,9 +912,29 @@ main(argc, argv)
                    inet_ntoa(to->sin_addr));
                if (source)
                        (void)printf(" from %s", shostname);
-               (void)printf(": %d data bytes\n", datalen);
-       } else
-               (void)printf("PING %s: %d data bytes\n", hostname, datalen);
+               if (sweepmax)
+                       (void)printf(": (%d ... %d) data bytes\n",
+                           sweepmin, sweepmax);
+               else 
+                       (void)printf(": %d data bytes\n", datalen);
+               
+       } else {
+               if (sweepmax)
+                       (void)printf("PING %s: (%d ... %d) data bytes\n",
+                           hostname, sweepmin, sweepmax);
+               else
+                       (void)printf("PING %s: %d data bytes\n", hostname, datalen);
+       }
+
+       /*
+        * rdar://25829310
+        *
+        * Clear blocked signals inherited from the parent
+        */
+       sigset_t newset;
+       sigemptyset(&newset);
+       if (sigprocmask(SIG_SETMASK, &newset, NULL) != 0)
+               err(EX_OSERR, "sigprocmask(newset)");
 
        /*
         * Use sigaction() instead of signal() to get unambiguous semantics,
@@ -683,17 +948,21 @@ main(argc, argv)
        if (sigaction(SIGINT, &si_sa, 0) == -1) {
                err(EX_OSERR, "sigaction SIGINT");
        }
-
+       si_sa.sa_handler = stopit;
+       if (sigaction(SIGQUIT, &si_sa, 0) == -1) {
+               err(EX_OSERR, "sigaction SIGQUIT");
+       }
+    
        si_sa.sa_handler = status;
        if (sigaction(SIGINFO, &si_sa, 0) == -1) {
-               err(EX_OSERR, "sigaction");
+               err(EX_OSERR, "sigaction SIGINFO");
        }
 
-        if (alarmtimeout > 0) {
+       if (alarmtimeout > 0) {
                si_sa.sa_handler = stopit;
                if (sigaction(SIGALRM, &si_sa, 0) == -1)
                        err(EX_OSERR, "sigaction SIGALRM");
-        }
+       }
 
        bzero(&msg, sizeof(msg));
        msg.msg_name = (caddr_t)&from;
@@ -728,6 +997,7 @@ main(argc, argv)
                struct timeval now, timeout;
                fd_set rfds;
                int cc, n;
+               int tc = -1;
 
                check_status();
                if ((unsigned)s >= FD_SETSIZE)
@@ -753,7 +1023,7 @@ main(argc, argv)
                if (n == 1) {
                        struct timeval *tv = NULL;
 #ifdef SO_TIMESTAMP
-                       struct cmsghdr *cmsg = (struct cmsghdr *)&ctrl;
+                       struct cmsghdr *cmsg;
 
                        msg.msg_controllen = sizeof(ctrl);
 #endif
@@ -764,25 +1034,40 @@ main(argc, argv)
                                warn("recvmsg");
                                continue;
                        }
+                       for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
 #ifdef SO_TIMESTAMP
-                       if (cmsg->cmsg_level == SOL_SOCKET &&
-                           cmsg->cmsg_type == SCM_TIMESTAMP &&
-                           cmsg->cmsg_len == CMSG_LEN(sizeof *tv)) {
-                               /* Copy to avoid alignment problems: */
-                               memcpy(&now, CMSG_DATA(cmsg), sizeof(now));
-                               tv = &now;
-                       }
+                               if (cmsg->cmsg_level == SOL_SOCKET &&
+                                       cmsg->cmsg_type == SCM_TIMESTAMP &&
+                                       cmsg->cmsg_len == CMSG_LEN(sizeof *tv)) {
+                                       /* Copy to avoid alignment problems: */
+                                       memcpy(&now, CMSG_DATA(cmsg), sizeof(now));
+                                       tv = &now;
+                               }
 #endif
+                               if (cmsg->cmsg_level == SOL_SOCKET &&
+                                       cmsg->cmsg_type == SO_TRAFFIC_CLASS &&
+                                       cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
+                                       /* Copy to avoid alignment problems: */
+                                       memcpy(&tc, CMSG_DATA(cmsg), sizeof(tc));
+                               }
+                       }
                        if (tv == NULL) {
                                (void)gettimeofday(&now, NULL);
                                tv = &now;
                        }
-                       pr_pack((char *)packet, cc, &from, tv);
+                       pr_pack((char *)packet, cc, &from, tv, tc);
                        if ((options & F_ONCE && nreceived) ||
                            (npackets && nreceived >= npackets))
                                break;
                }
                if (n == 0 || options & F_FLOOD) {
+                       if (sweepmax && sntransmitted == snpackets) {
+                               datalen += sweepincr;
+                               if (datalen > sweepmax)
+                                       break;
+                               send_len = icmp_len + datalen;
+                               sntransmitted = 0;
+                       } 
                        if (!npackets || ntransmitted < npackets)
                                pinger();
                        else {
@@ -794,14 +1079,22 @@ main(argc, argv)
                                        intvl.tv_sec = 2 * tmax / 1000;
                                        if (!intvl.tv_sec)
                                                intvl.tv_sec = 1;
-                               } else
-                                       intvl.tv_sec = MAXWAIT;
+                               } else {
+                                       intvl.tv_sec = waittime / 1000;
+                                       intvl.tv_usec = waittime % 1000 * 1000;
+                               }
                        }
                        (void)gettimeofday(&last, NULL);
                        if (ntransmitted - nreceived - 1 > nmissedmax) {
                                nmissedmax = ntransmitted - nreceived - 1;
                                if (options & F_MISSED)
                                        (void)write(STDOUT_FILENO, &BBELL, 1);
+                               if (!(options & F_QUIET)) {
+                                       printf("Request timeout for icmp_seq %u\n",
+                                              (uint16_t)(ntransmitted - 2));
+                                       if (!(options & F_FLOOD))
+                                               (void)fflush(stdout);
+                               }
                        }
                }
        }
@@ -817,8 +1110,7 @@ main(argc, argv)
  * to be called from a signal handler.
  */
 void
-stopit(sig)
-       int sig __unused;
+stopit(int sig __unused)
 {
 
        /*
@@ -842,6 +1134,7 @@ static void
 pinger(void)
 {
        struct timeval now;
+       struct tv32 tv32;
        struct ip *ip;
        struct icmp *icp;
        int cc, i;
@@ -857,16 +1150,23 @@ pinger(void)
 
        CLR(ntransmitted % mx_dup_ck);
 
+       if (datalen >= TIMEVAL_LEN)     /* can we time transfer */
+               timing = 1;
+       else
+               timing = 0;
+       
        if ((options & F_TIME) || timing) {
                (void)gettimeofday(&now, NULL);
 
+               tv32.tv32_sec = htonl(now.tv_sec);
+               tv32.tv32_usec = htonl(now.tv_usec);
                if (options & F_TIME)
                        icp->icmp_otime = htonl((now.tv_sec % (24*60*60))
                                * 1000 + now.tv_usec / 1000);
                if (timing)
-                       bcopy((void *)&now,
+                       bcopy((void *)&tv32,
                            (void *)&outpack[ICMP_MINLEN + phdr_len],
-                           sizeof(struct timeval));
+                           sizeof(tv32));
        }
 
        cc = ICMP_MINLEN + phdr_len + datalen;
@@ -881,9 +1181,55 @@ pinger(void)
                ip->ip_sum = in_cksum((u_short *)outpackhdr, cc);
                packet = outpackhdr;
        }
-       i = sendto(s, (char *)packet, cc, 0, (struct sockaddr *)&whereto,
-           sizeof(whereto));
+       if (use_sendmsg > 0) {
+               struct msghdr msg;
+               struct iovec iov;
+               char cmbuf[2 * CMSG_SPACE(sizeof(int))];
+               struct cmsghdr *cm = (struct cmsghdr *)cmbuf;
+
+               if ((options & F_CONNECT)) {
+                       msg.msg_name = NULL;
+                       msg.msg_namelen = 0;
+               } else {
+               msg.msg_name = &whereto;
+               msg.msg_namelen = sizeof(whereto);
+               }
+               iov.iov_base = packet;
+               iov.iov_len = cc;
+               msg.msg_iov = &iov;
+               msg.msg_iovlen = 1;
+
+               msg.msg_controllen = 0;
+               msg.msg_control = NULL;
+               
+               if (traffic_class >= 0) {
+                       cm->cmsg_len = CMSG_LEN(sizeof(int));
+                       cm->cmsg_level = SOL_SOCKET;
+                       cm->cmsg_type = SO_TRAFFIC_CLASS;
+                       *(int *)CMSG_DATA(cm) = traffic_class;
+                       msg.msg_controllen += CMSG_SPACE(sizeof(int));
+                       cm = (struct cmsghdr *)(((char *)cm) + CMSG_SPACE(sizeof(int)));
+               }
+               if (net_service_type >= 0) {
+                       cm->cmsg_len = CMSG_LEN(sizeof(int));
+                       cm->cmsg_level = SOL_SOCKET;
+                       cm->cmsg_type = SO_NET_SERVICE_TYPE;
+                       msg.msg_controllen += CMSG_SPACE(sizeof(int));
+                       *(int *)CMSG_DATA(cm) = net_service_type;
+               }
+               msg.msg_control = cmbuf;
+
+               msg.msg_flags = 0;
 
+               i = sendmsg(s, &msg, 0);
+       } else {
+               if ((options & F_CONNECT)) {
+                       i = send(s, (char *)packet, cc, 0);
+               } else {
+               i = sendto(s, (char *)packet, cc, 0, (struct sockaddr *)&whereto,
+                       sizeof(whereto));
+       }
+       }
        if (i < 0 || i != cc)  {
                if (i < 0) {
                        if (options & F_FLOOD && errno == ENOBUFS) {
@@ -897,6 +1243,7 @@ pinger(void)
                }
        }
        ntransmitted++;
+       sntransmitted++;
        if (!(options & F_QUIET) && options & F_FLOOD)
                (void)write(STDOUT_FILENO, &DOT, 1);
 }
@@ -909,11 +1256,8 @@ pinger(void)
  * program to be run without having intermingled output (or statistics!).
  */
 static void
-pr_pack(buf, cc, from, tv)
-       char *buf;
-       int cc;
-       struct sockaddr_in *from;
-       struct timeval *tv;
+pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv,
+    int tc)
 {
        struct in_addr ina;
        u_char *cp, *dp;
@@ -946,6 +1290,7 @@ pr_pack(buf, cc, from, tv)
                triptime = 0.0;
                if (timing) {
                        struct timeval tv1;
+                       struct tv32 tv32;
 #ifndef icmp_data
                        tp = &icp->icmp_ip;
 #else
@@ -955,7 +1300,9 @@ pr_pack(buf, cc, from, tv)
 
                        if (cc - ICMP_MINLEN - phdr_len >= sizeof(tv1)) {
                                /* Copy to avoid alignment problems: */
-                               memcpy(&tv1, tp, sizeof(tv1));
+                               memcpy(&tv32, tp, sizeof(tv32));
+                               tv1.tv_sec = ntohl(tv32.tv32_sec);
+                               tv1.tv_usec = ntohl(tv32.tv32_usec);
                                tvsub(tv, &tv1);
                                triptime = ((double)tv->tv_sec) * 1000.0 +
                                    ((double)tv->tv_usec) / 1000.0;
@@ -982,18 +1329,40 @@ pr_pack(buf, cc, from, tv)
 
                if (options & F_QUIET)
                        return;
+       
+               if (options & F_WAITTIME && triptime > waittime) {
+                       ++nrcvtimeout;
+                       return;
+               }
 
                if (options & F_FLOOD)
                        (void)write(STDOUT_FILENO, &BSPACE, 1);
                else {
+                       int seq_sent_len = send_len;
+                       int seq_datalen = datalen;
+                       
+                       if (sweepmax != 0) {
+                               /*
+                                * When sweeping take in account the length of that
+                                * was sent based on the sequence number
+                                */
+                               seq_datalen = sweepmin + (seq / snpackets) * sweepincr;
+                               seq_sent_len = icmp_len + seq_datalen;
+                       }
+                       if (options & F_PRTIME)
+                               pr_currenttime();
                        (void)printf("%d bytes from %s: icmp_seq=%u", cc,
                           inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
                           seq);
                        (void)printf(" ttl=%d", ip->ip_ttl);
                        if (timing)
                                (void)printf(" time=%.3f ms", triptime);
-                       if (dupflag)
+                       if (tc != -1) {
+                               (void)printf(" tc=%d", tc);
+                       }
+                       if (dupflag && no_dup == 0) {
                                (void)printf(" (DUP!)");
+                       }
                        if (options & F_AUDIBLE)
                                (void)write(STDOUT_FILENO, &BBELL, 1);
                        if (options & F_MASK) {
@@ -1006,10 +1375,10 @@ pr_pack(buf, cc, from, tv)
                                (void)printf(" tsr=%s", pr_ntime(icp->icmp_rtime));
                                (void)printf(" tst=%s", pr_ntime(icp->icmp_ttime));
                        }
-                       if (recv_len != send_len) {
+                       if (recv_len != seq_sent_len) {
                                (void)printf(
                                     "\nwrong total length %d instead of %d",
-                                    recv_len, send_len);
+                                    recv_len, seq_sent_len);
                        }
                        /* check the data */
                        cp = (u_char*)&icp->icmp_data[phdr_len];
@@ -1022,21 +1391,21 @@ pr_pack(buf, cc, from, tv)
                                cc -= TIMEVAL_LEN;
                                i += TIMEVAL_LEN;
                        }
-                       for (; i < datalen && cc > 0; ++i, ++cp, ++dp, --cc) {
+                       for (; i < seq_datalen && cc > 0; ++i, ++cp, ++dp, --cc) {
                                if (*cp != *dp) {
        (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
            i, *dp, *cp);
                                        (void)printf("\ncp:");
                                        cp = (u_char*)&icp->icmp_data[0];
-                                       for (i = 0; i < datalen; ++i, ++cp) {
-                                               if ((i % 16) == 8)
+                                       for (i = 0; i < seq_datalen; ++i, ++cp) {
+                                               if ((i % 16) == 0)
                                                        (void)printf("\n\t");
                                                (void)printf("%2x ", *cp);
                                        }
                                        (void)printf("\ndp:");
                                        cp = &outpack[ICMP_MINLEN];
-                                       for (i = 0; i < datalen; ++i, ++cp) {
-                                               if ((i % 16) == 8)
+                                       for (i = 0; i < seq_datalen; ++i, ++cp) {
+                                               if ((i % 16) == 0)
                                                        (void)printf("\n\t");
                                                (void)printf("%2x ", *cp);
                                        }
@@ -1068,6 +1437,8 @@ pr_pack(buf, cc, from, tv)
                     (oip->ip_p == IPPROTO_ICMP) &&
                     (oicmp->icmp_type == ICMP_ECHO) &&
                     (oicmp->icmp_id == ident))) {
+                   if (options & F_PRTIME)
+                           pr_currenttime();
                    (void)printf("%d bytes from %s: ", cc,
                        pr_addr(from->sin_addr));
                    pr_icmph(icp);
@@ -1169,9 +1540,7 @@ pr_pack(buf, cc, from, tv)
  *     Checksum routine for Internet Protocol family headers (C Version)
  */
 u_short
-in_cksum(addr, len)
-       u_short *addr;
-       int len;
+in_cksum(u_short *addr, int len)
 {
        int nleft, sum;
        u_short *w;
@@ -1215,8 +1584,7 @@ in_cksum(addr, len)
  * be >= in.
  */
 static void
-tvsub(out, in)
-       struct timeval *out, *in;
+tvsub(struct timeval *out, const struct timeval *in)
 {
 
        if ((out->tv_usec -= in->tv_usec) < 0) {
@@ -1232,20 +1600,19 @@ tvsub(out, in)
  */
 
 static void
-status(sig)
-       int sig __unused;
+status(int sig __unused)
 {
 
        siginfo_p = 1;
 }
 
 static void
-check_status()
+check_status(void)
 {
 
        if (siginfo_p) {
                siginfo_p = 0;
-               (void)fprintf(stderr, "\r%ld/%ld packets received (%.0f%%)",
+               (void)fprintf(stderr, "\r%ld/%ld packets received (%.1f%%)",
                    nreceived, ntransmitted,
                    ntransmitted ? nreceived * 100.0 / ntransmitted : 0.0);
                if (nreceived && timing)
@@ -1260,7 +1627,7 @@ check_status()
  *     Print out statistics, and give up.
  */
 static void
-finish()
+finish(void)
 {
 
        (void)signal(SIGINT, SIG_IGN);
@@ -1276,10 +1643,12 @@ finish()
                if (nreceived > ntransmitted)
                        (void)printf("-- somebody's printing up packets!");
                else
-                       (void)printf("%d%% packet loss",
-                           (int)(((ntransmitted - nreceived) * 100) /
-                           ntransmitted));
+                       (void)printf("%.1f%% packet loss",
+                           ((ntransmitted - nreceived) * 100.0) /
+                           ntransmitted);
        }
+       if (nrcvtimeout)
+               (void)printf(", %ld packets out of wait time", nrcvtimeout);
        (void)putchar('\n');
        if (nreceived && timing) {
                double n = nreceived + nrepeats;
@@ -1317,8 +1686,7 @@ static char *ttab[] = {
  *     Print a descriptive string about an ICMP header.
  */
 static void
-pr_icmph(icp)
-       struct icmp *icp;
+pr_icmph(struct icmp *icp)
 {
 
        switch(icp->icmp_type) {
@@ -1465,8 +1833,7 @@ pr_icmph(icp)
  *     Print an IP header with options.
  */
 static void
-pr_iph(ip)
-       struct ip *ip;
+pr_iph(struct ip *ip)
 {
        u_char *cp;
        int hlen;
@@ -1498,8 +1865,7 @@ pr_iph(ip)
  * a hostname.
  */
 static char *
-pr_addr(ina)
-       struct in_addr ina;
+pr_addr(struct in_addr ina)
 {
        struct hostent *hp;
        static char buf[16 + 3 + MAXHOSTNAMELEN];
@@ -1518,8 +1884,7 @@ pr_addr(ina)
  *     Dump some info on a returned (via ICMP) IP packet.
  */
 static void
-pr_retip(ip)
-       struct ip *ip;
+pr_retip(struct ip *ip)
 {
        u_char *cp;
        int hlen;
@@ -1537,7 +1902,7 @@ pr_retip(ip)
 }
 
 static char *
-pr_ntime (n_time timestamp)
+pr_ntime(n_time timestamp)
 {
        static char buf[10];
        int hour, min, sec;
@@ -1553,8 +1918,7 @@ pr_ntime (n_time timestamp)
 }
 
 static void
-fill(bp, patp)
-       char *bp, *patp;
+fill(char *bp, char *patp)
 {
        char *cp;
        int pat[16];
@@ -1584,21 +1948,187 @@ fill(bp, patp)
        }
 }
 
+int
+str2sotc(const char *str, bool *valid)
+{
+       int sotc = -1;
+       char *endptr;
+       
+       *valid = true;
+       
+       if (str == NULL || *str == '\0')
+               *valid = false;
+       else if (strcasecmp(str, "BK_SYS") == 0)
+               return SO_TC_BK_SYS;
+       else if (strcasecmp(str, "BK") == 0)
+               return SO_TC_BK;
+       else if (strcasecmp(str, "BE") == 0)
+               return SO_TC_BE;
+       else if (strcasecmp(str, "RD") == 0)
+               return SO_TC_RD;
+       else if (strcasecmp(str, "OAM") == 0)
+               return SO_TC_OAM;
+       else if (strcasecmp(str, "AV") == 0)
+               return SO_TC_AV;
+       else if (strcasecmp(str, "RV") == 0)
+               return SO_TC_RV;
+       else if (strcasecmp(str, "VI") == 0)
+               return SO_TC_VI;
+       else if (strcasecmp(str, "VO") == 0)
+               return SO_TC_VO;
+       else if (strcasecmp(str, "CTL") == 0)
+               return SO_TC_CTL;
+       else {
+               sotc = (int)strtol(str, &endptr, 0);
+               if (*endptr != '\0')
+                       *valid = false;
+       }
+       return (sotc);
+}
+
+int
+str2netservicetype(const char *str, bool *valid)
+{
+       int svc = -1;
+       char *endptr;
+       
+       *valid = true;
+       
+       if (str == NULL || *str == '\0')
+               *valid = false;
+       else if (strcasecmp(str, "BK") == 0)
+               return NET_SERVICE_TYPE_BK;
+       else if (strcasecmp(str, "BE") == 0)
+               return NET_SERVICE_TYPE_BE;
+       else if (strcasecmp(str, "VI") == 0)
+               return NET_SERVICE_TYPE_VI;
+       else if (strcasecmp(str, "SIG") == 0)
+               return NET_SERVICE_TYPE_SIG;
+       else if (strcasecmp(str, "VO") == 0)
+               return NET_SERVICE_TYPE_VO;
+       else if (strcasecmp(str, "RV") == 0)
+               return NET_SERVICE_TYPE_RV;
+       else if (strcasecmp(str, "AV") == 0)
+               return NET_SERVICE_TYPE_AV;
+       else if (strcasecmp(str, "OAM") == 0)
+               return NET_SERVICE_TYPE_OAM;
+       else if (strcasecmp(str, "RD") == 0)
+               return NET_SERVICE_TYPE_RD;
+       else {
+               svc = (int)strtol(str, &endptr, 0);
+               if (*endptr != '\0')
+                       *valid = false;
+       }
+       return (svc);
+}
+
+u_int8_t
+str2tos(const char *str, bool *valid)
+{
+       u_int8_t dscp = -1;
+       char *endptr;
+       
+       *valid = true;
+       
+       if (str == NULL || *str == '\0')
+               *valid = false;
+       else if (strcasecmp(str, "DF") == 0)
+               dscp = _DSCP_DF;
+       else if (strcasecmp(str, "EF") == 0)
+               dscp = _DSCP_EF;
+       else if (strcasecmp(str, "VA") == 0)
+               dscp = _DSCP_VA;
+       
+       else if (strcasecmp(str, "CS0") == 0)
+               dscp = _DSCP_CS0;
+       else if (strcasecmp(str, "CS1") == 0)
+               dscp = _DSCP_CS1;
+       else if (strcasecmp(str, "CS2") == 0)
+               dscp = _DSCP_CS2;
+       else if (strcasecmp(str, "CS3") == 0)
+               dscp = _DSCP_CS3;
+       else if (strcasecmp(str, "CS4") == 0)
+               dscp = _DSCP_CS4;
+       else if (strcasecmp(str, "CS5") == 0)
+               dscp = _DSCP_CS5;
+       else if (strcasecmp(str, "CS6") == 0)
+               dscp = _DSCP_CS6;
+       else if (strcasecmp(str, "CS7") == 0)
+               dscp = _DSCP_CS7;
+       
+       else if (strcasecmp(str, "AF11") == 0)
+               dscp = _DSCP_AF11;
+       else if (strcasecmp(str, "AF12") == 0)
+               dscp = _DSCP_AF12;
+       else if (strcasecmp(str, "AF13") == 0)
+               dscp = _DSCP_AF13;
+       else if (strcasecmp(str, "AF21") == 0)
+               dscp = _DSCP_AF21;
+       else if (strcasecmp(str, "AF22") == 0)
+               dscp = _DSCP_AF22;
+       else if (strcasecmp(str, "AF23") == 0)
+               dscp = _DSCP_AF23;
+       else if (strcasecmp(str, "AF31") == 0)
+               dscp = _DSCP_AF31;
+       else if (strcasecmp(str, "AF32") == 0)
+               dscp = _DSCP_AF32;
+       else if (strcasecmp(str, "AF33") == 0)
+               dscp = _DSCP_AF33;
+       else if (strcasecmp(str, "AF41") == 0)
+               dscp = _DSCP_AF41;
+       else if (strcasecmp(str, "AF42") == 0)
+               dscp = _DSCP_AF42;
+       else if (strcasecmp(str, "AF43") == 0)
+               dscp = _DSCP_AF43;
+       
+       else {
+               unsigned long val = strtoul(str, &endptr, 0);
+               if (*endptr != '\0' || val > 255)
+                       *valid = false;
+               else
+                       return ((u_int8_t)val);
+       }
+       /* DSCP occupies the 6 upper bits of the TOS field */
+       return (dscp << 2);
+}
+
+void
+pr_currenttime(void)
+{
+       int s;
+       struct timeval tv;
+       
+       gettimeofday(&tv, NULL);
+       
+       s = (tv.tv_sec + thiszone) % 86400;
+       printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60,
+              (u_int32_t)tv.tv_usec);
+}
+
 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
 #define        SECOPT          " [-P policy]"
 #else
 #define        SECOPT          ""
 #endif
 static void
-usage()
+usage(void)
 {
 
-       (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n",
-"usage: ping [-AaDdfnoQqRrv] [-c count] [-i wait] [-l preload] [-M mask | time]",
-"            [-m ttl]" SECOPT " [-p pattern] [-S src_addr] [-s packetsize]",
-"            [-t timeout] [-z tos] host",
-"       ping [-AaDdfLnoQqRrv] [-c count] [-I iface] [-i wait] [-l preload]",
-"            [-M mask | time] [-m ttl]" SECOPT " [-p pattern] [-S src_addr]",
-"            [-s packetsize] [-T ttl] [-t timeout] [-z tos] mcast-group");
+       (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+"usage: ping [-AaDdfnoQqRrv] [-c count] [-G sweepmaxsize]",
+"            [-g sweepminsize] [-h sweepincrsize] [-i wait]",
+"            [-l preload] [-M mask | time] [-m ttl]" SECOPT " [-p pattern]",
+"            [-S src_addr] [-s packetsize] [-t timeout][-W waittime]",
+"            [-z tos] host",
+"       ping [-AaDdfLnoQqRrv] [-c count] [-I iface] [-i wait]",
+"            [-l preload] [-M mask | time] [-m ttl]" SECOPT " [-p pattern] [-S src_addr]",
+"            [-s packetsize] [-T ttl] [-t timeout] [-W waittime]",
+"            [-z tos] mcast-group");
+       (void)fprintf(stderr, "Apple specific options (to be specified before mcast-group or host like all options)\n");
+       (void)fprintf(stderr, "            -b boundif           # bind the socket to the interface\n");
+       (void)fprintf(stderr, "            -k traffic_class     # set traffic class socket option\n");
+       (void)fprintf(stderr, "            -K net_service_type  # set traffic class socket options\n");
+       (void)fprintf(stderr, "            -apple-connect       # call connect(2) in the socket\n");
+       (void)fprintf(stderr, "            -apple-time          # display current time\n");
        exit(EX_USAGE);
 }