]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[1960] Removed old perfdhcp.
authorMarcin Siodelski <marcin@isc.org>
Fri, 14 Sep 2012 11:02:25 +0000 (13:02 +0200)
committerMarcin Siodelski <marcin@isc.org>
Fri, 14 Sep 2012 11:02:25 +0000 (13:02 +0200)
tests/tools/perfdhcp/Makefile.am
tests/tools/perfdhcp/perfdhcp.c [deleted file]

index 0532f27dcc205fa441d2ef69b6a8029231f4870e..cefd29851b4a6a88dc169ebbd566e0544ed50641 100644 (file)
@@ -18,27 +18,24 @@ if USE_STATIC_LINK
 AM_LDFLAGS += -static
 endif
 
-pkglibexec_PROGRAMS = perfdhcp2
-perfdhcp2_SOURCES = main.cc
-perfdhcp2_SOURCES += command_options.cc command_options.h
-perfdhcp2_SOURCES += localized_option.h
-perfdhcp2_SOURCES += perf_pkt6.cc perf_pkt6.h
-perfdhcp2_SOURCES += perf_pkt4.cc perf_pkt4.h
-perfdhcp2_SOURCES += pkt_transform.cc pkt_transform.h
-perfdhcp2_SOURCES += stats_mgr.h
-perfdhcp2_SOURCES += test_control.cc test_control.h
+pkglibexec_PROGRAMS = perfdhcp
+perfdhcp_SOURCES = main.cc
+perfdhcp_SOURCES += command_options.cc command_options.h
+perfdhcp_SOURCES += localized_option.h
+perfdhcp_SOURCES += perf_pkt6.cc perf_pkt6.h
+perfdhcp_SOURCES += perf_pkt4.cc perf_pkt4.h
+perfdhcp_SOURCES += pkt_transform.cc pkt_transform.h
+perfdhcp_SOURCES += stats_mgr.h
+perfdhcp_SOURCES += test_control.cc test_control.h
 libb10_perfdhcp___la_CXXFLAGS = $(AM_CXXFLAGS)
 
-perfdhcp2_CXXFLAGS = $(AM_CXXFLAGS)
+perfdhcp_CXXFLAGS = $(AM_CXXFLAGS)
 if USE_CLANGPP
 # Disable unused parameter warning caused by some of the
 # Boost headers when compiling with clang.
-perfdhcp2_CXXFLAGS += -Wno-unused-parameter
+perfdhcp_CXXFLAGS += -Wno-unused-parameter
 endif
 
