]> git.saurik.com Git - apple/network_cmds.git/blobdiff - ping6.tproj/ping6.c
network_cmds-511.50.3.tar.gz
[apple/network_cmds.git] / ping6.tproj / ping6.c
index 4892b95a665de1536f48ade082f87d5fe02373c0..c5b0785cdef74e86471d4e84fb1c49f3ed9a365b 100644 (file)
@@ -1,4 +1,30 @@
-/*     $KAME: ping6.c,v 1.169 2003/07/25 06:01:47 itojun Exp $ */
+/*
+ * Copyright (c) 2002-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) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -29,8 +55,6 @@
  * SUCH DAMAGE.
  */
 
-/*     BSDI    ping.c,v 2.3 1996/01/21 17:56:50 jch Exp        */
-
 /*
  * Copyright (c) 1989, 1993
  *     The Regents of the University of California.  All rights reserved.
  * SUCH DAMAGE.
  */
 
+#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
-#if 0
-static char sccsid[] = "@(#)ping.c     8.1 (Berkeley) 6/5/93";
-#endif
-static const char rcsid[] =
-  "$FreeBSD$";
-#endif /* not lint */
-
 /*
  * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
  * measure round-trip-delays and packet loss across network paths.
@@ -125,6 +143,7 @@ static const char rcsid[] =
 #include <fcntl.h>
 #include <math.h>
 #include <signal.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -132,17 +151,15 @@ static const char rcsid[] =
 #ifdef HAVE_POLL_H
 #include <poll.h>
 #endif
+#include <sysexits.h>
+#include <getopt.h>
 
 #ifdef IPSEC
 #include <netinet6/ah.h>
 #include <netinet6/ipsec.h>
 #endif
 
-#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
-#include <md5.h>
-#else
 #include "md5.h"
-#endif
 
 struct tv32 {
        u_int32_t tv32_sec;
@@ -174,6 +191,7 @@ struct tv32 {
 #define        F_QUIET         0x0010
 #define        F_RROUTE        0x0020
 #define        F_SO_DEBUG      0x0040
+#define        F_PRTIME        0x0080
 #define        F_VERBOSE       0x0100
 #ifdef IPSEC
 #ifdef IPSEC_POLICY_IPSEC
@@ -195,9 +213,24 @@ struct tv32 {
 #define F_ONCE         0x200000
 #define F_AUDIBLE      0x400000
 #define F_MISSED       0x800000
+#define F_DONTFRAG     0x1000000
+#define        F_SWEEP         0x2000000
+#define F_CONNECT      0x4000000
 #define F_NOUSERDATA   (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES)
 u_int options;
 
+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 }
+};
+
+
 #define IN6LEN         sizeof(struct in6_addr)
 #define SA6LEN         sizeof(struct sockaddr_in6)
 #define DUMMY_PORT     10101
@@ -229,9 +262,17 @@ int ident;                 /* process id to identify our packets */
 u_int8_t nonce[8];             /* nonce field for node information */
 int hoplimit = -1;             /* hoplimit */
 int pathmtu = 0;               /* path MTU for the destination.  0 = unspec. */
+u_char *packet = NULL;
+struct cmsghdr *cm = NULL;
 char *boundif;
 unsigned int ifscope;
 int nocell;
+#ifdef HAVE_POLL_H
+struct pollfd fdmaskp[1];
+#else
+fd_set *fdmaskp = NULL;
+int fdmasks;
+#endif
 
 /* counters */
 long nmissedmax;               /* max value of ntransmitted - nreceived - 1 */
@@ -240,6 +281,11 @@ long nreceived;                    /* # of packets we got back */
 long nrepeats;                 /* number of duplicates */
 long ntransmitted;             /* sequence # for outbound packets = #sent */
 struct timeval interval = {1, 0}; /* interval between packets */
+long snpackets = 0;            /* max packets to transmit in one sweep */
+long sntransmitted = 0;                /* # of packets we sent in this sweep */
+int sweepmax = 0;              /* max value of payload in sweep */
+int sweepmin = 0;              /* start value of payload in sweep */
+int sweepincr = 1;             /* payload increment in sweep */
 
 /* timing */
 int timing;                    /* flag to do timing */
@@ -253,8 +299,8 @@ u_short naflags;
 
 /* for ancillary data(advanced API) */
 struct msghdr smsghdr;
-struct iovec smsgiov;
-char *scmsg = 0;
+struct iovec smsgiov[2];
+char *scmsg = NULL;
 
 volatile sig_atomic_t seenalrm;
 volatile sig_atomic_t seenint;
@@ -264,8 +310,14 @@ volatile sig_atomic_t seeninfo;
 
 int rcvtclass = 0;
 
-int how_so_traffic_class = 0;
-int so_traffic_class = -1;
+int use_sendmsg = 0;
+int use_recvmsg = 0;
+int so_traffic_class = SO_TC_CTL;      /* use control class, by default */
+int net_service_type = -1;
+
+int32_t thiszone;              /* seconds offset from gmt to local time */
+extern int32_t gmt2local(time_t);
+static void pr_currenttime(void);
 
 int     main(int, char *[]);
 void    fill(char *, char *);
@@ -298,12 +350,13 @@ void       summary(void);
 void    tvsub(struct timeval *, struct timeval *);
 int     setpolicy(int, char *);
 char   *nigroup(char *);
+static int str2sotc(const char *, bool *);
+static int str2netservicetype(const char *, bool *);
+static u_int8_t str2tclass(const char *, bool *);
 void    usage(void);
 
 int
