/*
- * 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 */
#include <fcntl.h>
#include <math.h>
#include <signal.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
+#include <sysexits.h>
+#include <getopt.h>
#ifdef IPSEC
#include <netinet6/ah.h>
#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
#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
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 */
/* for ancillary data(advanced API) */
struct msghdr smsghdr;
-struct iovec smsgiov;
+struct iovec smsgiov[2];
char *scmsg = NULL;
volatile sig_atomic_t seenalrm;
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 *);
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
#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));
#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':
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;
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;
case 'p': /* fill buffer with user pattern */
options |= F_PINGFILLED;
fill((char *)datap, optarg);
- break;
+ break;
case 'q':
options |= F_QUIET;
break;
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
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*/
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;
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;
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;
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) {
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)) {
/*
#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)
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
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);
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)
/* 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
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));
void
onsignal(int sig)
{
-
+ fflush(stdout);
+
switch (sig) {
case SIGALRM:
seenalrm++;
{
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
pinger(void)
{
struct icmp6_hdr *icp;
- struct iovec iov[2];
int i, cc;
struct icmp6_nodeinfo *nip;
int seq;
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));
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;
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);
(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);
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;
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)) {
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);
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)) {
/* 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);
}
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)) {
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;
* 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),
*/
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));
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;
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)
{
"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);
}