-perfdhcp2_LDADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
-perfdhcp2_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
-perfdhcp2_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
-
-#pkglibexec_PROGRAMS  = perfdhcp
-#perfdhcp_SOURCES  = perfdhcp.c
+perfdhcp_LDADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+perfdhcp_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+perfdhcp_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
diff --git a/tests/tools/perfdhcp/perfdhcp.c b/tests/tools/perfdhcp/perfdhcp.c
deleted file mode 100644 (file)
index 3ab9a2e..0000000
+++ /dev/null
@@ -1,3559 +0,0 @@
-/*
- * Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <config.h>
-
-#ifndef HAVE_GETIFADDRS
-
-/*
- * Solaris 10 does not have the getifaddrs() function available (although it
- * is present on Solaris 11 and later).  For the present we will not implement
- * a replacement (as we do with clock_gettime) as the implementation is
- * relatively complex.  Just output a message saying that the utility is not
- * supported on this operating system.
- */
-
-#include <stdio.h>
-
-int
-main(const int argc, char* const argv[])
-{
-    fprintf(stderr, "perfdhcp is not supported on this version of the operating system\n");
-    return (1);
-}
-
-#else
-
-/* getifaddrs() present, so the code should compile */
-
-#ifdef __linux__
-#define _GNU_SOURCE
-#endif
-
-#include <sys/types.h>
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-
-#include <net/if.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <ifaddrs.h>
-#include <math.h>
-#include <netdb.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#ifndef HAVE_PSELECT
-
-#include <assert.h>
-
-/* Platforms such as OpenBSD don't provide a pselect(), so we use our
-   own implementation for this testcase, which wraps around select() and
-   hence doesn't implement the high precision timer. This implementation
-   is fine for our purpose. */
-
-static int
-pselect (int nfds, fd_set *readfds, fd_set *writefds,
-         fd_set *exceptfds, const struct timespec *timeout,
-         const sigset_t *sigmask)
-{
-       struct timeval my_timeout;
-
-       /* Our particular usage of pselect() doesn't use these fields. */
-       assert(writefds == NULL);
-       assert(exceptfds == NULL);
-       assert(sigmask == NULL);
-
-       my_timeout.tv_sec = timeout->tv_sec;
-       my_timeout.tv_usec = timeout->tv_nsec / 1000;
-
-       return (select(nfds, readfds, writefds, exceptfds, &my_timeout));
-}
-
-#endif /* !HAVE_PSELECT */
-
-/* DHCPv4 defines (to be moved/shared) */
-
-#define DHCP_OFF_OPCODE                0
-#define DHCP_OFF_HTYPE         1
-#define DHCP_OFF_HLEN          2
-#define DHCP_OFF_HOPS          3
-#define DHCP_OFF_XID           4
-#define DHCP_OFF_SECS          8
-#define DHCP_OFF_FLAGS         10
-#define DHCP_OFF_CIADDR                12
-#define DHCP_OFF_YIADDR                16
-#define DHCP_OFF_SADDR         20
-#define DHCP_OFF_GIADDR                24
-#define DHCP_OFF_CHADDR                28
-#define DHCP_OFF_SNAME         44
-#define DHCP_OFF_FILE          108
-#define DHCP_OFF_COOKIE                236
-#define DHCP_OFF_OPTIONS       240
-
-#define BOOTP_OP_REQUEST       1
-#define BOOTP_OP_REPLY         2
-#define BOOTP_MIN_LEN          300
-
-#define DHCP_OP_DISCOVER       1
-#define DHCP_OP_OFFER          2
-#define DHCP_OP_REQUEST                3
-#define DHCP_OP_DECLINE                4
-#define DHCP_OP_ACK            5
-#define DHCP_OP_NAK            6
-#define DHCP_OP_RELEASE                7
-#define DHCP_OP_INFORM         8
-
-#define DHCP_HTYPE_ETHER       1
-
-#define DHCP_OPT_PAD           0
-#define DHCP_OPT_SUBNET_MASK   1
-#define DHCP_OPT_TIME_OFFSET   2
-#define DHCP_OPT_ROUTERS       3
-#define DHCP_OPT_DNS_SERVERS   6
-#define DHCP_OPT_HOST_NAME     12
-#define DHCP_OPT_DOMAIN_NAME   15
-#define DHCP_OPT_BROADCAST     28
-#define DHCP_OPT_DHCP_ADDRESS  50
-#define DHCP_OPT_DHCP_LEASE    51
-#define DHCP_OPT_DHCP_MSGTYPE  53
-#define DHCP_OPT_DHCP_SRVID    54
-#define DHCP_OPT_DHCP_PRL      55
-#define DHCP_OPT_END           255
-
-#define DHCP_OPTLEN_SRVID      6
-
-/* DHCPv6 defines  (to be moved/shared) */
-
-#define DHCP6_OFF_MSGTYP       0
-#define DHCP6_OFF_XID          1
-#define DHCP6_OFF_OPTIONS      4
-
-#define DHCP6_OP_SOLICIT       1
-#define DHCP6_OP_ADVERTISE     2
-#define DHCP6_OP_REQUEST       3
-#define DHCP6_OP_REPLY         7
-
-#define DHCP6_OPT_CLIENTID     1
-#define DHCP6_OPT_SERVERID     2
-#define DHCP6_OPT_IA_NA                3
-#define DHCP6_OPT_ORO          6
-#define DHCP6_OPT_ELAPSED_TIME 8
-#define DHCP6_OPT_STATUS_CODE  13
-#define DHCP6_OPT_RAPID_COMMIT 14
-#define DHCP6_OPT_NAME_SERVERS 23
-#define DHCP6_OPT_DOMAIN_SEARCH        24
-
-#define DHCP6_ST_SUCCESS       0
-#define DHCP6_ST_NOADDRSAVAIL  2
-
-#define DHCP6_DUID_LLT         1
-#define DHCP6_DUID_EPOCH       946684800
-
-/* tail queue macros (from FreeBSD 8.2 /sys/sys/queue.h, to be moved/shared) */
-
-#define ISC_TAILQ_HEAD(name, type)                                     \
-struct name {                                                          \
-       struct type *tqh_first;                                         \
-       struct type **tqh_last;                                         \
-}
-
-#define ISC_TAILQ_ENTRY(type)                                          \
-struct {                                                               \
-       struct type *tqe_next;                                          \
-       struct type **tqe_prev;                                         \
-}
-
-#define ISC_TAILQ_EMPTY(head)  ((head)->tqh_first == NULL)
-
-#define ISC_TAILQ_FIRST(head)  ((head)->tqh_first)
-
-#define ISC_TAILQ_LAST(head, headname)                                 \
-       (*(((struct headname *)((head)->tqh_last))->tqh_last))
-
-#define ISC_TAILQ_NEXT(elm, field)     ((elm)->field.tqe_next)
-
-#define ISC_TAILQ_PREV(elm, headname, field)                           \
-       (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
-
-#define ISC_TAILQ_INIT(head)   do {                                    \
-       ISC_TAILQ_FIRST((head)) = NULL;                                 \
-       (head)->tqh_last = &ISC_TAILQ_FIRST((head));                    \
-} while (0)
-
-#define ISC_TAILQ_INSERT_HEAD(head, elm, field)        do {                    \
-       ISC_TAILQ_NEXT((elm), field) = ISC_TAILQ_FIRST((head));         \
-       if (!ISC_TAILQ_EMPTY((head)))                                   \
-               ISC_TAILQ_FIRST((head))->field.tqe_prev =               \
-                       &ISC_TAILQ_NEXT((elm), field);                  \
-       else                                                            \
-               (head)->tqh_last = &ISC_TAILQ_NEXT((elm), field);       \
-       ISC_TAILQ_FIRST((head)) = (elm);                                \
-       (elm)->field.tqe_prev = &ISC_TAILQ_FIRST((head));               \
-} while (0)
-
-#define ISC_TAILQ_INSERT_TAIL(head, elm, field)        do {                    \
-       ISC_TAILQ_NEXT((elm), field) = NULL;                            \
-       (elm)->field.tqe_prev = (head)->tqh_last;                       \
-       *(head)->tqh_last = (elm);                                      \
-       (head)->tqh_last = &ISC_TAILQ_NEXT((elm), field);               \
-} while (0)
-
-#define ISC_TAILQ_REMOVE(head, elm, field)     do {                    \
-       if ((ISC_TAILQ_NEXT((elm), field)) != NULL)                     \
-               ISC_TAILQ_NEXT((elm), field)->field.tqe_prev =          \
-                       (elm)->field.tqe_prev;                          \
-       else                                                            \
-               (head)->tqh_last = (elm)->field.tqe_prev;               \
-       *(elm)->field.tqe_prev = ISC_TAILQ_NEXT((elm), field);          \
-} while (0)
-
-#define ISC_TAILQ_FOREACH(var, head, field)                            \
-       for ((var) = ISC_TAILQ_FIRST((head));                           \
-            (var);                                                     \
-            (var) = ISC_TAILQ_NEXT((var), field))
-
-#define ISC_TAILQ_FOREACH_SAFE(var, head, field, tvar)                 \
-       for ((var) = ISC_TAILQ_FIRST((head));                           \
-            (var) && ((tvar) = ISC_TAILQ_NEXT((var), field), 1);       \
-            (var) = (tvar))
-
-/*
- * Data structures
- */
-
-/*
- * exchange:
- *    - per exchange values:
- *     * order (for debugging)
- *     * xid (even/odd for 4 packet exchanges)
- *     * random (for debugging)
- *     * time-stamps
- *     * server ID (for 3rd packet)
- *     * IA_NA (for IPv6 3rd packet)
- *
- * sent/rcvd global chains, "next to be received" on entry cache,
- * and hash table for xid -> data structure fast matching
- * (using the assumption collisions are unlikely, cf birthday problem)
- */
-
-struct exchange {                              /* per exchange structure */
-       ISC_TAILQ_ENTRY(exchange) gchain;       /* global chaining */
-       ISC_TAILQ_ENTRY(exchange) hchain;       /* hash table chaining */
-       uint64_t order0, order2;                /* number of this exchange */
-       uint32_t xid;                           /* transaction ID */
-       uint32_t rnd;                           /* random part */
-       struct timespec ts0, ts1, ts2, ts3;     /* timespecs */
-       uint8_t *sid;                           /* server ID */
-       size_t sidlen;                          /* server ID length */
-       uint8_t *iana;                          /* (IPv6) IA_NA */
-       size_t ianalen;                         /* (IPv6) IA_NA length */
-};
-struct exchange *xnext0, *xnext2;              /* next to be received */
-ISC_TAILQ_HEAD(xlist, exchange);               /* exchange list */
-struct xlist xsent0, xsent2, xrcvd0, xrcvd2;   /* sent and received lists */
-uint64_t xscount0, xscount2;                   /* sent counters */
-uint64_t xrcount0, xrcount2;                   /* received counters */
-caddr_t exchanges0, exchanges2;                        /* hash tables */
-uint32_t hashsize0, hashsize2;                 /* hash table sizes */
-
-/*
- * statictics counters and accumulators
- */
-
-uint64_t tooshort, orphans, locallimit;                /* error counters */
-uint64_t latesent, compsend, latercvd;         /* rate stats */
-uint64_t multrcvd, shortwait, collected[2];    /* rate stats (cont) */
-double dmin0 = 999999999., dmin2 = 999999999.; /* minimum delays */
-double dmax0 = 0., dmax2 = 0.;                 /* maximum delays */
-double dsum0 = 0., dsum2 = 0.;                 /* delay sums */
-double dsumsq0 = 0., dsumsq2 = 0.;             /* square delay sums */
-
-/*
- * command line parameters
- */
-
-int ipversion = 0;                     /* IP version */
-int simple;                            /* DO/SA in place of DORR/SARR */
-int rate;                              /* rate in exchange per second */
-int report;                            /* delay between two reports */
-uint32_t range;                                /* randomization range */
-uint32_t maxrandom;                    /* maximum random value */
-int basecnt;                           /* base count */
-char *base[4];                         /* bases */
-int gotnumreq;                         /* numreq[0] was set */
-int numreq[2];                         /* number of exchange */
-int period;                            /* test period */
-int gotlosttime;                       /* losttime[0] was set */
-double losttime[2] = {1., 1.};         /* time after a request is lost  */
-int gotmaxdrop;                                /* max{p}drop[0] was set */
-int maxdrop[2];                                /* maximum number of lost requests */
-double maxpdrop[2] = { 0., 0.};                /* maximum percentage */
-char *localname;                       /* local address or interface */
-int isinterface;                       /* interface vs local address */
-int preload;                           /* preload exchanges */
-int aggressivity = 1;                  /* back to back exchanges */
-int localport;                         /* local port number (host endian) */
-int seeded;                            /* is a seed provided */
-unsigned int seed;                     /* randomization seed */
-int isbroadcast;                       /* use broadcast */
-int rapidcommit;                       /* add rapid commit option */
-int usefirst;                          /* where to take the server-ID */
-char *templatefile[2];                 /* template file name */
-int xidoffset[2] = {-1, -1};           /* template offsets (xid)*/
-int rndoffset[2] = {-1, -1};           /* template offsets (random) */
-int elpoffset = -1;                    /* template offset (elapsed time) */
-int sidoffset = -1;                    /* template offset (server ID) */
-int ripoffset = -1;                    /* template offset (requested IP) */
-char *diags;                           /* diagnostic selectors */
-char *wrapped;                         /* wrapped command */
-char *servername;                      /* server */
-
-/*
- * global variables
- */
-
-struct sockaddr_storage localaddr;     /* local socket address */
-struct sockaddr_storage serveraddr;    /* server socket address */
-
-int sock;                              /* socket descriptor */
-int interrupted, fatal;                        /* to finish flags */
-
-uint8_t obuf[4096], ibuf[4096];                /* I/O buffers */
-char tbuf[8200];                       /* template buffer */
-
-struct timespec boot;                  /* the date of boot */
-struct timespec last;                  /* the date of last send */
-struct timespec due;                   /* the date of next send */
-struct timespec dreport;               /* the date of next reporting */
-struct timespec finished;              /* the date of finish */
-
-uint8_t *gsrvid;                       /* global server id */
-size_t gsrvidlen;                      /*  and its length */
-uint8_t gsrvidbuf[64];                 /*  and its storage */
-
-/* MAC address */
-uint8_t mac_prefix[6] = { 0x00, 0x0c, 0x01, 0x02, 0x03, 0x04 };
-
-/* DUID prefix */
-uint8_t *duid_prefix;
-int duid_length;
-
-/* magic cookie for BOOTP/DHCPv4 */
-uint8_t dhcp_cookie[4] = { 0x63, 0x82, 0x53, 0x63 };
-
-/*
- * templates
- *
- * note: the only hard point is what are the offsets:
- *   - xid_discover4 and xid_request4: first of the 4 octet long
- *     transaction ID (default DHCP_OFF_XID = 4)
- *   - random_discover4 and random_request4: last of the 6 octet long
- *     MAC address (default DHCP_OFF_CHADDR + 6 = 28 + 6)
- *   - elapsed_request4: first of the 2 octet long secs field
- *     (default DHCP_OFF_SECS = 8, 0 means disabled)
- *   - serverid_request4: first of the 6 octet long server ID option
- *     (no default, required)
- *   - reqaddr_request4: first of the 4 octet long requested IP address
- *     option content (i.e., the address itself, btw OFFER yiaddr)
- *     (no default, required)
- *   - xid_solicit6 and xid_request6: first of the 3 octet long
- *     transaction ID (default DHCP6_OFF_XID = 1)
- *   - random_solicit6 and random_request6: last of the DUID in the
- *     client ID option (no default, required when rate is set)
- *   - elapsed_request6: first of the 2 octet long content of
- *     the option elapsed time option (no default, 0 means disabled)
- *   - serverid_request6: position where the variable length server ID
- *     option is inserted (no default, required, set to length means append)
- *   - reqaddr_request6: position where of the variable length requested
- *     IP address option is inserted (no default, required, set to
- *     length means append)
- */
-
-size_t length_discover4;
-uint8_t template_discover4[4096];
-size_t xid_discover4;
-size_t random_discover4;
-size_t length_request4;
-uint8_t template_request4[4096];
-size_t xid_request4;
-size_t elapsed_request4;
-size_t random_request4;
-size_t serverid_request4;
-size_t reqaddr_request4;
-size_t length_solicit6;
-uint8_t template_solicit6[4096];
-size_t xid_solicit6;
-size_t random_solicit6;
-size_t length_request6;
-uint8_t template_request6[4096];
-size_t xid_request6;
-size_t elapsed_request6;
-size_t random_request6;
-size_t serverid_request6;
-size_t reqaddr_request6;
-
-
-// use definition of CLOCK_REALTIME (or lack of thereof) as an indicator
-// if the code is being compiled or Linux (or somewhere else)
-// Perhaps this should be based on OS_LINUX define?
-
-#if !defined (CLOCK_REALTIME)
-#define CLOCK_REALTIME 0
-
-/// @brief clock_gettime implementation for non-Linux systems
-///
-/// This implementation lacks nanosecond resolution. It is intended
-/// to be used on non-Linux systems that does not provide clock_gettime
-/// implementation.
-///
-/// @param clockid ignored (kept for Linux prototype compatibility)
-/// @param tp timespec structure
-///
-/// @return always zero (kept for compatibility reasons)
-int clock_gettime(int clockid, struct timespec *tp) {
-
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    tp->tv_sec = tv.tv_sec;
-    tp->tv_nsec = tv.tv_usec*1000;
-
-    return (0);
-}
-
-#endif
-
-/*
- * initialize data structures handling exchanges
- */
-
-void
-inits(void)
-{
-       struct xlist *bucket;
-       caddr_t p;
-       size_t len, i;
-
-       ISC_TAILQ_INIT(&xsent0);
-       ISC_TAILQ_INIT(&xsent2);
-       ISC_TAILQ_INIT(&xrcvd0);
-       ISC_TAILQ_INIT(&xrcvd2);
-
-       /// compute hashsizes
-       hashsize0 = 1024;
-       len = sizeof(*bucket) * hashsize0;
-       exchanges0 = malloc(len);
-       if (exchanges0 == NULL) {
-               perror("malloc(exchanges0)");
-               exit(1);
-       }
-       for (i = 0, p = exchanges0; i < hashsize0; i++, p += sizeof(*bucket)) {
-               bucket = (struct xlist *) p;
-               ISC_TAILQ_INIT(bucket);
-       }
-       if (simple != 0)
-               return;
-       hashsize2 = 1024;
-       len = sizeof(*bucket) * hashsize2;
-       exchanges2 = malloc(len);
-       if (exchanges2 == NULL) {
-               perror("malloc(exchanges2)");
-               exit(1);
-       }
-       for (i = 0, p = exchanges2; i < hashsize2; i++, p += sizeof(*bucket)) {
-               bucket = (struct xlist *) p;
-               ISC_TAILQ_INIT(bucket);
-       }
-}
-
-/*
- * randomize the value of the given field:
- *   - offset of the field
- *   - random seed (used as it when suitable)
- *   - returns the random value which was used
- */
-
-uint32_t
-randomize(size_t offset, uint32_t r)
-{
-       uint32_t v;
-
-       if (range == 0)
-               return 0;
-       if (range == UINT32_MAX)
-               return r;
-       if (maxrandom != 0)
-               while (r >= maxrandom)
-                       r = (uint32_t) random();
-       r %= range + 1;
-       v = r;
-       v += obuf[offset];
-       obuf[offset] = v;
-       if (v < 256)
-               return r;
-       v >>= 8;
-       v += obuf[offset - 1];
-       obuf[offset - 1] = v;
-       if (v < 256)
-               return r;
-       v >>= 8;
-       v += obuf[offset - 2];
-       obuf[offset - 2] = v;
-       if (v < 256)
-               return r;
-       v >>= 8;
-       v += obuf[offset - 3];
-       obuf[offset - 3] = v;
-       return r;
-}
-
-/*
- * receive a reply (4th packet), shared between IPv4 and IPv6:
- *   - transaction ID xid
- *   - receiving time-stamp now
- * called from receive[46]() when the xid is odd
- */
-
-void
-receive_reply(uint32_t xid, struct timespec *now)
-{
-       struct exchange *x, *t;
-       struct xlist *bucket;
-       uint32_t hash;
-       int checklost;
-       double delta;
-
-       /* bucket is needed even when the next cache matches */
-       hash = (xid >> 1) & (hashsize2 - 1);
-       bucket = (struct xlist *) (exchanges2 + hash * sizeof(*bucket));
-       /* try the 'next to be received' cache */
-       if ((xnext2 != NULL) && (xnext2->xid == xid)) {
-               x = xnext2;
-               goto found;
-       }
-       /* usually the lost probability is low for request/reply */
-       checklost = 1;
-       /* look for the exchange */
-       ISC_TAILQ_FOREACH_SAFE(x, bucket, hchain, t) {
-               double waited;
-
-               if (x->xid == xid)
-                       goto found;
-               if (checklost <= 0)
-                       continue;
-               checklost = 0;
-               /* check for a timed-out exchange */
-               waited = now->tv_sec - x->ts2.tv_sec;
-               waited += (now->tv_nsec - x->ts2.tv_nsec) / 1e9;
-               if (waited < losttime[1])
-                       continue;
-               /* garbage collect timed-out exchange */
-               ISC_TAILQ_REMOVE(bucket, x, hchain);
-               ISC_TAILQ_REMOVE(&xsent2, x, gchain);
-               free(x);
-               collected[1] += 1;
-       }
-       /* no match? very late or not for us */
-       orphans++;
-       return;
-
-       /* got it: update stats and move to the received queue */
-    found:
-       xrcount2++;
-       x->ts3 = *now;
-       delta = x->ts3.tv_sec - x->ts2.tv_sec;
-       delta += (x->ts3.tv_nsec - x->ts2.tv_nsec) / 1e9;
-       if (delta < dmin2)
-               dmin2 = delta;
-       if (delta > dmax2)
-               dmax2 = delta;
-       dsum2 += delta;
-       dsumsq2 += delta * delta;
-       xnext2 = ISC_TAILQ_NEXT(x, gchain);
-       ISC_TAILQ_REMOVE(bucket, x, hchain);
-       ISC_TAILQ_REMOVE(&xsent2, x, gchain);
-       ISC_TAILQ_INSERT_TAIL(&xrcvd2, x, gchain);
-}
-
-/*
- * get the DHCPv4 socket descriptor
- * (the only complexity is broadcast enabling: there is no easy way to
- *  recognize broadcast addresses, so the command line -B flag)
- */
-
-void
-getsock4(void)
-{
-       int ret;
-
-       /* update local port */
-       if (localport != 0) {
-               uint16_t lp = htons((uint16_t) localport);
-
-               ((struct sockaddr_in *) &localaddr)->sin_port = lp;
-       }
-       sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
-       if (sock < 0) {
-               perror("socket");
-               exit(1);
-       }
-       ret = bind(sock,
-                  (struct sockaddr *) &localaddr,
-                  sizeof(struct sockaddr_in));
-       if (ret < 0) {
-               perror("bind");
-               exit(1);
-       }
-       /* enable broadcast if needed or required */
-       if (isbroadcast != 0) {
-               int on = 1;
-
-               ret = setsockopt(sock,
-                                SOL_SOCKET, SO_BROADCAST,
-                                &on, sizeof(on));
-               if (ret < 0) {
-                       perror("setsockopt(SO_BROADCAST)");
-                       exit(1);
-               }
-       }
-}
-
-/*
- * build a DHCPv4 DISCOVER from a relay template
- * (implicit parameters are the local (giaddr) and MAC addresses (chaddr))
- * (assume the link is Ethernet)
- */
-
-void
-build_template_discover4(void)
-{
-       uint8_t *p = template_discover4;
-
-       length_discover4 = BOOTP_MIN_LEN;
-       xid_discover4 = DHCP_OFF_XID;
-       random_discover4 = DHCP_OFF_CHADDR + 6;
-       /* opcode */
-       p[DHCP_OFF_OPCODE] = BOOTP_OP_REQUEST;
-       /* hardware address type */
-       p[DHCP_OFF_HTYPE] = DHCP_HTYPE_ETHER;
-       /* hardware address length */
-       p[DHCP_OFF_HLEN] = 6;
-       /* hops */
-       p[DHCP_OFF_HOPS] = 1;
-       /* gateway address */
-       memcpy(p + DHCP_OFF_GIADDR,
-              &((struct sockaddr_in *) &localaddr)->sin_addr,
-              4);
-       /* hardware address */
-       memcpy(p + DHCP_OFF_CHADDR, mac_prefix, 6);
-       /* cookie */
-       memcpy(p + DHCP_OFF_COOKIE, dhcp_cookie, 4);
-       /* options */
-       p += DHCP_OFF_OPTIONS;
-       /* inline DHCP message type */
-       *p++ = DHCP_OPT_DHCP_MSGTYPE;
-       *p++ = 1;
-       *p++ = DHCP_OP_DISCOVER;
-       /* inline DHCP parameter request list (default) */
-       *p++ = DHCP_OPT_DHCP_PRL;
-       *p++ = 7;
-       *p++ = DHCP_OPT_SUBNET_MASK;
-       *p++ = DHCP_OPT_BROADCAST;
-       *p++ = DHCP_OPT_TIME_OFFSET;
-       *p++ = DHCP_OPT_ROUTERS;
-       *p++ = DHCP_OPT_DOMAIN_NAME;
-       *p++ = DHCP_OPT_DNS_SERVERS;
-       *p++ = DHCP_OPT_HOST_NAME;
-       /* end */
-       *p = DHCP_OPT_END;
-}
-
-/*
- * get a DHCPv4 client/relay first packet (usually a DISCOVER) template
- * from the file given in the command line (-T<template-file>)
- * and xid/rnd offsets (-X<xid-offset> and -O<random-offset>)
- */
-
-void
-get_template_discover4(void)
-{
-       uint8_t *p = template_discover4;
-       int fd, cc, i, j;
-
-       fd = open(templatefile[0], O_RDONLY);
-       if (fd < 0) {
-               fprintf(stderr, "open(%s): %s\n",
-                       templatefile[0], strerror(errno));
-               exit(2);
-       }
-       cc = read(fd, tbuf, sizeof(tbuf));
-       (void) close(fd);
-       if (cc < 0) {
-               fprintf(stderr, "read(%s): %s\n",
-                       templatefile[0], strerror(errno));
-               exit(1);
-       }
-       if (cc < 100) {
-               fprintf(stderr, "file '%s' too short\n", templatefile[0]);
-               exit(2);
-       }
-       if (cc > 8193) {
-               fprintf(stderr,"file '%s' too large\n", templatefile[0]);
-               exit(2);
-       }
-       j = 0;
-       for (i = 0; i < cc; i++) {
-               if (isspace((int) tbuf[i]))
-                       continue;
-               if (!isxdigit((int) tbuf[i])) {
-                       fprintf(stderr,
-                               "illegal char[%d]='%c' in file '%s'\n",
-                               i, (int) tbuf[i], templatefile[0]);
-                       exit(2);
-               }
-               tbuf[j] = tbuf[i];
-               j++;
-       }
-       cc = j;
-       if ((cc & 1) != 0) {
-               fprintf(stderr,
-                       "odd number of hexadecimal digits in file '%s'\n",
-                       templatefile[0]);
-               exit(2);
-       }
-       length_discover4 = cc >> 1;
-       for (i = 0; i < cc; i += 2)
-               (void) sscanf(tbuf + i, "%02hhx", &p[i >> 1]);
-       if (xidoffset[0] >= 0)
-               xid_discover4 = (size_t) xidoffset[0];
-       else
-               xid_discover4 = DHCP_OFF_XID;
-       if (xid_discover4 + 4 > length_discover4) {
-               fprintf(stderr,
-                       "xid (at %zu) outside the template (length %zu)?\n",
-                       xid_discover4, length_discover4);
-               exit(2);
-       }
-       if (rndoffset[0] >= 0)
-               random_discover4 = (size_t) rndoffset[0];
-       else
-               random_discover4 = DHCP_OFF_CHADDR + 6;
-       if (random_discover4 > length_discover4) {
-               fprintf(stderr,
-                       "random (at %zu) outside the template (length %zu)?\n",
-                       random_discover4, length_discover4);
-               exit(2);
-       }
-}
-
-/*
- * build a DHCPv4 REQUEST from a relay template
- * (implicit parameters are the local (giaddr) and MAC addresses (chaddr))
- * (assume the link is Ethernet)
- */
-
-void
-build_template_request4(void)
-{
-       uint8_t *p = template_request4;
-
-       length_request4 = BOOTP_MIN_LEN;
-       xid_request4 = DHCP_OFF_XID;
-       elapsed_request4 = DHCP_OFF_SECS;
-       random_request4 = DHCP_OFF_CHADDR + 6;
-       /* opcode */
-       p[DHCP_OFF_OPCODE] = BOOTP_OP_REQUEST;
-       /* hardware address type */
-       p[DHCP_OFF_HTYPE] = DHCP_HTYPE_ETHER;
-       /* hardware address length */
-       p[DHCP_OFF_HLEN] = 6;
-       /* hops */
-       p[DHCP_OFF_HOPS] = 1;
-       /* gateway address */
-       memcpy(p + DHCP_OFF_GIADDR,
-              &((struct sockaddr_in *) &localaddr)->sin_addr,
-              4);
-       /* hardware address */
-       memcpy(p + DHCP_OFF_CHADDR, mac_prefix, 6);
-       /* cookie */
-       memcpy(p + DHCP_OFF_COOKIE, dhcp_cookie, 4);
-       /* options */
-       p += DHCP_OFF_OPTIONS;
-       /* inline DHCP message type */
-       *p++ = DHCP_OPT_DHCP_MSGTYPE;
-       *p++ = 1;
-       *p++ = DHCP_OP_REQUEST;
-       /* place for DHCP server id (option) */
-       serverid_request4 = p - template_request4;
-       p += DHCP_OPTLEN_SRVID;
-       /* place for DHCP requested IP address (address) */
-       *p++ = DHCP_OPT_DHCP_ADDRESS;
-       *p++ = 4;
-       reqaddr_request4 = p - template_request4;
-       p += 4;
-       /* inline DHCP parameter request list (default) */
-       *p++ = DHCP_OPT_DHCP_PRL;
-       *p++ = 7;
-       *p++ = DHCP_OPT_SUBNET_MASK;
-       *p++ = DHCP_OPT_BROADCAST;
-       *p++ = DHCP_OPT_TIME_OFFSET;
-       *p++ = DHCP_OPT_ROUTERS;
-       *p++ = DHCP_OPT_DOMAIN_NAME;
-       *p++ = DHCP_OPT_DNS_SERVERS;
-       *p++ = DHCP_OPT_HOST_NAME;
-       /* end */
-       *p = DHCP_OPT_END;
-}
-
-/*
- * get a DHCPv4 client/relay third packet (usually a REQUEST) template
- * from the file given in the command line (-T<template-file>)
- * and offsets (-X,-O,-E,-S,-I).
- */
-
-void
-get_template_request4(void)
-{
-       uint8_t *p = template_request4;
-       int fd, cc, i, j;
-
-       fd = open(templatefile[1], O_RDONLY);
-       if (fd < 0) {
-               fprintf(stderr, "open(%s): %s\n",
-                       templatefile[1], strerror(errno));
-               exit(2);
-       }
-       cc = read(fd, tbuf, sizeof(tbuf));
-       (void) close(fd);
-       if (cc < 0) {
-               fprintf(stderr, "read(%s): %s\n",
-                       templatefile[1], strerror(errno));
-               exit(1);
-       }
-       if (cc < 100) {
-               fprintf(stderr, "file '%s' too short\n", templatefile[1]);
-               exit(2);
-       }
-       if (cc > 8193) {
-               fprintf(stderr,"file '%s' too large\n", templatefile[1]);
-               exit(2);
-       }
-       j = 0;
-       for (i = 0; i < cc; i++) {
-               if (isspace((int) tbuf[i]))
-                       continue;
-               if (!isxdigit((int) tbuf[i])) {
-                       fprintf(stderr,
-                               "illegal char[%d]='%c' in file '%s'\n",
-                               i, (int) tbuf[i], templatefile[1]);
-                       exit(2);
-               }
-               tbuf[j] = tbuf[i];
-               j++;
-       }
-       cc = j;
-       if ((cc & 1) != 0) {
-               fprintf(stderr,
-                       "odd number of hexadecimal digits in file '%s'\n",
-                       templatefile[1]);
-               exit(2);
-       }
-       length_request4 = cc >> 1;
-       for (i = 0; i < cc; i += 2)
-               (void) sscanf(tbuf + i, "%02hhx", &p[i >> 1]);
-       if (xidoffset[1] >= 0)
-               xid_request4 = (size_t) xidoffset[1];
-       else
-               xid_request4 = DHCP_OFF_XID;
-       if (xid_request4 + 4 > length_request4) {
-               fprintf(stderr,
-                       "xid (at %zu) outside the template (length %zu)?\n",
-                       xid_request4, length_request4);
-               exit(2);
-       }
-       if (rndoffset[1] >= 0)
-               random_request4 = (size_t) rndoffset[1];
-       else
-               random_request4 = DHCP_OFF_CHADDR + 6;
-       if (random_request4 > length_request4) {
-               fprintf(stderr,
-                       "random (at %zu) outside the template (length %zu)?\n",
-                       random_request4, length_request4);
-               exit(2);
-       }
-       if (elpoffset >= 0)
-               elapsed_request4 = (size_t) elpoffset;
-       else
-               elapsed_request4 = DHCP_OFF_SECS;
-       if (elapsed_request4 + 2 > length_request4) {
-               fprintf(stderr,
-                       "secs (at %zu) outside the template (length %zu)?\n",
-                       elapsed_request4, length_request4);
-               exit(2);
-       }
-       serverid_request4 = (size_t) sidoffset;
-       if (serverid_request4 + 6 > length_request4) {
-               fprintf(stderr,
-                       "server-id option (at %zu) outside the template "
-                       "(length %zu)?\n",
-                       serverid_request4, length_request4);
-               exit(2);
-       }
-       reqaddr_request4 = (size_t) ripoffset;
-       if (reqaddr_request4 + 4 > length_request4) {
-               fprintf(stderr,
-                       "requested-ip-address option (at %zu) outside "
-                       "the template (length %zu)?\n",
-                       reqaddr_request4, length_request4);
-               exit(2);
-       }
-}
-
-/*
- * send the DHCPv4 REQUEST third packet
- * (the transaction ID is odd)
- * (TODO: check for errors in the OFFER)
- */
-
-void
-send_request4(struct exchange *x0)
-{
-       struct exchange *x;
-       struct xlist *bucket;
-       uint32_t hash;
-       ssize_t ret;
-
-       x = (struct exchange *) malloc(sizeof(*x));
-       if (x == NULL) {
-               locallimit++;
-               perror("send2");
-               return;
-       }
-
-       memcpy(x, x0, sizeof(*x));
-       x->order2 = xscount2++;
-       x->xid |= 1;
-       hash = x->xid >> 1;
-
-       ISC_TAILQ_INSERT_TAIL(&xsent2, x, gchain);
-       hash &= hashsize2 - 1;
-       bucket = (struct xlist *) (exchanges2 + hash * sizeof(*bucket));
-       ISC_TAILQ_INSERT_TAIL(bucket, x, hchain);
-
-       memcpy(obuf, template_request4, length_request4);
-       /* xid */
-       memcpy(obuf + xid_request4, &x->xid, 4);
-       /* random */
-       randomize(random_request4, x->rnd);
-       /* secs */
-       if (elapsed_request4 > 0) {
-               int secs;
-
-               secs = x->ts1.tv_sec - x->ts0.tv_sec;
-               if (x->ts1.tv_nsec < x->ts0.tv_nsec)
-                       secs += 1;
-               if (secs > 0) {
-                       obuf[elapsed_request4] = secs >> 8;
-                       obuf[elapsed_request4 + 1] = secs & 0xff;
-               }
-       }
-       /* server ID */
-       memcpy(obuf + serverid_request4, x->sid, x->sidlen);
-       /* requested IP address */
-       memcpy(obuf + reqaddr_request4, ibuf + DHCP_OFF_YIADDR, 4);
-
-       /* timestamp */
-       ret = clock_gettime(CLOCK_REALTIME, &x->ts2);
-       if (ret < 0) {
-               perror("clock_gettime(send2)");
-               fatal = 1;
-               return;
-       }
-       ret = sendto(sock, obuf, length_request4, 0,
-                    (struct sockaddr *) &serveraddr,
-                    sizeof(struct sockaddr_in));
-       if (ret >= 0)
-               return;
-       if ((errno == EAGAIN) || (errno == EWOULDBLOCK) ||
-           (errno == ENOBUFS) || (errno == ENOMEM))
-               locallimit++;
-       perror("send2");
-}
-
-/*
- * send the DHCPv4 DISCOVER first packet
- * (for 4-exchange, the transaction ID xid is even)
- */
-
-int
-send4(void)
-{
-       struct exchange *x;
-       struct xlist *bucket;
-       uint32_t hash;
-       ssize_t ret;
-
-       x = (struct exchange *) malloc(sizeof(*x));
-       if (x == NULL)
-               return -ENOMEM;
-
-       memset(x, 0, sizeof(*x));
-       x->order0 = xscount0++;
-       hash = x->rnd = (uint32_t) random();
-       if (simple == 0)
-               x->xid = hash << 1;
-       else
-               x->xid = hash;
-
-       ISC_TAILQ_INSERT_TAIL(&xsent0, x, gchain);
-       hash &= hashsize0 - 1;
-       bucket = (struct xlist *) (exchanges0 + hash * sizeof(*bucket));
-       ISC_TAILQ_INSERT_TAIL(bucket, x, hchain);
-
-       memcpy(obuf, template_discover4, length_discover4);
-       /* xid */
-       memcpy(obuf + xid_discover4, &x->xid, 4);
-       /* random */
-       x->rnd = randomize(random_discover4, x->rnd);
-       /* timestamp */
-       ret = clock_gettime(CLOCK_REALTIME, &last);
-       if (ret < 0) {
-               perror("clock_gettime(send)");
-               fatal = 1;
-               return -errno;
-       }
-       x->ts0 = last;
-       errno = 0;
-       ret = sendto(sock, obuf, length_discover4, 0,
-                    (struct sockaddr *) &serveraddr,
-                    sizeof(struct sockaddr_in));
-       if (ret == (ssize_t) length_discover4)
-               return 0;
-       return -errno;
-}      
-
-/*
- * scan a DHCPv4 OFFER to get its server-id option
- */
-
-int
-scan_for_srvid4(struct exchange *x, size_t cc)
-{
-       size_t off = DHCP_OFF_OPTIONS;
-
-       for (;;) {
-               if (off + DHCP_OPTLEN_SRVID > cc) {
-                       fprintf(stderr, "truncated\n");
-                       return -1;
-               }
-               if (ibuf[off] == DHCP_OPT_DHCP_SRVID)
-                       break;
-               if (ibuf[off] == DHCP_OPT_END) {
-                       fprintf(stderr, "server-id not found\n");
-                       return -1;
-               }
-               if (ibuf[off] == DHCP_OPT_PAD) {
-                       off++;
-                       continue;
-               }
-               off += 2 + ibuf[off + 1];
-       }
-       /* check length */
-       if (ibuf[off + 1] != DHCP_OPTLEN_SRVID - 2) {
-               fprintf(stderr,
-                       "bad server-id length (%hhu)\n",
-                       ibuf[off + 1]);
-               return -1;
-       }
-       /* cache it in the global variables when required and not yet done */
-       if ((usefirst != 0) && (gsrvid == NULL)) {
-               memcpy(gsrvidbuf, ibuf + off, DHCP_OPTLEN_SRVID);
-               gsrvid = gsrvidbuf;
-               gsrvidlen = DHCP_OPTLEN_SRVID;
-       }
-       x->sid = ibuf + off;
-       x->sidlen = DHCP_OPTLEN_SRVID;
-       return 0;
-}
-
-/*
- * receive a DHCPv4 packet
- */
-
-void
-receive4(void)
-{
-       struct exchange *x, *t;
-       struct xlist *bucket;
-       struct timespec now;
-       ssize_t cc;
-       uint32_t xid, hash;
-       int checklost = 0;
-       double delta;
-
-       cc = recv(sock, ibuf, sizeof(ibuf), 0);
-       if (cc < 0) {
-               if ((errno == EAGAIN) ||
-                   (errno == EWOULDBLOCK) ||
-                   (errno == EINTR))
-                       return;
-               perror("recv");
-               fatal = 1;
-               return;
-       }
-       /* enforce a reasonable length */
-       if (cc < BOOTP_MIN_LEN) {
-               tooshort++;
-               return;
-       }
-       /* must be a BOOTP REPLY */
-       if (ibuf[DHCP_OFF_OPCODE] != BOOTP_OP_REPLY)
-               return;
-       if (clock_gettime(CLOCK_REALTIME, &now) < 0) {
-               perror("clock_gettime(receive)");
-               fatal = 1;
-               return;
-       }
-       memcpy(&xid, ibuf + xid_discover4, 4);
-       /* 4-packet exchange even/odd xid */
-       if (simple == 0) {
-               if ((xid & 1) != 0) {
-                       receive_reply(xid, &now);
-                       return;
-               }
-               hash = (xid >> 1) & (hashsize0 - 1);
-       } else
-               hash = xid & (hashsize0 - 1);
-       /* now it is the second packet, get the bucket which is needed */
-       bucket = (struct xlist *) (exchanges0 + hash * sizeof(*bucket));
-       /* try the 'next to be received' cache */
-       if ((xnext0 != NULL) && (xnext0->xid == xid)) {
-               x = xnext0;
-               goto found;
-       }
-       /* if the rate is not illimited, garbage collect up to 3
-          timed-out exchanges */
-       if (rate != 0)
-               checklost = 3;
-       /* look for the exchange */
-       ISC_TAILQ_FOREACH_SAFE(x, bucket, hchain, t) {
-               double waited;
-
-               if (x->xid == xid)
-                       goto found;
-               if (checklost <= 0)
-                       continue;
-               /* check for a timed-out exchange */
-               waited = now.tv_sec - x->ts0.tv_sec;
-               waited += (now.tv_nsec - x->ts0.tv_nsec) / 1e9;
-               if (waited < losttime[0]) {
-                       checklost = 0;
-                       continue;
-               }
-               /* garbage collect timed-out exchange */
-               checklost--;
-               ISC_TAILQ_REMOVE(bucket, x, hchain);
-               ISC_TAILQ_REMOVE(&xsent0, x, gchain);
-               free(x);
-               collected[0] += 1;
-       }
-       /* no match? very late or not for us */
-       orphans++;
-       return;
-
-       /* got it: update stats and move to the received queue */
-    found:
-       xrcount0++;
-       x->ts1 = now;
-       delta = x->ts1.tv_sec - x->ts0.tv_sec;
-       delta += (x->ts1.tv_nsec - x->ts0.tv_nsec) / 1e9;
-       if (delta < dmin0)
-               dmin0 = delta;
-       if (delta > dmax0)
-               dmax0 = delta;
-       dsum0 += delta;
-       dsumsq0 += delta * delta;
-       xnext0 = ISC_TAILQ_NEXT(x, gchain);
-       ISC_TAILQ_REMOVE(bucket, x, hchain);
-       ISC_TAILQ_REMOVE(&xsent0, x, gchain);
-       ISC_TAILQ_INSERT_TAIL(&xrcvd0, x, gchain);
-       /* if the exchange is not finished, go to the second part */
-       if (simple == 0) {
-               int ret = 0;
-
-               /* the server-ID option is needed */
-               if ((usefirst != 0) && (gsrvid != NULL)) {
-                       x->sid = gsrvid;
-                       x->sidlen = gsrvidlen;
-               } else
-                       ret = scan_for_srvid4(x, cc);
-               if (ret >= 0)
-                       send_request4(x);
-       }
-}
-
-/*
- * get the DHCPv6 socket descriptor
- */
-
-void
-getsock6(void)
-{
-       struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &serveraddr;
-       int ret;
-
-       /* update local port */
-       if (localport != 0) {
-               uint16_t lp = htons((uint16_t) localport);
-
-               ((struct sockaddr_in6 *) &localaddr)->sin6_port = lp;
-       }
-       sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
-       if (sock < 0) {
-               perror("socket");
-               exit(1);
-       }
-       ret = bind(sock,
-                  (struct sockaddr *) &localaddr,
-                  sizeof(struct sockaddr_in6));
-       if (ret < 0) {
-               perror("Failed to bind v6 socket to local-link address");
-               exit(1);
-       }
-       /* perform the multicast stuff when the destination is multicast */
-       if (IN6_IS_ADDR_MULTICAST(&s6->sin6_addr)) {
-               int hops = 1;
-
-               ret = setsockopt(sock,
-                                IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
-                                &hops, sizeof(hops));
-               if (ret < 0) {
-                       perror("setsockopt(IPV6_MULTICAST_HOPS)");
-                       exit(1);
-               }
-       }
-       if (isinterface && IN6_IS_ADDR_MULTICAST(&s6->sin6_addr)) {
-               unsigned idx = if_nametoindex(localname);
-
-               if (idx == 0) {
-                       fprintf(stderr,
-                               "if_nametoindex(%s) failed\n",
-                               localname);
-                       exit(1);
-               }
-               ret = setsockopt(sock,
-                                IPPROTO_IPV6, IPV6_MULTICAST_IF,
-                                &idx, sizeof(idx));
-               if (ret < 0) {
-                       perror("setsockopt(IPV6_MULTICAST_IF)");
-                       exit(1);
-               }
-       }
-}
-
-/*
- * build a DHCPv6 SOLICIT template
- * (implicit parameter is the DUID, don't assume an Ethernet link)
- */
-
-void
-build_template_solicit6(void)
-{
-       uint8_t *p = template_solicit6;
-
-       xid_solicit6 = DHCP6_OFF_XID;
-       /* message type */
-       p[DHCP6_OFF_MSGTYP] = DHCP6_OP_SOLICIT;
-       /* options */
-       p += DHCP6_OFF_OPTIONS;
-       /* elapsed time */
-       p[1] = DHCP6_OPT_ELAPSED_TIME;
-       p[3] = 2;
-       p += 6;
-       /* rapid commit */
-       if (rapidcommit != 0) {
-               p[1] = DHCP6_OPT_RAPID_COMMIT;
-               p += 4;
-       }
-       /* client ID */
-       p[1] = DHCP6_OPT_CLIENTID;
-       p[3] = duid_length;
-       memcpy(p + 4, duid_prefix, duid_length);
-       p += 4 + duid_length;
-       random_solicit6 = p - template_solicit6;
-       /* option request option */
-       p[1] = DHCP6_OPT_ORO;
-       p[3] = 4;
-       p[5] = DHCP6_OPT_NAME_SERVERS;
-       p[7] = DHCP6_OPT_DOMAIN_SEARCH;
-       p += 8;
-       /* IA_NA (IAID = 1, T1 = 3600, T2 = 5400) */
-       p[1] = DHCP6_OPT_IA_NA;
-       p[3] = 12;
-       p[7] = 1;
-       p[10] = 3600 >> 8;
-       p[11] = 3600 & 0xff;
-       p[14] = 5400 >> 8;
-       p[15] = 5400 & 0xff;
-       p += 16;
-       /* set length */
-       length_solicit6 = p - template_solicit6;
-}
-
-/*
- * get a DHCPv6 first packet (usually a SOLICIT) template
- * from the file given in the command line (-T<template-file>)
- * and xid/rnd offsets (-X<xid-offset> and -O<random-offset>)
- */
-
-void
-get_template_solicit6(void)
-{
-       uint8_t *p = template_solicit6;
-       int fd, cc, i, j;
-
-       fd = open(templatefile[0], O_RDONLY);
-       if (fd < 0) {
-               fprintf(stderr, "open(%s): %s\n",
-                       templatefile[0], strerror(errno));
-               exit(2);
-       }
-       cc = read(fd, tbuf, sizeof(tbuf));
-       (void) close(fd);
-       if (cc < 0) {
-               fprintf(stderr, "read(%s): %s\n",
-                       templatefile[0], strerror(errno));
-               exit(1);
-       }
-       if (cc < 10) {
-               fprintf(stderr, "file '%s' too short\n", templatefile[0]);
-               exit(2);
-       }
-       if (cc > 8193) {
-               fprintf(stderr,"file '%s' too large\n", templatefile[0]);
-               exit(2);
-       }
-       j = 0;
-       for (i = 0; i < cc; i++) {
-               if (isspace((int) tbuf[i]))
-                       continue;
-               if (!isxdigit((int) tbuf[i])) {
-                       fprintf(stderr,
-                               "illegal char[%d]='%c' in file '%s'\n",
-                               i, (int) tbuf[i], templatefile[0]);
-                       exit(2);
-               }
-               tbuf[j] = tbuf[i];
-               j++;
-       }
-       cc = j;
-       if ((cc & 1) != 0) {
-               fprintf(stderr,
-                       "odd number of hexadecimal digits in file '%s'\n",
-                       templatefile[0]);
-               exit(2);
-       }
-       length_solicit6 = cc >> 1;
-       for (i = 0; i < cc; i += 2)
-               (void) sscanf(tbuf + i, "%02hhx", &p[i >> 1]);
-       if (xidoffset[0] >= 0)
-               xid_solicit6 = (size_t) xidoffset[0];
-       else
-               xid_solicit6 = DHCP6_OFF_XID;
-       if (xid_solicit6 + 3 > length_solicit6) {
-               fprintf(stderr,
-                       "xid (at %zu) is outside the template (length %zu)?\n",
-                       xid_solicit6, length_solicit6);
-               exit(2);
-       }
-       if (rndoffset[0] >= 0)
-               random_solicit6 = (size_t) rndoffset[0];
-       else
-               random_solicit6 = 0;
-       if (random_solicit6 > length_solicit6) {
-               fprintf(stderr,
-                       "random (at %zu) outside the template (length %zu)?\n",
-                       random_solicit6, length_solicit6);
-               exit(2);
-       }
-}
-
-/*
- * build a DHCPv6 REQUEST template
- * (implicit parameter is the DUID, don't assume an Ethernet link)
- */
-
-void
-build_template_request6(void)
-{
-       uint8_t *p = template_request6;
-
-       xid_request6 = DHCP6_OFF_XID;
-       /* message type */
-       p[DHCP6_OFF_MSGTYP] = DHCP6_OP_REQUEST;
-       /* options */
-       p += DHCP6_OFF_OPTIONS;
-       /* elapsed time */
-       p[1] = DHCP6_OPT_ELAPSED_TIME;
-       p[3] = 2;
-       p += 4;
-       elapsed_request6 = p - template_request6;
-       p += 2;
-       /* client ID */
-       p[1] = DHCP6_OPT_CLIENTID;
-       p[3] = duid_length;
-       memcpy(p + 4, duid_prefix, duid_length);
-       p += 4 + duid_length;
-       random_request6 = p - template_request6;
-       /* option request option */
-       p[1] = DHCP6_OPT_ORO;
-       p[3] = 4;
-       p[5] = DHCP6_OPT_NAME_SERVERS;
-       p[7] = DHCP6_OPT_DOMAIN_SEARCH;
-       p += 8;
-       /* server ID and IA_NA */
-       serverid_request6 = p - template_request6;
-       reqaddr_request6 = p - template_request6;
-       /* set length */
-       length_request6 = p - template_request6;
-}
-
-/*
- * get a DHCPv6 third packet (usually a REQUEST) template
- * from the file given in the command line (-T<template-file>)
- * and offsets (-X,-O,-E,-S,-I).
- */
-
-void
-get_template_request6(void)
-{
-       uint8_t *p = template_request6;
-       int fd, cc, i, j;
-
-       fd = open(templatefile[1], O_RDONLY);
-       if (fd < 0) {
-               fprintf(stderr, "open(%s): %s\n",
-                       templatefile[1], strerror(errno));
-               exit(2);
-       }
-       cc = read(fd, tbuf, sizeof(tbuf));
-       (void) close(fd);
-       if (cc < 0) {
-               fprintf(stderr, "read(%s): %s\n",
-                       templatefile[1], strerror(errno));
-               exit(1);
-       }
-       if (cc < 10) {
-               fprintf(stderr, "file '%s' too short\n", templatefile[1]);
-               exit(2);
-       }
-       if (cc > 8193) {
-               fprintf(stderr,"file '%s' too large\n", templatefile[1]);
-               exit(2);
-       }
-       j = 0;
-       for (i = 0; i < cc; i++) {
-               if (isspace((int) tbuf[i]))
-                       continue;
-               if (!isxdigit((int) tbuf[i])) {
-                       fprintf(stderr,
-                               "illegal char[%d]='%c' in file '%s'\n",
-                               i, (int) tbuf[i], templatefile[1]);
-                       exit(2);
-               }
-               tbuf[j] = tbuf[i];
-               j++;
-       }
-       cc = j;
-       if ((cc & 1) != 0) {
-               fprintf(stderr,
-                       "odd number of hexadecimal digits in file '%s'\n",
-                       templatefile[1]);
-               exit(2);
-       }
-       length_request6 = cc >> 1;
-       for (i = 0; i < cc; i += 2)
-               (void) sscanf(tbuf + i, "%02hhx", &p[i >> 1]);
-       if (xidoffset[1] >= 0)
-               xid_request6 = (size_t) xidoffset[1];
-       else
-               xid_request6 = DHCP6_OFF_XID;
-       if (xid_request6 + 3 > length_request6) {
-               fprintf(stderr,
-                       "xid (at %zu) is outside the template (length %zu)?\n",
-                       xid_request6, length_request6);
-               exit(2);
-       }
-       if (rndoffset[1] >= 0)
-               random_request6 = (size_t) rndoffset[1];
-       else
-               random_request6 = 0;
-       if (random_request6 > length_request6) {
-               fprintf(stderr,
-                       "random (at %zu) outside the template (length %zu)?\n",
-                       random_request6, length_request6);
-               exit(2);
-       }
-       if (elpoffset >= 0)
-               elapsed_request6 = (size_t) elpoffset;
-       if (elapsed_request6 + 2 > length_request6) {
-               fprintf(stderr,
-                       "secs (at %zu) outside the template (length %zu)?\n",
-                       elapsed_request6, length_request6);
-               exit(2);
-       }
-       serverid_request6 = (size_t) sidoffset;
-       if (serverid_request6 > length_request6) {
-               fprintf(stderr,
-                       "server-id option (at %zu) outside the template "
-                       "(length %zu)?\n",
-                       serverid_request6, length_request6);
-               exit(2);
-       }
-       reqaddr_request6 = (size_t) ripoffset;
-       if (reqaddr_request6 > length_request6) {
-               fprintf(stderr,
-                       "requested-ip-address option (at %zu) outside "
-                       "the template (length %zu)?\n",
-                       reqaddr_request6, length_request6);
-               exit(2);
-       }
-}
-
-/*
- * send the DHCPv6 REQUEST third packet
- * (the transaction ID is odd)
- * (TODO: check for errors in the ADVERTISE)
- */
-
-void
-send_request6(struct exchange *x0)
-{
-       struct exchange *x;
-       struct xlist *bucket;
-       size_t len;
-       uint32_t hash;
-       ssize_t ret;
-
-       x = (struct exchange *) malloc(sizeof(*x));
-       if (x == NULL) {
-               locallimit++;
-               perror("send2");
-               return;
-       }
-
-       memcpy(x, x0, sizeof(*x));
-       x->order2 = xscount2++;
-       x->xid |= 1;
-       hash = x->xid >> 1;
-
-       ISC_TAILQ_INSERT_TAIL(&xsent2, x, gchain);
-       hash &= hashsize2 - 1;
-       bucket = (struct xlist *) (exchanges2 + hash * sizeof(*bucket));
-       ISC_TAILQ_INSERT_TAIL(bucket, x, hchain);
-
-       len = length_request6;
-       memcpy(obuf, template_request6, len);
-       /* xid */
-       obuf[xid_request6] = x->xid >> 16;
-       obuf[xid_request6 + 1] = x->xid >> 8;
-       obuf[xid_request6 + 2] = x->xid;
-       /* random */
-       randomize(random_request6, x->rnd);
-       /* elapsed time */
-       if (elapsed_request6 > 0) {
-               int et;
-
-               et = (x->ts1.tv_sec - x->ts0.tv_sec) * 100;
-               et += (x->ts1.tv_nsec - x->ts0.tv_nsec) / 10000000;
-               if (et > 65535) {
-                       obuf[elapsed_request6] = 0xff;
-                       obuf[elapsed_request6 + 1] = 0xff;
-               } else if (et > 0) {
-                       obuf[elapsed_request6] = et >> 8;
-                       obuf[elapsed_request6 + 1] = et & 0xff;
-               }
-       }
-       /* server ID */
-       if (serverid_request6 < length_request6)
-               memmove(obuf + serverid_request6 + x->sidlen,
-                       obuf + serverid_request6,
-                       x->sidlen);
-       memcpy(obuf + serverid_request6, x->sid, x->sidlen);
-       len += x->sidlen;
-       /* IA_NA */
-       if (reqaddr_request6 < serverid_request6) {
-               memmove(obuf + reqaddr_request6 + x->ianalen,
-                       obuf + reqaddr_request6,
-                       x->ianalen);
-               memcpy(obuf + reqaddr_request6, x->iana, x->ianalen);
-       } else if (reqaddr_request6 < length_request6) {
-               memmove(obuf + reqaddr_request6 + x->sidlen + x->ianalen,
-                       obuf + reqaddr_request6 + x->sidlen,
-                       x->ianalen);
-               memcpy(obuf + reqaddr_request6+ x->sidlen,
-                      x->iana,
-                      x->ianalen);
-       } else
-               memcpy(obuf + len, x->iana, x->ianalen);
-       len += x->ianalen;
-
-       /* timestamp */
-       ret = clock_gettime(CLOCK_REALTIME, &x->ts2);
-       if (ret < 0) {
-               perror("clock_gettime(send2)");
-               fatal = 1;
-               return;
-       }
-       ret = sendto(sock, obuf, len, 0,
-                    (struct sockaddr *) &serveraddr,
-                    sizeof(struct sockaddr_in6));
-       if (ret >= 0)
-               return;
-       if ((errno == EAGAIN) || (errno == EWOULDBLOCK) ||
-           (errno == ENOBUFS) || (errno == ENOMEM))
-               locallimit++;
-       perror("send2");
-}
-
-/*
- * send the DHCPv6 SOLICIT first packet
- * (for 4-exchange, the transaction ID xid is even)
- */
-
-int
-send6(void)
-{
-       struct exchange *x;
-       struct xlist *bucket;
-       uint32_t hash;
-       ssize_t ret;
-
-       x = (struct exchange *) malloc(sizeof(*x));
-       if (x == NULL)
-               return -ENOMEM;
-
-       memset(x, 0, sizeof(*x));
-       x->order0 = xscount0++;
-       hash = x->rnd = (uint32_t) random();
-       if (simple == 0)
-               x->xid = (hash << 1) & 0x00ffffff;
-       else
-               x->xid = hash & 0x00ffffff;
-
-       ISC_TAILQ_INSERT_TAIL(&xsent0, x, gchain);
-       hash &= hashsize0 - 1;
-       bucket = (struct xlist *) (exchanges0 + hash * sizeof(*bucket));
-       ISC_TAILQ_INSERT_TAIL(bucket, x, hchain);
-
-       memcpy(obuf, template_solicit6, length_solicit6);
-       /* xid */
-       obuf[xid_solicit6] = x->xid >> 16;
-       obuf[xid_solicit6 + 1] = x->xid >> 8;
-       obuf[xid_solicit6 + 2] = x->xid;
-       /* random */
-       x->rnd = randomize(random_solicit6, x->rnd);
-
-       /* timestamp */
-       ret = clock_gettime(CLOCK_REALTIME, &last);
-       if (ret < 0) {
-               perror("clock_gettime(send)");
-               fatal = 1;
-               return -errno;
-       }
-       x->ts0 = last;
-       errno = 0;
-       ret = sendto(sock, obuf, length_solicit6, 0,
-                    (struct sockaddr *) &serveraddr,
-                    sizeof(struct sockaddr_in6));
-       if (ret == (ssize_t) length_solicit6)
-               return 0;
-       return -errno;
-}
-
-/*
- * scan a DHCPv6 ADVERTISE to get its server-id option
- */
-
-int
-scan_for_srvid6(struct exchange *x, size_t cc)
-{
-       size_t off = DHCP6_OFF_OPTIONS, len;
-
-       for (;;) {
-               if (off + 4 > cc) {
-                       fprintf(stderr, "server-id not found\n");
-                       return -1;
-               }
-               if ((ibuf[off] == 0) && (ibuf[off + 1] == DHCP6_OPT_SERVERID))
-                       break;
-               off += 4 + (ibuf[off + 2] << 8) + ibuf[off + 3];
-       }
-       len = 4 + (ibuf[off + 2] << 8) + ibuf[off + 3];
-       /* cache it in the global variables when required and not yet done */
-       if ((usefirst != 0) && (gsrvid == NULL)) {
-               if (len <= sizeof(gsrvidbuf)) {
-                       memcpy(gsrvidbuf, ibuf + off, len);
-                       gsrvid = gsrvidbuf;
-                       gsrvidlen = len;
-               } else {
-                       gsrvid = (uint8_t *) malloc(len);
-                       if (gsrvid == NULL) {
-                               perror("malloc(gsrvid");
-                               return -1;
-                       }
-                       memcpy(gsrvid, ibuf + off, len);
-                       gsrvidlen = len;
-               }
-       }
-       x->sid = ibuf + off;
-       x->sidlen = len;
-       return 0;
-}
-
-/*
- * scan a DHCPv6 ADVERTISE to get its IA_NA option
- * (TODO: check for errors)
- */
-
-int
-scan_for_ia_na(struct exchange *x, size_t cc)
-{
-       size_t off = DHCP6_OFF_OPTIONS, len;
-
-       for (;;) {
-               if (off + 4 > cc) {
-                       fprintf(stderr, "ia-na not found\n");
-                       return -1;
-               }
-               if ((ibuf[off] == 0) && (ibuf[off + 1] == DHCP6_OPT_IA_NA))
-                       break;
-               off += 4 + (ibuf[off + 2] << 8) + ibuf[off + 3];
-       }
-       len = 4 + (ibuf[off + 2] << 8) + ibuf[off + 3];
-       x->iana = ibuf + off;
-       x->ianalen = len;
-       return 0;
-}
-
-/*
- * receive a DHCPv6 packet
- */
-
-void
-receive6(void)
-{
-       struct exchange *x, *t;
-       struct xlist *bucket;
-       struct timespec now;
-       ssize_t cc;
-       uint32_t xid, hash;
-       int checklost = 0;
-       double delta;
-
-       cc = recv(sock, ibuf, sizeof(ibuf), 0);
-       if (cc < 0) {
-               if ((errno == EAGAIN) ||
-                   (errno == EWOULDBLOCK) ||
-                   (errno == EINTR))
-                       return;
-               perror("recv");
-               fatal = 1;
-               return;
-       }
-       /* enforce a reasonable length */
-       if (cc < 22) {
-               tooshort++;
-               return;
-       }
-       if (clock_gettime(CLOCK_REALTIME, &now) < 0) {
-               perror("clock_gettime(receive)");
-               fatal = 1;
-               return;
-       }
-       xid = ibuf[xid_solicit6] << 16;
-       xid |= ibuf[xid_solicit6 + 1] << 8;
-       xid |= ibuf[xid_solicit6 + 2];
-       /* 4-packet exchange even/odd xid */
-       if (simple == 0) {
-               if ((xid & 1) != 0) {
-                       receive_reply(xid, &now);
-                       return;
-               }
-               hash = (xid >> 1) & (hashsize0 - 1);
-       } else
-               hash = xid & (hashsize0 - 1);
-       /* now it is the second packet, get the bucket which is needed */
-       bucket = (struct xlist *) (exchanges0 + hash * sizeof(*bucket));
-       /* try the 'next to be received' cache */
-       if ((xnext0 != NULL) && (xnext0->xid == xid)) {
-               x = xnext0;
-               goto found;
-       }
-       /* if the rate is not illimited, garbage collect up to 3
-          timed-out exchanges */
-       if (rate != 0)
-               checklost = 3;
-       /* look for the exchange */
-       ISC_TAILQ_FOREACH_SAFE(x, bucket, hchain, t) {
-               double waited;
-
-               if (x->xid == xid)
-                       goto found;
-               if (checklost <= 0)
-                       continue;
-               /* check for a timed-out exchange */
-               waited = now.tv_sec - x->ts0.tv_sec;
-               waited += (now.tv_nsec - x->ts0.tv_nsec) / 1e9;
-               if (waited < losttime[0]) {
-                       checklost = 0;
-                       continue;
-               }
-               /* garbage collect timed-out exchange */
-               checklost--;
-               ISC_TAILQ_REMOVE(bucket, x, hchain);
-               ISC_TAILQ_REMOVE(&xsent0, x, gchain);
-               free(x);
-               collected[0] += 1;
-       }
-       /* no match? very late or not for us */
-       orphans++;
-       return;
-
-       /* got it: update stats and move to the received queue */
-    found:
-       xrcount0++;
-       x->ts1 = now;
-       delta = x->ts1.tv_sec - x->ts0.tv_sec;
-       delta += (x->ts1.tv_nsec - x->ts0.tv_nsec) / 1e9;
-       if (delta < dmin0)
-               dmin0 = delta;
-       if (delta > dmax0)
-               dmax0 = delta;
-       dsum0 += delta;
-       dsumsq0 += delta * delta;
-       xnext0 = ISC_TAILQ_NEXT(x, gchain);
-       ISC_TAILQ_REMOVE(bucket, x, hchain);
-       ISC_TAILQ_REMOVE(&xsent0, x, gchain);
-       ISC_TAILQ_INSERT_TAIL(&xrcvd0, x, gchain);
-       /* if the exchange is not finished, go to the second part */
-       if (simple == 0) {
-               int ret = 0;
-
-               /* the server-ID option is needed */
-               if ((usefirst != 0) && (gsrvid != NULL)) {
-                       x->sid = gsrvid;
-                       x->sidlen = gsrvidlen;
-               } else
-                       ret = scan_for_srvid6(x, cc);
-               /* and the IA_NA option too */
-               if (ret >= 0)
-                       ret = scan_for_ia_na(x, cc);
-               if (ret >= 0)
-                       send_request6(x);
-       }
-}
-
-/*
- * decode a base command line parameter
- * (currently only MAC address and DUID are supported)
- */
-
-void
-decodebase(void)
-{
-       char *b0 = base[basecnt];
-
-       /* MAC address (alias Ethernet address) */
-       if ((strncasecmp(b0, "mac=", 4) == 0) ||
-           (strncasecmp(b0, "ether=", 6) == 0)) {
-               char *b;
-
-               b = strchr(b0, '=') + 1;
-               if (sscanf(b, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
-                          &mac_prefix[0], &mac_prefix[1],
-                          &mac_prefix[2], &mac_prefix[3],
-                          &mac_prefix[4], &mac_prefix[5]) == 6) {
-                       if ((diags != NULL) && (strchr(diags, 'a') != NULL))
-                               printf("set MAC to %s\n", b);
-                       return;
-               }
-               fprintf(stderr,
-                       "expected base in '%*s=xx:xx:xx:xx:xx:xx' format\n",
-                       (int) (b - b0 - 1), b0);
-                       exit(2);
-       }
-       /* DUID */
-       if (strncasecmp(b0, "duid=", 5) == 0) {
-               char *b;
-               size_t i, l;
-
-               if (duid_prefix != NULL) {
-                       fprintf(stderr, "duid was already set?\n");
-                       exit(2);
-               }
-               b = strchr(b0, '=') + 1;
-               l = 0;
-               while (*b != '\0') {
-                       if (!isxdigit((int) *b)) {
-                               fprintf(stderr,
-                                       "illegal char '%c' in duid\n",
-                                       (int) *b);
-                               exit(2);
-                       }
-                       b++;
-                       l++;
-               }
-               if ((l & 1) != 0) {
-                       fprintf(stderr,
-                               "odd number of hexadecimal digits in duid\n");
-                       exit(2);
-               }
-               l /= 2;
-               if (l > 64) {
-                       fprintf(stderr, "duid too large\n");
-                       exit(2);
-               }
-               duid_prefix = (uint8_t *) malloc(l);
-               if (duid_prefix == NULL) {
-                       perror("malloc(duid)");
-                       exit(1);
-               }
-               b = strchr(b0, '=') + 1;
-               for (i = 0; i < l; i++, b += 2)
-                       (void) sscanf(b, "%02hhx", &duid_prefix[i]);
-               duid_length = l;
-               if ((diags != NULL) && (strchr(diags, 'a') != NULL)) {
-                       b = strchr(b0, '=') + 1;
-                       printf("set DUID[%d] to %s\n",
-                              duid_length, b);
-               }
-               return;
-       }
-       /* other */
-       fprintf(stderr, "not yet supported base '%s'\n", b0);
-       exit(2);
-}
-                          
-/*
- * get the server socket address from the command line:
- *  - flags: inherited from main, 0 or AI_NUMERICHOST (for literals)
- */
-
-void
-getserveraddr(const int flags)
-{
-       struct addrinfo hints, *res;
-       char *service;
-       int ret;
-
-       memset(&hints, 0, sizeof(hints));
-       if (ipversion == 4) {
-               hints.ai_family = AF_INET;
-               service = "67";
-       } else {
-               hints.ai_family = AF_INET6;
-               service = "547";
-       }
-       hints.ai_socktype = SOCK_DGRAM;
-
-       hints.ai_flags = AI_NUMERICSERV | flags;
-#if defined(AI_ADDRCONFIG)
-       hints.ai_flags |= AI_ADDRCONFIG;
-#endif
-       hints.ai_protocol = IPPROTO_UDP;
-       
-       ret = getaddrinfo(servername, service, &hints, &res);
-       if (ret != 0) {
-               fprintf(stderr, "bad server=%s: %s\n",
-                       servername, gai_strerror(ret));
-               exit(2);
-       }
-       if (res->ai_next != NULL) {
-               fprintf(stderr, "ambiguous server=%s\n", servername);
-               exit(2);
-       }
-       memcpy(&serveraddr, res->ai_addr, res->ai_addrlen);
-       freeaddrinfo(res);
-}
-
-/*
- * get the interface from the command line:
- *   - name of the interface
- *   - socket address to fill
- * (in IPv6, get the first link-local address)
- */
-
-void
-getinterface(const char *name, struct sockaddr_storage *ss)
-{
-       struct ifaddrs *ifaddr, *ifa;
-       int ret;
-       size_t len;
-
-       ret = getifaddrs(&ifaddr);
-       if (ret < 0) {
-               perror("getifaddrs");
-               exit(1);
-       }
-
-       for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
-               if (ifa->ifa_name == NULL)
-                       continue;
-               if (strcmp(ifa->ifa_name, name) != 0)
-                       continue;
-               if ((ifa->ifa_flags & IFF_UP) == 0)
-                       continue;
-               if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
-                       continue;
-               if (ifa->ifa_addr == NULL)
-                       continue;
-               if ((ipversion == 4) &&
-                   (ifa->ifa_addr->sa_family != AF_INET))
-                       continue;
-               if (ipversion == 6) {
-                       struct sockaddr_in6 *a6;
-
-                       a6 = (struct sockaddr_in6 *) ifa->ifa_addr;
-                       if (a6->sin6_family != AF_INET6)
-                               continue;
-                       if (!IN6_IS_ADDR_LINKLOCAL(&a6->sin6_addr))
-                               continue;
-               }
-               if (ipversion == 4)
-                       len = sizeof(struct sockaddr_in);
-               else
-                       len = sizeof(struct sockaddr_in6);
-               memcpy(ss, ifa->ifa_addr, len);
-               /* fill the server port */
-               if (ipversion == 4)
-                       ((struct sockaddr_in *) ss)->sin_port = htons(67);
-               else
-                       ((struct sockaddr_in6 *) ss)->sin6_port = htons(546);
-               return;
-       }
-       fprintf(stderr, "can't find interface %s\n", name);
-       exit(1);
-}
-
-/*
- * get the local socket address from the command line
- * (if it doesn't work, try an interface name)
- */
-
-void
-getlocaladdr(void)
-{
-       struct addrinfo hints, *res;
-       char *service;
-       int ret;
-
-       memset(&hints, 0, sizeof(hints));
-       if (ipversion == 4) {
-               hints.ai_family = AF_INET;
-               service = "67";
-       } else {
-               hints.ai_family = AF_INET6;
-               service = "546";
-       }
-       hints.ai_socktype = SOCK_DGRAM;
-       hints.ai_flags =  AI_NUMERICSERV;
-#if defined(AI_ADDRCONFIG)
-       hints.ai_flags |= AI_ADDRCONFIG;
-#endif
-       hints.ai_protocol = IPPROTO_UDP;
-       
-       ret = getaddrinfo(localname, service, &hints, &res);
-       if ((ret == EAI_NONAME)
-#ifdef EAI_NODATA
-           || (ret == EAI_NODATA)
-#endif
-          ) {
-               isinterface = 1;
-               getinterface(localname, &localaddr);
-               return;
-       }
-       if (ret != 0) {
-               fprintf(stderr,
-                       "bad -l<local-addr=%s>: %s\n",
-                       localname,
-                       gai_strerror(ret));
-               exit(2);
-       }
-       /* refuse multiple addresses */
-       if (res->ai_next != NULL) {
-               fprintf(stderr,
-                       "ambiguous -l<local-addr=%s>\n",
-                       localname);
-               exit(2);
-       }
-       memcpy(&localaddr, res->ai_addr, res->ai_addrlen);
-       freeaddrinfo(res);
-       return;
-}
-
-/*
- * get the local socket address from the server one
- */
-
-void
-getlocal(void)
-{
-       int ret, s;
-       socklen_t l;
-
-       if (ipversion == 4) {
-               l = sizeof(struct sockaddr_in);
-               s = socket(PF_INET, SOCK_DGRAM, 0);
-       } else {
-               l = sizeof(struct sockaddr_in6);
-               s = socket(PF_INET6, SOCK_DGRAM, 0);
-       }
-       if (s < 0) {
-               perror("socket");
-               exit(1);
-       }
-       if ((ipversion == 4) && (isbroadcast != 0)) {
-               int on = 1;
-
-               ret = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
-               if (ret < 0) {
-                       perror("setsockopt(SO_BROADCAST)");
-                       exit(1);
-               }
-       }
-       ret = connect(s, (struct sockaddr *) &serveraddr, l);
-       if (ret < 0) {
-               perror("connect");
-               exit(1);
-       }
-       l = sizeof(localaddr);
-       ret = getsockname(s, (struct sockaddr *) &localaddr, &l);
-       if (ret < 0) {
-               perror("getsockname");
-               exit(1);
-       }
-       (void) close(s);
-       /* fill the local port */
-       if (ipversion == 4)
-               ((struct sockaddr_in *) &localaddr)->sin_port = htons(67);
-       else
-               ((struct sockaddr_in6 *) &localaddr)->sin6_port = htons(546);
-}
-
-/*
- * intermediate reporting
- * (note: an in-transit packet can be reported as dropped)
- */
-
-void
-reporting(void)
-{
-       dreport.tv_sec += report;
-
-       if (xscount2 == 0) {
-               printf("sent: %llu, received: %llu (drops: %lld)",
-                      (unsigned long long) xscount0,
-                      (unsigned long long) xrcount0,
-                      (long long) (xscount0 - xrcount0));
-               if (!ISC_TAILQ_EMPTY(&xrcvd0)) {
-                       double avg;
-
-                       avg = dsum0 / xrcount0;
-                       printf(" average: %.3f ms", avg * 1e3);
-               }
-       } else {
-               printf("sent: %llu/%llu received: %llu/%llu "
-                      "(drops: %lld/%lld)",
-                      (unsigned long long) xscount0,
-                      (unsigned long long) xscount2,
-                      (unsigned long long) xrcount0,
-                      (unsigned long long) xrcount2,
-                      (long long) (xscount0 - xrcount0),
-                      (long long) (xscount2 - xrcount2));
-               if (!ISC_TAILQ_EMPTY(&xrcvd0)) {
-                       double avg0, avg2;
-
-                       avg0 = dsum0 / xrcount0;
-                       if (xrcount2 != 0)
-                               avg2 = dsum2 / xrcount2;
-                       else
-                               avg2 = 0.;
-                       printf(" average: %.3f/%.3f ms",
-                              avg0 * 1e3, avg2 * 1e3);
-               }
-       }
-       printf("\n");
-}
-
-/*
- * SIGCHLD handler
- */
-
-void
-reapchild(int sig)
-{
-       int status;
-
-       sig = sig;
-       while (wait3(&status, WNOHANG, NULL) > 0)
-               /* continue */;
-}
-
-/*
- * SIGINT handler
- */
-
-void
-interrupt(int sig)
-{
-       sig = sig;
-       interrupted = 1;
-}
-
-/*
- * '-v' handler
- */
-
-void
-version(void)
-{
-       fprintf(stderr, "version 0.01\n");
-}
-
-/*
- * usage (from the wiki)
- */
-
-void
-usage(void)
-{
-       fprintf(stderr, "%s",
-"perfdhcp [-hv] [-4|-6] [-r<rate>] [-t<report>] [-R<range>] [-b<base>]\n"
-"    [-n<num-request>] [-p<test-period>] [-d<drop-time>] [-D<max-drop>]\n"
-"    [-l<local-addr|interface>] [-P<preload>] [-a<aggressivity>]\n"
-"    [-L<local-port>] [-s<seed>] [-i] [-B] [-c] [-1]\n"
-"    [-T<template-file>] [-X<xid-offset>] [-O<random-offset]\n"
-"    [-E<time-offset>] [-S<srvid-offset>] [-I<ip-offset>]\n"
-"    [-x<diagnostic-selector>] [-w<wrapped>] [server]\n"
-"\f\n"
-"The [server] argument is the name/address of the DHCP server to\n"
-"contact.  For DHCPv4 operation, exchanges are initiated by\n"
-"transmitting a DHCP DISCOVER to this address.\n"
-"\n"
-"For DHCPv6 operation, exchanges are initiated by transmitting a DHCP\n"
-"SOLICIT to this address.  In the DHCPv6 case, the special name 'all'\n"
-"can be used to refer to All_DHCP_Relay_Agents_and_Servers (the\n"
-"multicast address FF02::1:2), or the special name 'servers' to refer\n"
-"to All_DHCP_Servers (the multicast address FF05::1:3).  The [server]\n"
-"argument is optional only in the case that -l is used to specify an\n"
-"interface, in which case [server] defaults to 'all'.\n"
-"\n"
-"The default is to perform a single 4-way exchange, effectively pinging\n"
-"the server.\n"
-"The -r option is used to set up a performance test, without\n"
-"it exchanges are initiated as fast as possible.\n"
-"\n"
-"Options:\n"
-"-1: Take the server-ID option from the first received message.\n"
-"-4: DHCPv4 operation (default). This is incompatible with the -6 option.\n"
-"-6: DHCPv6 operation. This is incompatible with the -4 option.\n"
-"-a<aggressivity>: When the target sending rate is not yet reached,\n"
-"    control how many exchanges are initiated before the next pause.\n"
-"-b<base>: The base MAC, DUID, IP, etc, used to simulate different\n"
-"    clients.  This can be specified multiple times, each instance is\n"
-"    in the <type>=<value> form, for instance:\n"
-"    (and default) MAC=00:0c:01:02:03:04.\n"
-"-d<drop-time>: Specify the time after which a request is treated as\n"
-"    having been lost.  The value is given in seconds and may contain a\n"
-"    fractional component.  The default is 1 second.\n"
-"-E<time-offset>: Offset of the (DHCPv4) secs field / (DHCPv6)\n"
-"    elapsed-time option in the (second/request) template.\n"
-"    The value 0 disables it.\n"
-"-h: Print this help.\n"
-"-i: Do only the initial part of an exchange: DO or SA, depending on\n"
-"    whether -6 is given.\n"
-"-I<ip-offset>: Offset of the (DHCPv4) IP address in the requested-IP\n"
-"    option / (DHCPv6) IA_NA option in the (second/request) template.\n"
-"-l<local-addr|interface>: For DHCPv4 operation, specify the local\n"
-"    hostname/address to use when communicating with the server.  By\n"
-"    default, the interface address through which traffic would\n"
-"    normally be routed to the server is used.\n"
-"    For DHCPv6 operation, specify the name of the network interface\n"
-"    via which exchanges are initiated.\n"
-"-L<local-port>: Specify the local port to use\n"
-"    (the value 0 means to use the default).\n"
-"-O<random-offset>: Offset of the last octet to randomize in the template.\n"
-"-P<preload>: Initiate first <preload> exchanges back to back at startup.\n"
-"-r<rate>: Initiate <rate> DORA/SARR (or if -i is given, DO/SA)\n"
-"    exchanges per second.  A periodic report is generated showing the\n"
-"    number of exchanges which were not completed, as well as the\n"
-"    average response latency.  The program continues until\n"
-"    interrupted, at which point a final report is generated.\n"
-"-R<range>: Specify how many different clients are used. With 1\n"
-"    (the default), all requests seem to come from the same client.\n"
-"-s<seed>: Specify the seed for randomization, making it repeatable.\n"
-"-S<srvid-offset>: Offset of the server-ID option in the\n"
-"    (second/request) template.\n"
-"-T<template-file>: The name of a file containing the template to use\n"
-"    as a stream of hexadecimal digits.\n"
-"-v: Report the version number of this program.\n"
-"-w<wrapped>: Command to call with start/stop at the beginning/end of\n"
-"    the program.\n"
-"-x<diagnostic-selector>: Include extended diagnostics in the output.\n"
-"    <diagnostic-selector> is a string of single-keywords specifying\n"
-"    the operations for which verbose output is desired.  The selector\n"
-"    keyletters are:\n"
-"   * 'a': print the decoded command line arguments\n"
-"   * 'e': print the exit reason\n"
-"   * 'i': print rate processing details\n"
-"   * 'r': print randomization details\n"
-"   * 's': print first server-id\n"
-"   * 't': when finished, print timers of all successful exchanges\n"
-"   * 'T': when finished, print templates\n"
-"-X<xid-offset>: Transaction ID (aka. xid) offset in the template.\n"
-"\n"
-"DHCPv4 only options:\n"
-"-B: Force broadcast handling.\n"
-"\n"
-"DHCPv6 only options:\n"
-"-c: Add a rapid commit option (exchanges will be SA).\n"
-"\n"
-"The remaining options are used only in conjunction with -r:\n"
-"\n"
-"-D<max-drop>: Abort the test if more than <max-drop> requests have\n"
-"    been dropped.  Use -D0 to abort if even a single request has been\n"
-"    dropped.  If <max-drop> includes the suffix '%', it specifies a\n"
-"    maximum percentage of requests that may be dropped before abort.\n"
-"    In this case, testing of the threshold begins after 10 requests\n"
-"    have been expected to be received.\n"
-"-n<num-request>: Initiate <num-request> transactions.  No report is\n"
-"    generated until all transactions have been initiated/waited-for,\n"
-"    after which a report is generated and the program terminates.\n"
-"-p<test-period>: Send requests for the given test period, which is\n"
-"    specified in the same manner as -d.  This can be used as an\n"
-"    alternative to -n, or both options can be given, in which case the\n"
-"    testing is completed when either limit is reached.\n"
-"-t<report>: Delay in seconds between two periodic reports.\n"
-"\n"
-"Errors:\n"
-"- tooshort: received a too short message\n"
-"- orphans: received a message which doesn't match an exchange\n"
-"   (duplicate, late or not related)\n"
-"- locallimit: reached to local system limits when sending a message.\n"
-"\n"
-"Exit status:\n"
-"The exit status is:\n"
-"0 on complete success.\n"
-"1 for a general error.\n"
-"2 if an error is found in the command line arguments.\n"
-"3 if there are no general failures in operation, but one or more\n"
-"  exchanges are not successfully completed.\n");
-}
-
-/*
- * main function / entry point
- */
-
-int
-main(const int argc, char * const argv[])
-{
-       int opt, flags = 0, ret, i;
-       long long r;
-       char *pc;
-       extern char *optarg;
-       extern int optind;
-
-#define OPTIONS        "hv46r:t:R:b:n:p:d:D:l:P:a:L:s:iBc1T:X:O:E:S:I:x:w:"
-
-       /* decode options */
-       while ((opt = getopt(argc, argv, OPTIONS)) != -1)
-       switch (opt) {
-       case 'h':
-               usage();
-               exit(0);
-
-       case 'v':
-               version();
-               exit(0);
-
-       case '4':
-               if (ipversion == 6) {
-                       fprintf(stderr, "IP version already set to 6\n");
-                       usage();
-                       exit(2);
-               }
-               ipversion = 4;
-               break;
-
-       case '6':
-               if (ipversion == 4) {
-                       fprintf(stderr, "IP version already set to 4\n");
-                       usage();
-                       exit(2);
-               }
-               ipversion = 6;
-               break;
-
-       case 'r':
-               rate = atoi(optarg);
-               if (rate <= 0) {
-                       fprintf(stderr, "rate must be a positive integer\n");
-                       usage();
-                       exit(2);
-               }
-               break;
-
-       case 't':
-               report = atoi(optarg);
-               if (report <= 0) {
-                       fprintf(stderr, "report must be a positive integer\n");
-                       usage();
-                       exit(2);
-               }
-               break;
-
-       case 'R':
-               r = atoll(optarg);
-               if (r < 0) {
-                       fprintf(stderr,
-                               "range must not be a negative integer\n");
-                       usage();
-                       exit(2);
-               }
-               range = (uint32_t) r;
-               if ((range != 0) && (range != UINT32_MAX)) {
-                       uint32_t s = range + 1;
-                       uint64_t b = UINT32_MAX + 1, m;
-
-                       m = (b / s) * s;
-                       if (m == b)
-                               maxrandom = 0;
-                       else
-                               maxrandom = (uint32_t) m;
-               }
-               break;
-
-       case 'b':
-               if (basecnt > 3) {
-                       fprintf(stderr, "too many bases\n");
-                       usage();
-                       exit(2);
-               }
-               base[basecnt] = optarg;
-               decodebase();
-               basecnt++;
-               break;
-
-       case 'n':
-               numreq[gotnumreq] = atoi(optarg);
-               if (numreq[gotnumreq] <= 0) {
-                       fprintf(stderr,
-                               "num-request must be a positive integer\n");
-                       usage();
-                       exit(2);
-               }
-               gotnumreq = 1;
-               break;
-
-       case 'p':
-               period = atoi(optarg);
-               if (period <= 0) {
-                       fprintf(stderr,
-                               "test-period must be a positive integer\n");
-                       usage();
-                       exit(2);
-               }
-               break;
-
-       case 'd':
-               losttime[gotlosttime] = atof(optarg);
-               if (losttime[gotlosttime] <= 0.) {
-                       fprintf(stderr,
-                               "drop-time must be a positive number\n");
-                       usage();
-                       exit(2);
-               }
-               gotlosttime = 1;
-               break;
-
-       case 'D':
-               pc = strchr(optarg, '%');
-               if (pc != NULL) {
-                       *pc = '\0';
-                       maxpdrop[gotmaxdrop] = atof(optarg);
-                       if ((maxpdrop[gotmaxdrop] <= 0) ||
-                           (maxpdrop[gotmaxdrop] >= 100)) {
-                               fprintf(stderr,
-                                       "invalid drop-time percentage\n");
-                               usage();
-                               exit(2);
-                       }
-                       gotmaxdrop = 1;
-                       break;
-               }
-               maxdrop[gotmaxdrop] = atoi(optarg);
-               if (maxdrop[gotmaxdrop] <= 0) {
-                       fprintf(stderr,
-                               "max-drop must be a positive integer\n");
-                       usage();
-                       exit(2);
-               }
-               gotmaxdrop = 1;
-               break;
-
-       case 'l':
-               localname = optarg;
-               break;
-
-       case 'P':
-               preload = atoi(optarg);
-               if (preload < 0) {
-                       fprintf(stderr,
-                               "preload must not be a negative integer\n");
-                       usage();
-                       exit(2);
-               }
-               break;
-
-       case 'a':
-               aggressivity = atoi(optarg);
-               if (aggressivity <= 0) {
-                       fprintf(stderr,
-                               "aggressivity must be a positive integer\n");
-                       usage();
-                       exit(2);
-               }
-               break;
-
-       case 'L':
-               localport = atoi(optarg);
-               if (localport < 0) {
-                       fprintf(stderr,
-                               "local-port must not be a negative integer\n");
-                       usage();
-                       exit(2);
-               }
-               if (localport > (int) UINT16_MAX) {
-                       fprintf(stderr,
-                               "local-port must be lower than %d\n",
-                               (int) UINT16_MAX);
-                       usage();
-                       exit(2);
-               }
-               break;
-
-       case 's':
-               seeded = 1;
-               seed = (unsigned int) atol(optarg);
-               break;
-
-       case 'i':
-               simple = 1;
-               break;
-
-       case 'B':
-               isbroadcast = 1;
-               break;
-
-       case 'c':
-               rapidcommit = 1;
-               break;
-
-       case '1':
-               usefirst = 1;
-               break;
-
-       case 'T':
-               if (templatefile[0] != NULL) {
-                       if (templatefile[1] != NULL) {
-                               fprintf(stderr,
-                                       "template-files are already set\n");
-                               usage();
-                               exit(2);
-                       }
-                       templatefile[1] = optarg;
-               } else
-                       templatefile[0] = optarg;
-               break;
-
-       case 'X':
-               if (xidoffset[0] >= 0)
-                       i = 1;
-               else
-                       i = 0;
-               xidoffset[i] = atoi(optarg);
-               if (xidoffset[i] <= 0) {
-                       fprintf(stderr,
-                               "xid-offset must be a positive integer\n");
-                       usage();
-                       exit(2);
-               }
-               break;
-
-       case 'O':
-               if (rndoffset[0] >= 0)
-                       i = 1;
-               else
-                       i = 0;
-               rndoffset[i] = atoi(optarg);
-               if (rndoffset[i] < 3) {
-                       fprintf(stderr,
-                               "random-offset must be greater than 3\n");
-                       usage();
-                       exit(2);
-               }
-               break;
-
-       case 'E':
-               elpoffset = atoi(optarg);
-               if (elpoffset < 0) {
-                       fprintf(stderr,
-                               "time-offset must not be a "
-                               "negative integer\n");
-                       usage();
-                       exit(2);
-               }
-               break;
-
-       case 'S':
-               sidoffset = atoi(optarg);
-               if (sidoffset <= 0) {
-                       fprintf(stderr,
-                               "srvid-offset must be a positive integer\n");
-                       usage();
-                       exit(2);
-               }
-               break;
-
-       case 'I':
-               ripoffset = atoi(optarg);
-               if (ripoffset <= 0) {
-                       fprintf(stderr,
-                               "ip-offset must be a positive integer\n");
-                       usage();
-                       exit(2);
-               }
-               break;
-
-       case 'x':
-               diags = optarg;
-               break;
-
-       case 'w':
-               wrapped = optarg;
-               break;
-
-       default:
-               usage();
-               exit(2);
-       }
-
-       /* adjust some global variables */
-       if (ipversion == 0)
-               ipversion = 4;
-       if (templatefile[1] != NULL) {
-               if (xidoffset[1] < 0)
-                       xidoffset[1] = xidoffset[0];
-               if (rndoffset[1] < 0)
-                       rndoffset[1] = rndoffset[0];
-       }
-
-       /* when required, print the internal view of the command line */
-       if ((diags != NULL) && (strchr(diags, 'a') != NULL)) {
-               printf("IPv%d", ipversion);
-               if (simple != 0) {
-                       if (ipversion == 4)
-                               printf(" DO only");
-                       else
-                               printf(" SA only");
-               }
-               if (rate != 0)
-                       printf(" rate=%d", rate);
-               if (report != 0)
-                       printf(" report=%d", report);
-               if (range != 0) {
-                       if (strchr(diags, 'r') != NULL)
-                               printf(" range=0..%d [0x%x]",
-                                      range,
-                                      (unsigned int) maxrandom);
-                       else
-                               printf(" range=0..%d", range);
-               }
-               if (basecnt != 0)
-                       for (i = 0; i < basecnt; i++)
-                               printf(" base[%d]='%s'", i, base[i]);
-               if (gotnumreq != 0)
-                       printf(" num-request=%d,%d", numreq[0], numreq[1]);
-               if (period != 0)
-                       printf(" test-period=%d", period);
-               printf(" drop-time=%g,%g", losttime[0], losttime[1]);
-               if ((maxdrop[0] != 0) || (maxdrop[1] != 0))
-                       printf(" max-drop=%d,%d", maxdrop[0], maxdrop[1]);
-               if ((maxpdrop[0] != 0.) || (maxpdrop[1] != 0.))
-                       printf(" max-drop=%2.2f%%,%2.2f%%",
-                              maxpdrop[0], maxpdrop[1]);
-               if (preload != 0)
-                       printf(" preload=%d", preload);
-               printf(" aggressivity=%d", aggressivity);
-               if (localport != 0)
-                       printf(" local-port=%d", localport);
-               if (seeded)
-                       printf(" seed=%u", seed);
-               if (isbroadcast != 0)
-                       printf(" broadcast");
-               if (rapidcommit != 0)
-                       printf(" rapid-commit");
-               if (usefirst != 0)
-                       printf(" use-first");
-               if ((templatefile[0] != NULL) && (templatefile[1] == NULL))
-                       printf(" template-file='%s'", templatefile[0]);
-               else if (templatefile[1] != NULL)
-                       printf(" template-file='%s','%s'",
-                              templatefile[0], templatefile[1]);
-               if ((xidoffset[0] >= 0) && (xidoffset[1] < 0))
-                       printf(" xid-offset=%d", xidoffset[0]);
-               else if (xidoffset[1] >= 0)
-                       printf(" xid-offset=%d,%d",
-                              xidoffset[0], xidoffset[1]);
-               if ((rndoffset[0] >= 0) && (rndoffset[1] < 0))
-                       printf(" xid-offset=%d", rndoffset[0]);
-               else if (rndoffset[1] >= 0)
-                       printf(" xid-offset=%d,%d",
-                              rndoffset[0], rndoffset[1]);
-               if (elpoffset >= 0)
-                       printf(" time-offset=%d", elpoffset);
-               if (sidoffset >= 0)
-                       printf(" srvid-offset=%d", sidoffset);
-               if (ripoffset >= 0)
-                       printf(" ip-offset=%d", ripoffset);
-               printf(" diagnotic-selectors='%s'", diags);
-               if (wrapped != NULL)
-                       printf(" wrapped='%s'", wrapped);
-               printf("\n");
-       }
-
-       /* check DHCPv4 only options */
-       if ((ipversion != 4) && (isbroadcast != 0)) {
-               fprintf(stderr, "-b is not compatible with IPv6 (-6)\n");
-               usage();
-               exit(2);
-       }
-
-       /* check DHCPv6 only options */
-       if ((ipversion != 6) && (rapidcommit != 0)) {
-               fprintf(stderr, "-6 (IPv6) must be set to use -c\n");
-               usage();
-               exit(2);
-       }
-
-       /* check 4-packet (aka not simple) mode options */
-       if ((simple != 0) && (numreq[1] != 0)) {
-               fprintf(stderr,
-                       "second -n<num-request> is not compatible with -i\n");
-               usage();
-               exit(2);
-       }
-       if ((simple != 0) && (losttime[1] != 1.)) {
-               fprintf(stderr,
-                       "second -d<drop-time> is not compatible with -i\n");
-               usage();
-               exit(2);
-       }
-       if ((simple != 0) &&
-           ((maxdrop[1] != 0) || (maxpdrop[1] != 0.))) {
-               fprintf(stderr,
-                       "second -D<max-drop> is not compatible with -i\n");
-               usage();
-               exit(2);
-       }
-       if ((simple != 0) && (usefirst != 0)) {
-               fprintf(stderr,
-                       "-1 is not compatible with -i\n");
-               usage();
-               exit(2);
-       }
-       if ((simple != 0) && (templatefile[1] != NULL)) {
-               fprintf(stderr,
-                       "second -T<template-file> is not "
-                       "compatible with -i\n");
-               usage();
-               exit(2);
-       }
-       if ((simple != 0) && (xidoffset[1] >= 0)) {
-               fprintf(stderr,
-                       "second -X<xid-offset> is not compatible with -i\n");
-               usage();
-               exit(2);
-       }
-       if ((simple != 0) && (rndoffset[1] >= 0)) {
-               fprintf(stderr,
-                       "second -O<random-offset is not compatible with -i\n");
-               usage();
-               exit(2);
-       }
-       if ((simple != 0) && (elpoffset >= 0)) {
-               fprintf(stderr,
-                       "-E<time-offset> is not compatible with -i\n");
-               usage();
-               exit(2);
-       }
-       if ((simple != 0) && (sidoffset >= 0)) {
-               fprintf(stderr,
-                       "-S<srvid-offset> is not compatible with -i\n");
-               usage();
-               exit(2);
-       }
-       if ((simple != 0) && (ripoffset >= 0)) {
-               fprintf(stderr,
-                       "-I<ip-offset> is not compatible with -i\n");
-               usage();
-               exit(2);
-       }
-
-
-       /* check simple mode options */
-       if ((simple == 0) && (rapidcommit != 0)) {
-               fprintf(stderr, "-i must be set to use -c\n");
-               usage();
-               exit(2);
-       }
-
-       /* check rate '-r' options */
-       if ((rate == 0) && (report != 0)) {
-               fprintf(stderr,
-                       "-r<rate> must be set to use -t<report>\n");
-               usage();
-               exit(2);
-       }
-       if ((rate == 0) && ((numreq[0] != 0) || (numreq[1] != 0))) {
-               fprintf(stderr,
-                       "-r<rate> must be set to use -n<num-request>\n");
-               usage();
-               exit(2);
-       }
-       if ((rate == 0) && (period != 0)) {
-               fprintf(stderr,
-                       "-r<rate> must be set to use -p<test-period>\n");
-               usage();
-               exit(2);
-       }
-       if ((rate == 0) &&
-           ((maxdrop[0] != 0) || (maxdrop[1] != 0) ||
-            (maxpdrop[0] != 0.) || (maxpdrop[1] != 0.))) {
-               fprintf(stderr,
-                       "-r<rate> must be set to use -D<max-drop>\n");
-               usage();
-               exit(2);
-       }
-
-       /* check (first) template file options */
-       if ((templatefile[0] == NULL) && (xidoffset[0] >= 0)) {
-               fprintf(stderr,
-                       "-T<template-file> must be set to "
-                       "use -X<xid-offset>\n");
-               usage();
-               exit(2);
-       }
-       if ((templatefile[0] == NULL) && (rndoffset[0] >= 0)) {
-               fprintf(stderr,
-                       "-T<template-file> must be set to "
-                       "use -O<random-offset>\n");
-               usage();
-               exit(2);
-       }
-
-       /* check (second) template file options */
-       if ((templatefile[1] == NULL) && (elpoffset >= 0)) {
-               fprintf(stderr,
-                       "second/request -T<template-file> must be set to "
-                       "use -E<time-offset>\n");
-               usage();
-               exit(2);
-       }
-       if ((templatefile[1] == NULL) && (sidoffset >= 0)) {
-               fprintf(stderr,
-                       "second/request -T<template-file> must be set to "
-                       "use -S<srvid-offset>\n");
-               usage();
-               exit(2);
-       }
-       if ((templatefile[1] == NULL) && (ripoffset >= 0)) {
-               fprintf(stderr,
-                       "second/request -T<template-file> must be set to "
-                       "use -I<ip-offset>\n");
-               usage();
-               exit(2);
-       }
-
-       /* check various template file(s) and other condition(s) options */
-       if ((templatefile[0] != NULL) && (range > 0) && (rndoffset[0] < 0)) {
-               fprintf(stderr,
-                       "-O<random-offset> must be set when "
-                       "-T<template-file> and -R<range> are used\n");
-               usage();
-               exit(2);
-       }
-       if ((templatefile[1] != NULL) && (sidoffset < 0)) {
-               fprintf(stderr,
-                       "-S<srvid-offset> must be set when second "
-                       "-T<template-file> is used\n");
-               usage();
-               exit(2);
-       }
-       if ((templatefile[1] != NULL) && (ripoffset < 0)) {
-               fprintf(stderr,
-                       "-I<ip-offset> must be set when second "
-                       "-T<template-file> is used\n");
-               usage();
-               exit(2);
-       }
-
-       /* get the server argument */
-       if (optind < argc - 1) {
-               fprintf(stderr, "extra arguments?\n");
-               usage();
-               exit(2);
-       }
-       if (optind == argc - 1) {
-               servername = argv[optind];
-               /* decode special cases */
-               if ((ipversion == 4) &&
-                   (strcmp(servername, "all") == 0)) {
-                       flags = AI_NUMERICHOST;
-                       isbroadcast = 1;
-                       servername = "255.255.255.255";
-               } else if ((ipversion == 6) &&
-                          (strcmp(servername, "all") == 0)) {
-                       flags = AI_NUMERICHOST;
-                       servername = "FF02::1:2";
-               } else if ((ipversion == 6) &&
-                          (strcmp(servername, "servers") == 0)) {
-                       flags = AI_NUMERICHOST;
-                       servername = "FF05::1:3";
-               }
-       }
-
-       /* handle the local '-l' address/interface */
-       if (localname != NULL) {
-               /* given */
-               getlocaladdr();
-               if ((diags != NULL) && (strchr(diags, 'a') != NULL)) {
-                       if (isinterface)
-                               printf("interface='%s'\n", localname);
-                       else
-                               printf("local-addr='%s'\n", localname);
-               }
-               /* get the not given server from it */
-               if (servername == NULL) {
-                       if (isinterface && (ipversion == 4)) {
-                               flags = AI_NUMERICHOST;
-                               isbroadcast = 1;
-                               servername = "255.255.255.255";
-                       } else if (isinterface && (ipversion == 6)) {
-                               flags = AI_NUMERICHOST;
-                               servername = "FF02::1:2";
-                       } else {
-                               fprintf(stderr,
-                                       "without an interface "
-                                       "server is required\n");
-                               usage();
-                               exit(2);
-                       }
-               }
-       } else if (servername == NULL) {
-               fprintf(stderr, "without an interface server is required\n");
-               usage();
-               exit(2);
-       }
-       /* get the server socket address */
-       getserveraddr(flags);
-       /* finish local/server socket address stuff and print it */
-       if ((diags != NULL) && (strchr(diags, 'a') != NULL))
-               printf("server='%s'\n", servername);
-       if (localname == NULL)
-               getlocal();
-       if ((diags != NULL) && (strchr(diags, 'a') != NULL)) {
-               char addr[NI_MAXHOST];
-
-               ret = getnameinfo((struct sockaddr *) &localaddr,
-                                 sizeof(localaddr),
-                                 addr,
-                                 NI_MAXHOST,
-                                 NULL,
-                                 0,
-                                 NI_NUMERICHOST);
-               if (ret != 0) {
-                       fprintf(stderr,
-                               "can't get the local address: %s\n",
-                               gai_strerror(ret));
-                       exit(1);
-               }
-               printf("local address='%s'\n", addr);
-       }
-
-       /* initialize exchange structures */
-       inits();
-
-       /* get the socket descriptor and template(s) */
-       if (ipversion == 4) {
-               getsock4();
-               if (templatefile[0] == NULL)
-                       build_template_discover4();
-               else
-                       get_template_discover4();
-               if (simple == 0) {
-                       if (templatefile[1] == NULL)
-                               build_template_request4();
-                       else
-                               get_template_request4();
-               }
-       } else {
-               getsock6();
-               if (duid_prefix != NULL) {
-                       if (templatefile[0] == NULL)
-                               build_template_solicit6();
-                       else
-                               get_template_solicit6();
-                       if (simple == 0) {
-                               if (templatefile[1] == NULL)
-                                       build_template_request6();
-                               else
-                                       get_template_request6();
-                       }
-               }
-       }
-       /* sanity check */
-       if ((unsigned) sock > FD_SETSIZE) {
-               fprintf(stderr, "socket descriptor (%d) too large?!\n", sock);
-               exit(1);
-       }
-       /* make the socket descriptor not blocking */
-       flags = fcntl(sock, F_GETFL, 0);
-       if (flags < 0) {
-               perror("fcntl(F_GETFL)");
-               exit(1);
-       }
-       if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
-               perror("fcntl(F_SETFL)");
-               exit(1);
-       }
-
-       /* wrapped start */
-       if (wrapped != NULL) {
-               pid_t pid;
-
-               (void) signal(SIGCHLD, reapchild);
-               pid = fork();
-               if (pid < 0) {
-                       perror("fork");
-                       exit(1);
-               } else if (pid == 0)
-                       (void) execlp(wrapped, "start", (char *) NULL);
-       }
-
-       /* boot is done! */
-       if (clock_gettime(CLOCK_REALTIME, &boot) < 0) {
-               perror("clock_gettime(boot)");
-               exit(1);
-       }
-
-       /* compute the next intermediate reporting date */
-       if (report != 0) {
-               dreport.tv_sec = boot.tv_sec + report;
-               dreport.tv_nsec = boot.tv_nsec;
-       }
-
-       /* compute the DUID (the current date is needed) */
-       if ((ipversion == 6) && (duid_prefix == NULL)) {
-               uint32_t curdate;
-
-               duid_length = 14;
-               duid_prefix = (uint8_t *) malloc(duid_length);
-               if (duid_prefix == NULL) {
-                       perror("malloc(duid)");
-                       exit(1);
-               }
-               duid_prefix[0] = DHCP6_DUID_LLT >> 8;
-               duid_prefix[1] = DHCP6_DUID_LLT;
-               duid_prefix[2] = DHCP_HTYPE_ETHER >> 8;
-               duid_prefix[3] = DHCP_HTYPE_ETHER;
-               curdate = htonl(boot.tv_sec - DHCP6_DUID_EPOCH);
-               memcpy(duid_prefix + 4, &curdate, 4);
-               memcpy(duid_prefix + 8, mac_prefix, 6);
-               /* the DUID is in template(s) */
-               if (templatefile[0] == NULL)
-                       build_template_solicit6();
-               else
-                       get_template_solicit6();
-               if (simple == 0) {
-                       if (templatefile[1] == NULL)
-                               build_template_request6();
-                       else
-                               get_template_request6();
-               }
-       }
-               
-       /* seed the random generator */
-       if (seeded == 0)
-               seed = (unsigned int) (boot.tv_sec + boot.tv_nsec);
-       srandom(seed);
-
-       /* preload the server with at least one packet */
-       compsend = preload + 1;
-       for (i = 0; i <= preload; i++) {
-               if (ipversion == 4)
-                       ret = send4();
-               else
-                       ret = send6();
-               if (ret < 0) {
-                       /* failure at the first packet is fatal */
-                       if (i == 0) {
-                               fprintf(stderr,
-                                       "initial send failed: %s\n",
-                                       strerror(-ret));
-                               exit(1);
-                       }
-                       if ((errno == EAGAIN) ||
-                           (errno == EWOULDBLOCK) ||
-                           (errno == ENOBUFS) ||
-                           (errno == ENOMEM))
-                               locallimit++;
-                       fprintf(stderr, "preload send: %s\n", strerror(-ret));
-                       break;
-               }
-       }
-
-       /* required only before the interrupted flag check */
-       (void) signal(SIGINT, interrupt);
-
-       /* main loop */
-       for (;;) {
-               struct timespec now, ts;
-               fd_set rfds;
-
-               /* immediate loop exit conditions */
-               if (interrupted) {
-                       if ((diags != NULL) && (strchr(diags, 'e') != NULL))
-                               printf("interrupted\n");
-                       break;
-               }
-               if (fatal) {
-                       if ((diags != NULL) && (strchr(diags, 'e') != NULL))
-                               printf("got a fatal error\n");
-                       break;
-               }
-
-               /* get the date and use it */
-               if (clock_gettime(CLOCK_REALTIME, &now) < 0) {
-                       perror("clock_gettime(now)");
-                       fatal = 1;
-                       continue;
-               }
-               if ((period != 0) &&
-                   ((boot.tv_sec + period < now.tv_sec) ||
-                    ((boot.tv_sec + period == now.tv_sec) &&
-                     (boot.tv_nsec < now.tv_nsec)))) {
-                       if ((diags != NULL) && (strchr(diags, 'e') != NULL))
-                               printf("reached test-period\n");
-                       break;
-               }
-               if ((report != 0) &&
-                   ((dreport.tv_sec < now.tv_sec) ||
-                    ((dreport.tv_sec == now.tv_sec) &&
-                     (dreport.tv_nsec < now.tv_nsec))))
-                       reporting();
-
-               /* compute the delay for the next send */
-               due = last;
-               if (rate == 1)
-                       due.tv_sec += 1;
-               else if (rate != 0)
-                       due.tv_nsec += 1010000000 / rate;
-               else
-                       due.tv_nsec += 1;
-               while (due.tv_nsec >= 1000000000) {
-                       due.tv_sec += 1;
-                       due.tv_nsec -= 1000000000;
-               }
-               ts = due;
-               ts.tv_sec -= now.tv_sec;
-               ts.tv_nsec -= now.tv_nsec;
-               while (ts.tv_nsec < 0) {
-                       ts.tv_sec -= 1;
-                       ts.tv_nsec += 1000000000;
-               }
-               /* the send was already due? */
-               if (ts.tv_sec < 0) {
-                       ts.tv_sec = ts.tv_nsec = 0;
-                       latesent++;
-               }
-
-               /* pselect() */
-               FD_ZERO(&rfds);
-               FD_SET(sock, &rfds);
-               ret = pselect(sock + 1, &rfds, NULL, NULL, &ts, NULL);
-               if (ret < 0) {
-                       if (errno == EINTR)
-                               continue;
-                       perror("pselect");
-                       fatal = 1;
-                       continue;
-               }
-
-               /* packet(s) to receive */
-               while (ret == 1) {
-                       if (ipversion == 4)
-                               receive4();
-                       else
-                               receive6();
-                       if (recv(sock, ibuf, sizeof(ibuf), MSG_PEEK) <= 0)
-                               ret = 0;
-                       else
-                               multrcvd++;
-               }
-               if (fatal)
-                       continue;
-
-               /* check receive loop exit conditions */
-               if ((numreq[0] != 0) && ((int) xscount0 >= numreq[0])) {
-                       if ((diags != NULL) && (strchr(diags, 'e') != NULL))
-                               printf("reached num-request0\n");
-                       break;
-               }
-               if ((numreq[1] != 0) && ((int) xscount2 >= numreq[1])) {
-                       if ((diags != NULL) && (strchr(diags, 'e') != NULL))
-                               printf("reached num-request2\n");
-                       break;
-               }
-               if ((maxdrop[0] != 0) &&
-                   ((int) (xscount0 - xrcount0) > maxdrop[0])) {
-                       if ((diags != NULL) && (strchr(diags, 'e') != NULL))
-                               printf("reached max-drop%s (absolute)\n",
-                                      simple != 0 ? "" : "0");
-                       break;
-               }
-               if ((maxdrop[1] != 0) &&
-                   ((int) (xscount2 - xrcount2) > maxdrop[1])) {
-                       if ((diags != NULL) && (strchr(diags, 'e') != NULL))
-                               printf("reached max-drop2 (absolute)\n");
-                       break;
-               }
-               if ((maxpdrop[0] != 0.) &&
-                   (xscount0 > 10) &&
-                   (((100. * (xscount0 - xrcount0)) / xscount0)
-                       > maxpdrop[0])) {
-                       if ((diags != NULL) && (strchr(diags, 'e') != NULL))
-                               printf("reached max-drop%s (percent)\n",
-                                      simple != 0 ? "" : "0");
-                       break;
-               }
-               if ((maxpdrop[1] != 0.) &&
-                   (xscount2 > 10) &&
-                   (((100. * (xscount2 - xrcount2)) / xscount2)
-                       > maxpdrop[1])) {
-                       if ((diags != NULL) && (strchr(diags, 'e') != NULL))
-                               printf("reached max-drop2 (percent)\n");
-                       break;
-               }
-
-               /* compute how many packets to send */
-               if (clock_gettime(CLOCK_REALTIME, &now) < 0) {
-                       perror("clock_gettime(now2)");
-                       fatal = 1;
-                       continue;
-               }
-               if ((now.tv_sec > due.tv_sec) ||
-                   ((now.tv_sec == due.tv_sec) &&
-                    (now.tv_nsec >= due.tv_nsec))) {
-                       double tosend;
-
-                       if (rate != 0) {
-                               tosend = (now.tv_nsec - due.tv_nsec) / 1e9;
-                               tosend += now.tv_sec - due.tv_sec;
-                               tosend *= rate;
-                               tosend += 1;
-                               if (tosend > (double) aggressivity)
-                                       i = aggressivity;
-                               else
-                                       i = (int) tosend;
-                       } else
-                               i = aggressivity;
-                       compsend += i;
-                       /* send packets */
-                       for (;;) {
-                               if (ipversion == 4)
-                                       ret = send4();
-                               else
-                                       ret = send6();
-                               if (ret < 0) {
-                                       if ((errno == EAGAIN) ||
-                                           (errno == EWOULDBLOCK) ||
-                                           (errno == ENOBUFS) ||
-                                           (errno == ENOMEM))
-                                               locallimit++;
-                                       fprintf(stderr,
-                                               "send: %s\n", strerror(-ret));
-                                       break;
-                               }
-                               i--;
-                               if (i == 0)
-                                       break;
-                               /* check for late packets to receive */
-                               if (recv(sock, ibuf, sizeof(ibuf),
-                                        MSG_PEEK) > 0) {
-                                       latercvd++;
-                                       if (ipversion == 4)
-                                               receive4();
-                                       else
-                                               receive6();
-                               }
-                       }
-               } else
-                       /* there was no packet to send */
-                       shortwait++;
-       }
-
-       /* after main loop: finished */
-       if (clock_gettime(CLOCK_REALTIME, &finished) < 0)
-               perror("clock_gettime(finished)");
-
-       /* wrapped stop */
-       if (wrapped != NULL) {
-               pid_t pid;
-
-               pid = fork();
-               if (pid == 0)
-                       (void) execlp(wrapped, "stop", (char *) NULL);
-       }
-
-       /* main statictics */
-       if (xscount2 == 0)
-               printf("sent: %llu, received: %llu (drops: %lld)\n",
-                      (unsigned long long) xscount0,
-                      (unsigned long long) xrcount0,
-                      (long long) (xscount0 - xrcount0));
-       else
-               printf("sent: %llu/%llu, received: %llu/%llu "
-                      "(drops: %lld/%lld)\n",
-                      (unsigned long long) xscount0,
-                      (unsigned long long) xscount2,
-                      (unsigned long long) xrcount0,
-                      (unsigned long long) xrcount2,
-                      (long long) (xscount0 - xrcount0),
-                      (long long) (xscount2 - xrcount2));
-       printf("tooshort: %llu, orphans: %llu, local limits: %llu\n",
-              (unsigned long long) tooshort,
-              (unsigned long long) orphans,
-              (unsigned long long) locallimit);
-
-       /* print the rate */
-       if (finished.tv_sec != 0) {
-               double dall, erate;
-
-               dall = (finished.tv_nsec - boot.tv_nsec) / 1e9;
-               dall += finished.tv_sec - boot.tv_sec;
-               erate = xrcount0 / dall;
-               if (rate != 0)
-                       printf("rate: %f (expected %d)\n", erate, rate);
-               else
-                       printf("rate: %f\n", erate);
-       }
-
-       /* rate processing instrumentation */
-       if ((diags != NULL) && (strchr(diags, 'i') != NULL)) {
-               printf("latesent: %llu, compsend: %llu, shortwait: %llu\n"
-                      "multrcvd: %llu, latercvd: %llu, collected:%llu/%llu\n",
-                      (unsigned long long) latesent,
-                      (unsigned long long) compsend,
-                      (unsigned long long) shortwait,
-                      (unsigned long long) multrcvd,
-                      (unsigned long long) latercvd,
-                      (unsigned long long) collected[0],
-                      (unsigned long long) collected[1]);
-       }
-
-       /* round-time trip statistics */
-       if (xrcount2 != 0) {
-               double avg0, avg2, stddev0, stddev2;
-               
-               avg0 = dsum0 / xrcount0;
-               avg2 = dsum2 / xrcount2;
-               stddev0 = sqrt(dsumsq0 / xrcount0 - avg0 * avg0);
-               stddev2 = sqrt(dsumsq2 / xrcount2 - avg2 * avg2);
-               printf("RTT0: min/avg/max/stddev:  %.3f/%.3f/%.3f/%.3f ms\n",
-                      dmin0 * 1e3, avg0 * 1e3, dmax0 * 1e3, stddev0 * 1e3);
-               printf("RTT2: min/avg/max/stddev:  %.3f/%.3f/%.3f/%.3f ms\n",
-                      dmin2 * 1e3, avg2 * 1e3, dmax2 * 1e3, stddev2 * 1e3);
-       } else if (xrcount0 != 0) {
-               double avg, stddev;
-               
-               avg = dsum0 / xrcount0;
-               stddev = sqrt(dsumsq0 / xrcount0 - avg * avg);
-               printf("RTT%s: min/avg/max/stddev:  %.3f/%.3f/%.3f/%.3f ms\n",
-                      simple != 0 ? "" : "0",
-                      dmin0 * 1e3, avg * 1e3, dmax0 * 1e3, stddev * 1e3);
-       }
-
-       /* (first) server-ID option content */
-       if ((diags != NULL) && (strchr(diags, 's') != NULL) &&
-           !ISC_TAILQ_EMPTY(&xrcvd0)) {
-               struct exchange *x;
-               size_t n;
-
-               printf("server-id: ");
-               x = ISC_TAILQ_FIRST(&xrcvd0);
-               if (ipversion == 4)
-                       n = 2;
-               else
-                       n = 4;
-               for (; n < x->sidlen; n++)
-                       printf("%02hhx", x->sid[n]);
-               printf("\n");
-       }
-
-       /* all time-stamps */
-       if ((diags != NULL) && (strchr(diags, 't') != NULL) &&
-           !ISC_TAILQ_EMPTY(&xrcvd0)) {
-               struct exchange *x;
-
-               printf("\n\n");
-               ISC_TAILQ_FOREACH(x, &xrcvd0, gchain)
-                       printf("%ld.%09ld %ld.%09ld\n",
-                              (long) x->ts0.tv_sec, x->ts0.tv_nsec,
-                              (long) x->ts1.tv_sec, x->ts1.tv_nsec);
-
-       }
-       if ((diags != NULL) && (strchr(diags, 't') != NULL) &&
-           !ISC_TAILQ_EMPTY(&xrcvd2)) {
-               struct exchange *x;
-
-               printf("--\n");
-               ISC_TAILQ_FOREACH(x, &xrcvd2, gchain)
-                       printf("%ld.%09ld %ld.%09ld %ld.%09ld %ld.%09ld\n",
-                              (long) x->ts0.tv_sec, x->ts0.tv_nsec,
-                              (long) x->ts1.tv_sec, x->ts1.tv_nsec,
-                              (long) x->ts2.tv_sec, x->ts2.tv_nsec,
-                              (long) x->ts3.tv_sec, x->ts3.tv_nsec);
-
-       }
-       if ((diags != NULL) && (strchr(diags, 't') != NULL) &&
-           !ISC_TAILQ_EMPTY(&xrcvd0))
-               printf("\n\n");
-
-       /* template(s) */
-       if ((diags != NULL) && (strchr(diags, 'T') != NULL)) {
-               size_t n;
-
-               if (ipversion == 4) {
-                       printf("length = %zu\n", length_discover4);
-                       printf("xid offset = %d\n", DHCP_OFF_XID);
-                       printf("xid length = 4\n");
-                       printf("random offset = %zu\n", random_discover4);
-                       printf("content:\n");
-                       for (n = 0; n < length_discover4; n++) {
-                               printf("%s%02hhx",
-                                      (n & 15) == 0 ? "" : " ",
-                                      template_discover4[n]);
-                               if ((n & 15) == 15)
-                                       printf("\n");
-                       }
-                       if ((n & 15) != 15)
-                               printf("\n");
-                       if (simple != 0)
-                               goto doneT;
-                       printf("--\n");
-                       printf("length = %zu\n", length_request4);
-                       printf("xid offset = %d\n", DHCP_OFF_XID);
-                       printf("xid length = 4\n");
-                       printf("random offset = %zu\n", random_request4);
-                       if (elapsed_request4 > 0)
-                               printf("secs offset = %zu\n",
-                                      elapsed_request4);
-                       printf("server-id offset = %zu\n", serverid_request4);
-                       printf("server-id length = %d\n", DHCP_OPTLEN_SRVID);
-                       printf("content:\n");
-                       printf("requested-ip-address offset = %zu\n",
-                              reqaddr_request4);
-                       printf("requested-ip-address length = %d\n", 4);
-                       for (n = 0; n < length_request4; n++) {
-                               printf("%s%02hhx",
-                                      (n & 15) == 0 ? "" : " ",
-                                      template_request4[n]);
-                               if ((n & 15) == 15)
-                                       printf("\n");
-                       }
-                       printf("\n");
-               } else {
-                       printf("length = %zu\n", length_solicit6);
-                       printf("xid offset = %d\n", DHCP6_OFF_XID);
-                       printf("xid length = 3\n");
-                       printf("random offset = %zu\n", random_solicit6);
-                       for (n = 0; n < length_solicit6; n++) {
-                               printf("%s%02hhx",
-                                      (n & 15) == 0 ? "" : " ",
-                                      template_solicit6[n]);
-                               if ((n & 15) == 15)
-                                       printf("\n");
-                       }
-                       if ((n & 15) != 15)
-                               printf("\n");
-                       if (simple != 0)
-                               goto doneT;
-                       printf("--\n");
-                       printf("length = %zu\n", length_request6);
-                       printf("xid offset = %d\n", DHCP_OFF_XID);
-                       printf("xid length = 4\n");
-                       printf("random offset = %zu\n", random_request6);
-                       if (elapsed_request6 > 0)
-                               printf("secs offset = %zu\n",
-                                      elapsed_request6);
-                       printf("server-id offset = %zu\n", serverid_request6);
-                       printf("content:\n");
-                       printf("requested-ip-address offset = %zu\n",
-                              reqaddr_request6);
-                       for (n = 0; n < length_request6; n++) {
-                               printf("%s%02hhx",
-                                      (n & 15) == 0 ? "" : " ",
-                                      template_request6[n]);
-                               if ((n & 15) == 15)
-                                       printf("\n");
-                       }
-                       printf("\n");
-               }
-       }
-    doneT:
-
-       /* compute the exit code (and exit) */
-       if (fatal)
-               exit(1);
-       else if ((xscount0 == xrcount0) && (xscount2 == xrcount2))
-               exit(0);
-       else
-               exit(3);
-}
-
-#endif  /* HAVE_GETIFADDRS */