-main(argc, argv)
-       int argc;
-       char *argv[];
+main(int argc, char *argv[])
 {
        struct itimerval itimer;
        struct sockaddr_in6 from;
@@ -316,19 +369,12 @@ main(argc, argv)
        struct timeval timeout, *tv;
 #endif
        struct addrinfo hints;
-#ifdef HAVE_POLL_H
-       struct pollfd fdmaskp[1];
-#else
-       fd_set *fdmaskp;
-       int fdmasks;
-#endif
        int cc, i;
        int ch, hold, packlen, preload, optval, ret_ga;
-       u_char *datap, *packet;
+       u_char *datap;
        char *e, *target, *ifname = NULL, *gateway = NULL;
        int ip6optlen = 0;
        struct cmsghdr *scmsgp = NULL;
-       struct cmsghdr *cm;
 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
        u_long lsockbufsize;
        int sockbufsize = 0;
@@ -347,7 +393,10 @@ main(argc, argv)
 #ifdef IPV6_USE_MIN_MTU
        int mflag = 0;
 #endif
-       int tclass = -2; /* T_CLASS value -1 means default, so -2 means do not bother */
+       /* T_CLASS value -1 means default, so -2 means do not bother */
+       int tclass = -2;
+       bool valid;
+       struct timeval intvl;
 
        /* just to be sure */
        memset(&smsghdr, 0, sizeof(smsghdr));
@@ -364,8 +413,9 @@ main(argc, argv)
 #define ADDOPTS        "AE"
 #endif /*IPSEC_POLICY_IPSEC*/
 #endif
-       while ((ch = getopt(argc, argv,
-           "a:b:B:Cc:dfHg:h:I:i:k:l:mnNop:qrRS:s:tvwWz:" ADDOPTS)) != -1) {
+       while ((ch = getopt_long(argc, argv,
+           "a:b:B:Cc:DdfHG:g:h:I:i:k:K:l:mnNop:qrRS:s:tvwWz:" ADDOPTS,
+           longopts, NULL)) != -1) {
 #undef ADDOPTS
                switch (ch) {
                case 'a':
@@ -400,8 +450,8 @@ main(argc, argv)
                                        naflags |= NI_NODEADDR_FLAG_ANYCAST;
                                        break;
 #else
-                                       errx(1,
-"-a A is not supported on the platform");
+                                       errx(1, "-a A is not supported on "
+                                           "the platform");
                                        /*NOTREACHED*/
 #endif
                                default:
@@ -421,8 +471,8 @@ main(argc, argv)
                            sockbufsize != lsockbufsize)
                                errx(1, "invalid socket buffer size");
 #else
-                       errx(1,
-"-b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported");
+                       errx(1, "-b option ignored: SO_SNDBUF/SO_RCVBUF "
+                           "socket options not supported");
 #endif
                        break;
                case 'B':
@@ -437,6 +487,9 @@ main(argc, argv)
                                errx(1,
                                    "illegal number of packets -- %s", optarg);
                        break;
+               case 'D':
+                       options |= F_DONTFRAG;
+                       break;
                case 'd':
                        options |= F_SO_DEBUG;
                        break;
@@ -451,6 +504,66 @@ main(argc, argv)
                case 'g':
                        gateway = optarg;
                        break;
+               case 'G': {
+                       char *ptr ;
+                       char *tofree;
+                       unsigned long ultmp;
+
+                       tofree = strdup(optarg);
+                       if (tofree == NULL)
+                               errx(1, "### strdup() failed");
+                       ptr = tofree;
+                       do {
+                               char *str;
+                               char *ep;
+                               
+                               if ((str = strsep(&ptr, ",")) == NULL)
+                                       errx(1, "-G requires maximum packet size");
+                               ultmp = strtoul(str, &ep, 0);
+                               if (*ep || ep == optarg)
+                                       errx(EX_USAGE, "option -G invalid maximum packet size: `%s'",
+                                            str);
+                               options |= F_SWEEP;
+                               sweepmax = ultmp;
+                               if (sweepmax < 1 || sweepmax > MAXDATALEN) {
+                                       errx(1,
+                                            "-G invalid maximum packet size, needs to be between 1 and %d",
+                                            MAXDATALEN);
+                               }
+
+                               if ((str = strsep(&ptr, ",")) == NULL)
+                                       break;
+                               if (*str != 0) {
+                                       ultmp = strtoul(str, &ep, 0);
+                                       if (*ep || ep == optarg)
+                                               errx(EX_USAGE, "option -G invalid minimum packet size: `%s'",
+                                                    str);
+                                       sweepmin = ultmp;
+                                       if (sweepmin < 0 || sweepmin > MAXDATALEN) {
+                                               errx(1,
+                                                    "-G invalid minimum packet size, needs to be between 0 and %d",
+                                                    MAXDATALEN);
+                                       }
+                               }
+                               
+                               if ((str = strsep(&ptr, ",")) == NULL)
+                                       break;
+                               if (*str == 0)
+                                       break;
+                               ultmp = strtoul(str, &ep, 0);
+                               if (*ep || ep == optarg)
+                                       errx(EX_USAGE, "option -G invalid sweep increment size: `%s'",
+                                            str);
+                               sweepincr = ultmp;
+                               if (sweepincr < 1 || sweepincr > MAXDATALEN) {
+                                       errx(1,
+                                            "-G invalid sweep increment size, needs to be between 1 and %d",
+                                            MAXDATALEN);
+                               }
+                       } while (0);
+                       free(tofree);
+                       break;
+               }
                case 'H':
                        options |= F_HOSTNAME;
                        break;
@@ -473,8 +586,8 @@ main(argc, argv)
                        intval = strtod(optarg, &e);
                        if (*optarg == '\0' || *e != '\0')
                                errx(1, "illegal timing interval %s", optarg);
-                       if (intval < 1 && getuid()) {
-                               errx(1, "%s: only root may use interval < 1s",
+                       if (intval < 0.1 && getuid()) {
+                               errx(1, "%s: only root may use interval < 0.1s",
                                    strerror(EPERM));
                        }
                        interval.tv_sec = (long)intval;
@@ -490,10 +603,31 @@ main(argc, argv)
                        options |= F_INTERVAL;
                        break;
                case 'k':
-                       how_so_traffic_class++;
-                       so_traffic_class = atoi(optarg);
+                       if (strcasecmp(optarg, "sendmsg") == 0) {
+                               use_sendmsg++;
+                               break;
+                       }
+                       if (strcasecmp(optarg, "recvmsg") == 0) {
+                               use_recvmsg++;
+                               break;
+                       }
+                       so_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) */
+                       so_traffic_class = -1;
                        break;
-                       
                case 'l':
                        if (getuid()) {
                                errno = EPERM;
@@ -523,7 +657,7 @@ main(argc, argv)
                case 'p':               /* fill buffer with user pattern */
                        options |= F_PINGFILLED;
                        fill((char *)datap, optarg);
-                               break;
+                       break;
                case 'q':
                        options |= F_QUIET;
                        break;
@@ -552,6 +686,7 @@ main(argc, argv)
                        memcpy(&src, res->ai_addr, res->ai_addrlen);
                        srclen = res->ai_addrlen;
                        freeaddrinfo(res);
+                       res = NULL;
                        options |= F_SRCADDR;
                        break;
                case 's':               /* size of packet to send */
@@ -580,13 +715,9 @@ main(argc, argv)
                        options |= F_FQDNOLD;
                        break;
                case 'z':
-                       tclass = (int)strtol(optarg, &e, 10);
-                       if (tclass < -1 || *optarg == '\0' || *e != '\0')
+                       tclass = str2tclass(optarg, &valid);
+                       if (valid == false)
                                errx(1, "illegal TOS value -- %s", optarg);
-                       if (tclass > MAXTOS)
-                               errx(1,
-                                   "TOS value too large, maximum is %d",
-                                   MAXTOS);
                        rcvtclass = 1;
                        break;
 #ifdef IPSEC
@@ -611,6 +742,20 @@ main(argc, argv)
                        break;
 #endif /*IPSEC_POLICY_IPSEC*/
 #endif /*IPSEC*/
+               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();
                        /*NOTREACHED*/
@@ -620,6 +765,12 @@ main(argc, argv)
        if (boundif != NULL && (ifscope = if_nametoindex(boundif)) == 0)
                errx(1, "bad interface name");
 
+       if ((options & F_SWEEP) && !sweepmax)
+               errx(EX_USAGE, "Maximum sweep size must be specified");
+
+       if ((options & F_SWEEP) && (options & F_NOUSERDATA))
+               errx(EX_USAGE, "Option -G incompatible with -t, -w and -W");
+       
        argc -= optind;
        argv += optind;
 
@@ -755,23 +906,40 @@ main(argc, argv)
        }
 
        /* revoke root privilege */
-       seteuid(getuid());
-       setuid(getuid());
+       if (seteuid(getuid()) != 0)
+               err(1, "seteuid() failed");
+       if (setuid(getuid()) != 0)
+               err(1, "setuid() failed");
 
        if ((options & F_FLOOD) && (options & F_INTERVAL))
                errx(1, "-f and -i incompatible options");
 
-       if ((options & F_NOUSERDATA) == 0) {
-               if (datalen >= sizeof(struct tv32)) {
-                       /* we can time transfer */
-                       timing = 1;
+       if ((options & F_CONNECT)) {
+               if (connect(s, (struct sockaddr *)&dst, sizeof(dst)) == -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
-                       timing = 0;
+                       snpackets = 1;
+               datalen = sweepmin;
+       }
+       
+       if ((options & F_NOUSERDATA) == 0) {
                /* in F_VERBOSE case, we may get non-echoreply packets*/
                if (options & F_VERBOSE)
-                       packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA;
+                       packlen = MAX(2048, sweepmax) + IP6LEN + ICMP6ECHOLEN + EXTRA;
                else
-                       packlen = datalen + IP6LEN + ICMP6ECHOLEN + EXTRA;
+                       packlen = MAX(datalen, sweepmax) + IP6LEN + ICMP6ECHOLEN + EXTRA;
        } else {
                /* suppress timing for node information query */
                timing = 0;
@@ -779,10 +947,10 @@ main(argc, argv)
                packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA;
        }
 
-       if (!(packet = (u_char *)malloc((u_int)packlen)))
+       if (!(packet = (u_char *)malloc((u_int)MAX(datalen, sweepmax))))
                err(1, "Unable to allocate packet");
        if (!(options & F_PINGFILLED))
-               for (i = ICMP6ECHOLEN; i < packlen; ++i)
+               for (i = ICMP6ECHOLEN; i < MAX(datalen, sweepmax); ++i)
                        *datap++ = i;
 
        ident = getpid() & 0xFFFF;
@@ -797,12 +965,20 @@ main(argc, argv)
        for (i = 0; i < sizeof(nonce); i += sizeof(u_int32_t))
                *((u_int32_t *)&nonce[i]) = arc4random();
 #endif
-
+       optval = 1;
+       if (options & F_DONTFRAG)
+               if (setsockopt(s, IPPROTO_IPV6, IPV6_DONTFRAG,
+                   &optval, sizeof(optval)) == -1)
+                       err(1, "IPV6_DONTFRAG");
        hold = 1;
-
        if (options & F_SO_DEBUG)
                (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
                    sizeof(hold));
+
+       hold = 1;
+       (void) setsockopt(s, SOL_SOCKET, SO_RECV_ANYIF, (char *)&hold,
+           sizeof(hold));
+
        optval = IPV6_DEFHLIM;
        if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr))
                if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
@@ -892,15 +1068,17 @@ main(argc, argv)
 
        if (tclass != -2) {
                int on = 1;
-               
-               if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVTCLASS, &on, sizeof(on)))
+
+               if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVTCLASS, &on,
+                   sizeof(on)))
                        err(1, "setsockopt(IPV6_RECVTCLASS)");
-               
-               if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass)))
+
+               if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &tclass,
+                   sizeof(tclass)))
                        err(1, "setsockopt(IPV6_TCLASS)");
        }
 
