]> 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 419552b44986187b0c2d8281aba5e2b53ce31d8a..c5b0785cdef74e86471d4e84fb1c49f3ed9a365b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
  * 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 */
@@ -141,6 +143,7 @@ static const char copyright[] =
 #include <fcntl.h>
 #include <math.h>
 #include <signal.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -148,6 +151,8 @@ static const char copyright[] =
 #ifdef HAVE_POLL_H
 #include <poll.h>
 #endif
+#include <sysexits.h>
+#include <getopt.h>
 
 #ifdef IPSEC
 #include <netinet6/ah.h>
@@ -186,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
@@ -208,9 +214,23 @@ struct tv32 {
 #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
@@ -261,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 */
@@ -274,7 +299,7 @@ u_short naflags;
 
 /* for ancillary data(advanced API) */
 struct msghdr smsghdr;
-struct iovec smsgiov;
+struct iovec smsgiov[2];
 char *scmsg = NULL;
 
 volatile sig_atomic_t seenalrm;
@@ -285,8 +310,14 @@ volatile sig_atomic_t seeninfo;
 
 int rcvtclass = 0;
 
-int how_so_traffic_class = 0;
+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 *);
@@ -319,6 +350,9 @@ 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
@@ -361,6 +395,8 @@ main(int argc, char *argv[])
 #endif
        /* 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));
@@ -377,8 +413,9 @@ main(int argc, char *argv[])
 #define ADDOPTS        "AE"
 #endif /*IPSEC_POLICY_IPSEC*/
 #endif
-       while ((ch = getopt(argc, argv,
-           "a:b:B:Cc:DdfHg: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':
@@ -467,6 +504,66 @@ main(int argc, char *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;
@@ -506,10 +603,31 @@ main(int argc, char *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;
@@ -539,7 +657,7 @@ main(int argc, char *argv[])
                case 'p':               /* fill buffer with user pattern */
                        options |= F_PINGFILLED;
                        fill((char *)datap, optarg);
-                               break;
+                       break;
                case 'q':
                        options |= F_QUIET;
                        break;
@@ -597,13 +715,9 @@ main(int argc, char *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
@@ -628,6 +742,20 @@ main(int argc, char *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*/
@@ -637,6 +765,12 @@ main(int argc, char *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;
 
@@ -780,17 +914,32 @@ main(int argc, char *argv[])
        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;
@@ -798,10 +947,10 @@ main(int argc, char *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;
@@ -952,17 +1101,29 @@ main(int argc, char *argv[])
        if (tclass != -2)
                ip6optlen += CMSG_SPACE(sizeof(int));
 
-       if (how_so_traffic_class < 2 && so_traffic_class >= 0) {
-               (void) setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS,
-                   (void *)&so_traffic_class, sizeof (so_traffic_class));
+       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 (how_so_traffic_class > 0) {
+       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) {
@@ -1075,13 +1236,21 @@ main(int argc, char *argv[])
 
                scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
        }
-       if (how_so_traffic_class > 1 && so_traffic_class >= 0) {
-               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;
+       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);
+                       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)) {
                /*
@@ -1149,7 +1318,7 @@ main(int argc, char *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)
@@ -1159,7 +1328,7 @@ main(int argc, char *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
@@ -1196,21 +1365,42 @@ main(int argc, char *argv[])
                    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);
@@ -1218,17 +1408,20 @@ main(int argc, char *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)
@@ -1240,28 +1433,32 @@ main(int argc, char *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
@@ -1295,9 +1492,9 @@ main(int argc, char *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));
@@ -1371,7 +1568,8 @@ main(int argc, char *argv[])
 void
 onsignal(int sig)
 {
-
+       fflush(stdout);
+       
        switch (sig) {
        case SIGALRM:
                seenalrm++;
@@ -1396,9 +1594,9 @@ 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
@@ -1450,7 +1648,6 @@ int
 pinger(void)
 {
        struct icmp6_hdr *icp;
-       struct iovec iov[2];
        int i, cc;
        struct icmp6_nodeinfo *nip;
        int seq;
@@ -1458,6 +1655,13 @@ pinger(void)
        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));
@@ -1523,6 +1727,11 @@ pinger(void)
                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;
@@ -1539,12 +1748,17 @@ pinger(void)
                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);
@@ -1555,6 +1769,7 @@ pinger(void)
                (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);
 
@@ -1586,7 +1801,7 @@ 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;
@@ -1708,7 +1923,7 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
                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)) {
@@ -1746,6 +1961,8 @@ pr_pack(u_char *buf, int cc, struct msghdr *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);
@@ -1789,15 +2006,15 @@ pr_pack(u_char *buf, int cc, struct msghdr *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)) {
@@ -1934,6 +2151,8 @@ pr_pack(u_char *buf, int cc, struct msghdr *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);
        }
@@ -1954,7 +2173,6 @@ pr_exthdrs(struct msghdr *mhdr)
        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)) {
@@ -1991,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;
@@ -2007,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),
@@ -2027,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));
@@ -2180,7 +2397,7 @@ pr_suptypes(struct icmp6_nodeinfo *ni, size_t 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;
@@ -2988,6 +3205,163 @@ nigroup(char *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(void)
 {
@@ -3005,13 +3379,21 @@ usage(void)
            "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);
 }