-       /*
+/*
        optval = 1;
        if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr))
                if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
@@ -915,21 +1093,38 @@ main(argc, argv)
        if (hoplimit != -1)
                ip6optlen += CMSG_SPACE(sizeof(int));
 
+#ifdef IPV6_USE_MIN_MTU
+       if (mflag != 1)
+               ip6optlen += CMSG_SPACE(sizeof(int));
+#endif /* IPV6_USE_MIN_MTU */
+
        if (tclass != -2)
                ip6optlen += CMSG_SPACE(sizeof(int));
 
-       if (how_so_traffic_class == 1 && so_traffic_class > 0) {
-               (void)setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&so_traffic_class,
-                                                sizeof(so_traffic_class));
-       } 
-       if (how_so_traffic_class > 0) {
+       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 (so_traffic_class != -1) {
+                       if (setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS,
+                           (void *)&so_traffic_class, sizeof (so_traffic_class)) != 0)
+                               warn("setsockopt(SO_TRAFFIC_CLASS");
+                       
+               }
+       } else {
+               if (net_service_type != -1)
+                       ip6optlen += CMSG_SPACE(sizeof(int));
+               if (so_traffic_class != -1)
+                       ip6optlen += CMSG_SPACE(sizeof(int));
+       }
+       if (use_recvmsg > 0) {
                int on = 1;
-               (void)setsockopt(s, SOL_SOCKET, SO_RECV_TRAFFIC_CLASS, (void *)&on,
-                                                sizeof(on));
+               if (setsockopt(s, SOL_SOCKET, SO_RECV_TRAFFIC_CLASS,
+                   (void *)&on, sizeof (on)) != 0)
+                       warn("setsockopt(SO_RECV_TRAFFIC_CLASS");
        }
-       if (how_so_traffic_class > 1)
-               ip6optlen += CMSG_SPACE(sizeof(int));
-       
+
        /* set IP6 packet options */
        if (ip6optlen) {
                if ((scmsg = (char *)malloc(ip6optlen)) == 0)
@@ -967,6 +1162,19 @@ main(argc, argv)
                scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
        }
 
+#ifdef IPV6_USE_MIN_MTU
+       if (mflag != 1) {
+               optval = mflag > 1 ? 0 : 1;
+
+               scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+               scmsgp->cmsg_level = IPPROTO_IPV6;
+               scmsgp->cmsg_type = IPV6_USE_MIN_MTU;
+               *(int *)(CMSG_DATA(scmsgp)) = optval;
+
+               scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+       }
+#endif /* IPV6_USE_MIN_MTU */
+
        if (argc > 1) { /* some intermediate addrs are specified */
                int hops, error;
 #ifdef USE_RFC2292BIS
@@ -1028,13 +1236,21 @@ main(argc, argv)
 
                scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
        }
-       if (how_so_traffic_class > 1) {
-               scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
-               scmsgp->cmsg_level = SOL_SOCKET;
-               scmsgp->cmsg_type = SO_TRAFFIC_CLASS;
-               *(int *)(CMSG_DATA(scmsgp)) = so_traffic_class;
-               
-               scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+       if (use_sendmsg != 0) {
+               if (so_traffic_class != -1) {
+                       scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+                       scmsgp->cmsg_level = SOL_SOCKET;
+                       scmsgp->cmsg_type = SO_TRAFFIC_CLASS;
+                       *(int *)(CMSG_DATA(scmsgp)) = so_traffic_class;
+
+                       scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+               }
+               if (net_service_type != -1) {
+                       scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+                       scmsgp->cmsg_level = SOL_SOCKET;
+                       scmsgp->cmsg_type = SO_NET_SERVICE_TYPE;
+                       *(int *)(CMSG_DATA(scmsgp)) = net_service_type;
+               }
        }
        if (!(options & F_SRCADDR)) {
                /*
@@ -1102,7 +1318,7 @@ main(argc, argv)
 
 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
        if (sockbufsize) {
-               if (datalen > sockbufsize)
+               if (MAX(datalen, sweepmax) > sockbufsize)
                        warnx("you need -b to increase socket buffer size");
                if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize,
                    sizeof(sockbufsize)) < 0)
@@ -1112,7 +1328,7 @@ main(argc, argv)
                        err(1, "setsockopt(SO_RCVBUF)");
        }
        else {
-               if (datalen > 8 * 1024) /*XXX*/
+               if (MAX(datalen, sweepmax) > 8 * 1024)  /*XXX*/
                        warnx("you need -b to increase socket buffer size");
                /*
                 * When pinging the broadcast address, you can get a lot of
@@ -1145,24 +1361,46 @@ main(argc, argv)
 #else  /* old adv. API */
        if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval,
            sizeof(optval)) < 0)
-               warn("setsockopt(IPV6_HOPLIMIT, %d, %lu)", optval, sizeof(optval)); /* XXX err? */
+               warn("setsockopt(IPV6_HOPLIMIT, %d, %lu)",
+                   optval, sizeof(optval)); /* XXX err? */
 #endif
 
-       printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()),
-           (unsigned long)(pingerlen() - 8));
+       if (sweepmax)
+               printf("PING6(40+8+[%lu...%lu] bytes) ",
+                      (unsigned long)(sweepmin),
+                      (unsigned long)(sweepmax));
+       else
+               printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()),
+                       (unsigned long)(pingerlen() - 8));
        printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src)));
        printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst)));
 
        while (preload--)               /* Fire off them quickies. */
                (void)pinger();
 
+       /*
+        * 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)");
+       
+       seenalrm = seenint = 0;
+#ifdef SIGINFO
+       seeninfo = 0;
+#endif
+       
        (void)signal(SIGINT, onsignal);
 #ifdef SIGINFO
        (void)signal(SIGINFO, onsignal);
 #endif
 
        if ((options & F_FLOOD) == 0) {
-               (void)signal(SIGALRM, onsignal);
+               if (signal(SIGALRM, onsignal) == SIG_ERR)
+                       warn("signal(SIGALRM)");
                itimer.it_interval = interval;
                itimer.it_value = interval;
                (void)setitimer(ITIMER_REAL, &itimer, NULL);
@@ -1170,17 +1408,20 @@ main(argc, argv)
                        retransmit();
        }
 
+       if (options & F_FLOOD) {
+               intvl.tv_sec = 0;
+               intvl.tv_usec = 10000;
+       } else {
+               intvl.tv_sec = interval.tv_sec;
+               intvl.tv_usec = interval.tv_usec;
+       }
+       
 #ifndef HAVE_POLL_H
        fdmasks = howmany(s + 1, NFDBITS) * sizeof(fd_mask);
        if ((fdmaskp = malloc(fdmasks)) == NULL)
                err(1, "malloc");
 #endif
 
-       seenalrm = seenint = 0;
-#ifdef SIGINFO
-       seeninfo = 0;
-#endif
-
        /* For control (ancillary) data received from recvmsg() */
        cm = (struct cmsghdr *)malloc(CONTROLLEN);
        if (cm == NULL)
@@ -1192,28 +1433,32 @@ main(argc, argv)
 
                /* signal handling */
                if (seenalrm) {
+                       seenalrm = 0;
                        /* last packet sent, timeout reached? */
                        if (npackets && ntransmitted >= npackets)
                                break;
+                       /* sweep done ? */
+                       if (sweepmax && datalen > sweepmax)
+                               break;
                        retransmit();
-                       seenalrm = 0;
                        continue;
                }
                if (seenint) {
-                       onint(SIGINT);
                        seenint = 0;
+                       onint(SIGINT);
                        continue;
                }
 #ifdef SIGINFO
                if (seeninfo) {
-                       summary();
                        seeninfo = 0;
+                       summary();
                        continue;
                }
 #endif
 
                if (options & F_FLOOD) {
-                       (void)pinger();
+                       if (pinger() != 0)
+                               break;
 #ifdef HAVE_POLL_H
                        timeout = 10;
 #else
@@ -1247,9 +1492,9 @@ main(argc, argv)
                                sleep(1);
                        }
                        continue;
-               } else if (cc == 0)
+               } else if (cc == 0) {
                        continue;
-
+               }
                m.msg_name = (caddr_t)&from;
                m.msg_namelen = sizeof(from);
                memset(&iov, 0, sizeof(iov));
@@ -1273,7 +1518,7 @@ main(argc, argv)
 
                        /*
                         * receive control messages only. Process the
-                        * exceptions (currently the only possiblity is
+                        * exceptions (currently the only possibility is
                         * a path MTU notification.)
                         */
                        if ((mtu = get_pathmtu(&m)) > 0) {
@@ -1299,14 +1544,32 @@ main(argc, argv)
                }
        }
        summary();
+
+       if (res != NULL)
+               freeaddrinfo(res);
+
+        if (packet != NULL)
+                free(packet);
+
+       if (cm != NULL)
+               free(cm);
+
+       if (scmsg != NULL)
+               free(scmsg);
+
+#ifndef HAVE_POLL_H
+        if (fdmaskp != NULL)
+                free(fdmaskp);
+#endif
+
        exit(nreceived == 0 ? 2 : 0);
 }
 
 void
-onsignal(sig)
-       int sig;
+onsignal(int sig)
 {
-
+       fflush(stdout);
+       
        switch (sig) {
        case SIGALRM:
                seenalrm++;
@@ -1327,13 +1590,13 @@ onsignal(sig)
  *     This routine transmits another ping6.
  */
 void
-retransmit()
+retransmit(void)
 {
        struct itimerval itimer;
 
-       if (pinger() == 0)
+       if (pinger() == 0) {
                return;
-
+       }
        /*
         * If we're not transmitting any more packets, change the timer
         * to wait two round-trip times if we've received any packets or
@@ -1363,7 +1626,7 @@ retransmit()
  * byte-order, to compute the round-trip time.
  */
 size_t
-pingerlen()
+pingerlen(void)
 {
        size_t l;
 
@@ -1382,10 +1645,9 @@ pingerlen()
 }
 
 int
-pinger()
+pinger(void)
 {
        struct icmp6_hdr *icp;
-       struct iovec iov[2];
        int i, cc;
        struct icmp6_nodeinfo *nip;
        int seq;
@@ -1393,6 +1655,13 @@ pinger()
        if (npackets && ntransmitted >= npackets)
                return(-1);     /* no more transmission */
 
+       if (sweepmax && sntransmitted == snpackets) {
+               datalen += sweepincr;
+               if (datalen > sweepmax)
+                       return(-1);     /* no more transmission */
+               sntransmitted = 0;
+       }
+
        icp = (struct icmp6_hdr *)outpack;
        nip = (struct icmp6_nodeinfo *)outpack;
        memset(icp, 0, sizeof(*icp));
@@ -1458,6 +1727,11 @@ pinger()
                icp->icmp6_code = 0;
                icp->icmp6_id = htons(ident);
                icp->icmp6_seq = ntohs(seq);
+               if (datalen >= sizeof(struct tv32)) {
+                       /* we can time transfer */
+                       timing = 1;
+               } else
+                       timing = 0;
                if (timing) {
                        struct timeval tv;
                        struct tv32 *tv32;
@@ -1474,12 +1748,17 @@ pinger()
                errx(1, "internal error; length mismatch");
 #endif
 
+       if ((options & F_CONNECT)) {
+               smsghdr.msg_name = NULL;
+               smsghdr.msg_namelen = 0;
+       } else {
        smsghdr.msg_name = (caddr_t)&dst;
        smsghdr.msg_namelen = sizeof(dst);
-       memset(&iov, 0, sizeof(iov));
-       iov[0].iov_base = (caddr_t)outpack;
-       iov[0].iov_len = cc;
-       smsghdr.msg_iov = iov;
+       }
+       memset(&smsgiov, 0, sizeof(smsgiov));
+       smsgiov[0].iov_base = (caddr_t)outpack;
+       smsgiov[0].iov_len = cc;
+       smsghdr.msg_iov = smsgiov;
        smsghdr.msg_iovlen = 1;
 
        i = sendmsg(s, &smsghdr, 0);
@@ -1490,6 +1769,7 @@ pinger()
                (void)printf("ping6: wrote %s %d chars, ret=%d\n",
                    hostname, cc, i);
        }
+       sntransmitted++;
        if (!(options & F_QUIET) && options & F_FLOOD)
                (void)write(STDOUT_FILENO, &DOT, 1);
 
@@ -1497,8 +1777,7 @@ pinger()
 }
 
 int
-myechoreply(icp)
-       const struct icmp6_hdr *icp;
+myechoreply(const struct icmp6_hdr *icp)
 {
        if (ntohs(icp->icmp6_id) == ident)
                return 1;
@@ -1507,8 +1786,7 @@ myechoreply(icp)
 }
 
 int
-mynireply(nip)
-       const struct icmp6_nodeinfo *nip;
+mynireply(const struct icmp6_nodeinfo *nip)
 {
        if (memcmp(nip->icmp6_ni_nonce + sizeof(u_int16_t),
            nonce + sizeof(u_int16_t),
@@ -1519,14 +1797,11 @@ mynireply(nip)
 }
 
 char *
-dnsdecode(sp, ep, base, buf, bufsiz)
-       const u_char **sp;
-       const u_char *ep;
-       const u_char *base;     /*base for compressed name*/
-       char *buf;
-       size_t bufsiz;
+dnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf,
+    size_t bufsiz)
+       /*base for compressed name*/
 {
-       int i;
+       int i = 0;
        const u_char *cp;
        char cresult[NS_MAXDNAME + 1];
        const u_char *comp;
@@ -1589,10 +1864,7 @@ dnsdecode(sp, ep, base, buf, bufsiz)
  * program to be run without having intermingled output (or statistics!).
  */
 void
-pr_pack(buf, cc, mhdr)
-       u_char *buf;
-       int cc;
-       struct msghdr *mhdr;
+pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
 {
 #define safeputc(c)    printf((isprint((c)) ? "%c" : "\\%03o"), c)
        struct icmp6_hdr *icp;
@@ -1613,7 +1885,7 @@ pr_pack(buf, cc, mhdr)
        char dnsname[NS_MAXDNAME + 1];
        int tclass = 0;
        int sotc = -1;
-       
+
        (void)gettimeofday(&tv, NULL);
 
        if (!mhdr || !mhdr->msg_name ||
@@ -1650,10 +1922,10 @@ pr_pack(buf, cc, mhdr)
                warnx("failed to get receiving traffic class");
                return;
        }
-       
-       if (how_so_traffic_class > 0)
+
+       if (use_recvmsg > 0)
                sotc = get_so_traffic_class(mhdr);
-               
+
        if (icp->icmp6_type == ICMP6_ECHO_REPLY && myechoreply(icp)) {
                seq = ntohs(icp->icmp6_seq);
                ++nreceived;
@@ -1689,6 +1961,8 @@ pr_pack(buf, cc, mhdr)
                else {
                        if (options & F_AUDIBLE)
                                (void)write(STDOUT_FILENO, &BBELL, 1);
+                       if (options & F_PRTIME)
+                               pr_currenttime();
                        (void)printf("%d bytes from %s, icmp_seq=%u", cc,
                            pr_addr(from, fromlen), seq);
                        (void)printf(" hlim=%d", hoplim);
@@ -1719,7 +1993,9 @@ pr_pack(buf, cc, mhdr)
                        dp = outpack + ICMP6ECHOLEN + ICMP6ECHOTMLEN;
                        for (i = 8; cp < end; ++i, ++cp, ++dp) {
                                if (*cp != *dp) {
-                                       (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", i, *dp, *cp);
+                                       (void)printf("\nwrong data byte #%d "
+                                           "should be 0x%x but was 0x%x",
+                                           i, *dp, *cp);
                                        break;
                                }
                        }
@@ -1730,15 +2006,15 @@ pr_pack(buf, cc, mhdr)
                if (TST(seq % mx_dup_ck)) {
                        ++nrepeats;
                        --nreceived;
-                       dupflag = 1;
                } else {
                        SET(seq % mx_dup_ck);
-                       dupflag = 0;
                }
 
                if (options & F_QUIET)
                        return;
 
+               if (options & F_PRTIME)
+                       pr_currenttime();
                (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen));
 
                switch (ntohs(ni->ni_code)) {
@@ -1825,7 +2101,8 @@ pr_pack(buf, cc, mhdr)
                                        putchar(')');
                                        goto fqdnend;
                                }
-                               ttl = (int32_t)ntohl(*(u_int32_t *)&buf[off+ICMP6ECHOLEN+8]);
+                               ttl = (int32_t)ntohl(*(u_int32_t *)
+                                   &buf[off+ICMP6ECHOLEN+8]);
                                if (comma)
                                        printf(",");
                                if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) {
@@ -1874,6 +2151,8 @@ pr_pack(buf, cc, mhdr)
                /* We've got something other than an ECHOREPLY */
                if (!(options & F_VERBOSE))
                        return;
+               if (options & F_PRTIME)
+                       pr_currenttime();
                (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen));
                pr_icmph(icp, end);
        }
@@ -1888,14 +2167,12 @@ pr_pack(buf, cc, mhdr)
 }
 
 void
-pr_exthdrs(mhdr)
-       struct msghdr *mhdr;
+pr_exthdrs(struct msghdr *mhdr)
 {
        ssize_t bufsize;
        void    *bufp;
        struct cmsghdr *cm;
 
-       bufsize = 0;
        bufp = mhdr->msg_control;
        for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
             cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
@@ -1904,7 +2181,7 @@ pr_exthdrs(mhdr)
 
                bufsize = CONTROLLEN - ((caddr_t)CMSG_DATA(cm) - (caddr_t)bufp);
                if (bufsize <= 0)
-                       continue; 
+                       continue;
                switch (cm->cmsg_type) {
                case IPV6_HOPOPTS:
                        printf("  HbH Options: ");
@@ -1932,7 +2209,7 @@ pr_ip6opt(void *extbuf, size_t bufsize)
        struct ip6_hbh *ext;
        int currentlen;
        u_int8_t type;
-       socklen_t extlen, len, origextlen;
+       socklen_t extlen, len;
        void *databuf;
        size_t offset;
        u_int16_t value2;
@@ -1948,7 +2225,6 @@ pr_ip6opt(void *extbuf, size_t bufsize)
         *     subtract the size of a cmsg structure from the buffer size.
         */
        if (bufsize < (extlen  + CMSG_SPACE(0))) {
-               origextlen = extlen;
                extlen = bufsize - CMSG_SPACE(0);
                warnx("options truncated, showing only %u (total=%u)",
                    (unsigned int)(extlen / 8 - 1),
@@ -1968,14 +2244,14 @@ pr_ip6opt(void *extbuf, size_t bufsize)
                 */
                case IP6OPT_JUMBO:
                        offset = 0;
-                       offset = inet6_opt_get_val(databuf, offset,
+                       (void) inet6_opt_get_val(databuf, offset,
                            &value4, sizeof(value4));
                        printf("    Jumbo Payload Opt: Length %u\n",
                            (u_int32_t)ntohl(value4));
                        break;
                case IP6OPT_ROUTER_ALERT:
                        offset = 0;
-                       offset = inet6_opt_get_val(databuf, offset,
+                       (void)inet6_opt_get_val(databuf, offset,
                                                   &value2, sizeof(value2));
                        printf("    Router Alert Opt: Type %u\n",
                            ntohs(value2));
@@ -2065,10 +2341,7 @@ pr_rthdr(void *extbuf, size_t bufsize __unused)
 #endif /* USE_RFC2292BIS */
 
 int
-pr_bitrange(v, soff, ii)
-       u_int32_t v;
-       int soff;
-       int ii;
+pr_bitrange(u_int32_t v, int soff, int ii)
 {
        int off;
        int i;
@@ -2114,9 +2387,8 @@ pr_bitrange(v, soff, ii)
 }
 
 void
-pr_suptypes(ni, nilen)
-       struct icmp6_nodeinfo *ni; /* ni->qtype must be SUPTYPES */
-       size_t nilen;
+pr_suptypes(struct icmp6_nodeinfo *ni, size_t nilen)
+       /* ni->qtype must be SUPTYPES */
 {
        size_t clen;
        u_int32_t v;
@@ -2125,7 +2397,7 @@ pr_suptypes(ni, nilen)
        struct cbit {
                u_int16_t words;        /*32bit count*/
                u_int16_t skip;
-       } cbit;
+       } cbit = { 0, 0 };
 #define MAXQTYPES      (1 << 16)
        size_t off;
        int b;
@@ -2181,9 +2453,8 @@ pr_suptypes(ni, nilen)
 }
 
 void
-pr_nodeaddr(ni, nilen)
-       struct icmp6_nodeinfo *ni; /* ni->qtype must be NODEADDR */
-       int nilen;
+pr_nodeaddr(struct icmp6_nodeinfo *ni, int nilen)
+       /* ni->qtype must be NODEADDR */
 {
        u_char *cp = (u_char *)(ni + 1);
        char ntop_buf[INET6_ADDRSTRLEN];
@@ -2248,8 +2519,7 @@ pr_nodeaddr(ni, nilen)
 }
 
 int
-get_hoplim(mhdr)
-       struct msghdr *mhdr;
+get_hoplim(struct msghdr *mhdr)
 {
        struct cmsghdr *cm;
 
@@ -2268,8 +2538,7 @@ get_hoplim(mhdr)
 }
 
 struct in6_pktinfo *
-get_rcvpktinfo(mhdr)
-       struct msghdr *mhdr;
+get_rcvpktinfo(struct msghdr *mhdr)
 {
        struct cmsghdr *cm;
 
@@ -2288,8 +2557,7 @@ get_rcvpktinfo(mhdr)
 }
 
 int
-get_pathmtu(mhdr)
-       struct msghdr *mhdr;
+get_pathmtu(struct msghdr *mhdr)
 {
 #ifdef IPV6_RECVPATHMTU
        struct cmsghdr *cm;
@@ -2367,21 +2635,20 @@ int
 get_so_traffic_class(struct msghdr *mhdr)
 {
        struct cmsghdr *cm;
-       
+
        for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
             cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
                if (cm->cmsg_len == 0)
                        return(-1);
-               
+
                if (cm->cmsg_level == SOL_SOCKET &&
                    cm->cmsg_type == SO_TRAFFIC_CLASS &&
                    cm->cmsg_len == CMSG_LEN(sizeof(int)))
                        return(*(int *)CMSG_DATA(cm));
        }
-       
+
        return(-1);
-}      
-       
+}
 
 /*
  * tvsub --
@@ -2389,8 +2656,7 @@ get_so_traffic_class(struct msghdr *mhdr)
  * be >= in.
  */
 void
-tvsub(out, in)
-       struct timeval *out, *in;
+tvsub(struct timeval *out, struct timeval *in)
 {
        if ((out->tv_usec -= in->tv_usec) < 0) {
                --out->tv_sec;
@@ -2405,11 +2671,27 @@ tvsub(out, in)
  */
 /* ARGSUSED */
 void
-onint(notused)
-       int notused;
+onint(int notused __unused)
 {
        summary();
 
+       if (res != NULL)
+               freeaddrinfo(res);
+
+        if (packet != NULL)
+                free(packet);
+
+       if (cm != NULL)
+               free(cm);
+
+       if (scmsg != NULL)
+               free(scmsg);
+
+#ifndef HAVE_POLL_H
+        if (fdmaskp != NULL)
+                free(fdmaskp);
+#endif
+
        (void)signal(SIGINT, SIG_DFL);
        (void)kill(getpid(), SIGINT);
 
@@ -2422,9 +2704,8 @@ onint(notused)
  *     Print out statistics.
  */
 void
-summary()
+summary(void)
 {
-
        (void)printf("\n--- %s ping6 statistics ---\n", hostname);
        (void)printf("%ld packets transmitted, ", ntransmitted);
        (void)printf("%ld packets received, ", nreceived);
@@ -2470,9 +2751,7 @@ static const char *nircode[] = {
  *     Print a descriptive string about an ICMP header.
  */
 void
-pr_icmph(icp, end)
-       struct icmp6_hdr *icp;
-       u_char *end;
+pr_icmph(struct icmp6_hdr *icp, u_char *end)
 {
        char ntop_buf[INET6_ADDRSTRLEN];
        struct nd_redirect *red;
@@ -2702,8 +2981,7 @@ pr_icmph(icp, end)
  *     Print an IP6 header.
  */
 void
-pr_iph(ip6)
-       struct ip6_hdr *ip6;
+pr_iph(struct ip6_hdr *ip6)
 {
        u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK;
        u_int8_t tc;
@@ -2731,9 +3009,7 @@ pr_iph(ip6)
  * a hostname.
  */
 const char *
-pr_addr(addr, addrlen)
-       struct sockaddr *addr;
-       int addrlen;
+pr_addr(struct sockaddr *addr, int addrlen)
 {
        static char buf[NI_MAXHOST];
        int flag = 0;
@@ -2752,9 +3028,7 @@ pr_addr(addr, addrlen)
  *     Dump some info on a returned (via ICMPv6) IPv6 packet.
  */
 void
-pr_retip(ip6, end)
-       struct ip6_hdr *ip6;
-       u_char *end;
+pr_retip(struct ip6_hdr *ip6, u_char *end)
 {
        u_char *cp = (u_char *)ip6, nh;
        int hlen;
@@ -2834,8 +3108,7 @@ pr_retip(ip6, end)
 }
 
 void
-fill(bp, patp)
-       char *bp, *patp;
+fill(char *bp, char *patp)
 {
        int ii, jj, kk;
        int pat[16];
@@ -2868,9 +3141,7 @@ fill(bp, patp)
 #ifdef IPSEC
 #ifdef IPSEC_POLICY_IPSEC
 int
-setpolicy(so, policy)
-       int so;
-       char *policy;
+setpolicy(int so __unused, char *policy)
 {
        char *buf;
 
@@ -2891,8 +3162,7 @@ setpolicy(so, policy)
 #endif
 
 char *
-nigroup(name)
-       char *name;
+nigroup(char *name)
 {
        char *p;
        char *q;
@@ -2935,15 +3205,172 @@ nigroup(name)
        return strdup(hbuf);
 }
 
+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
+str2tclass(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 traffic class 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);
+}
+
 void
-usage()
+usage(void)
 {
        (void)fprintf(stderr,
 #if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC)
            "A"
 #endif
            "usage: ping6 [-"
-           "d"
+           "Dd"
 #if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC)
            "E"
 #endif
@@ -2952,13 +3379,21 @@ usage()
            "m"
 #endif
            "nNoqrRtvwW] "
-           "[-a addrtype] [-b bufsiz] [-B boundif] [-c count]\n"
+           "[-a addrtype] [-b bufsiz] [-c count]\n"
            "             [-g gateway] [-h hoplimit] [-I interface] [-i wait] [-l preload]"
 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
            " [-P policy]"
 #endif
            "\n"
            "             [-p pattern] [-S sourceaddr] [-s packetsize] [-z tclass] "
+           "[-k traffic_class] [-K net_service_type] "
            "[hops ...] host\n");
+       (void)fprintf(stderr, "Apple specific options (to be specified before hops 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");
+       (void)fprintf(stderr, "            -apple-progress      # show progress for debugging\n");
        exit(1);
 }