Project import
diff --git a/iputils/Android.mk b/iputils/Android.mk
new file mode 100644
index 0000000..b2a4f9a
--- /dev/null
+++ b/iputils/Android.mk
@@ -0,0 +1,41 @@
+LOCAL_PATH:= $(call my-dir)
+
+iputils_cflags := \
+  -D_GNU_SOURCE \
+  -Wno-missing-field-initializers \
+  -Wno-sign-compare \
+  -Wno-unused-parameter \
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS := $(iputils_cflags)
+LOCAL_MODULE := ping
+LOCAL_SRC_FILES := ping.c ping_common.c
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS := $(iputils_cflags)
+LOCAL_MODULE := ping6
+LOCAL_SHARED_LIBRARIES := libcrypto
+LOCAL_SRC_FILES := ping6.c ping_common.c
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS := $(iputils_cflags)
+LOCAL_MODULE := tracepath
+LOCAL_MODULE_TAGS := debug
+LOCAL_SRC_FILES := tracepath.c
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS := $(iputils_cflags)
+LOCAL_MODULE := tracepath6
+LOCAL_MODULE_TAGS := debug
+LOCAL_SRC_FILES := tracepath6.c
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS := $(iputils_cflags)
+LOCAL_MODULE := traceroute6
+LOCAL_MODULE_TAGS := debug
+LOCAL_SRC_FILES := traceroute6.c
+include $(BUILD_EXECUTABLE)
diff --git a/iputils/CleanSpec.mk b/iputils/CleanSpec.mk
new file mode 100644
index 0000000..b84e1b6
--- /dev/null
+++ b/iputils/CleanSpec.mk
@@ -0,0 +1,49 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/iputils/INSTALL b/iputils/INSTALL
new file mode 100644
index 0000000..e066de3
--- /dev/null
+++ b/iputils/INSTALL
@@ -0,0 +1,24 @@
+
+make
+make html
+make man
+lynx doc/iputils.html
+Read...
+
+
+
+If the first "make" fails, no problems:
+
+make html
+lynx doc/iputils.html
+Read section "Installation notes"...
+
+
+
+But if "make html" fails too, check that DocBook package is installed
+on your machine. If it is installed, and nevertheless "make" does not work,
+delete iputils and go to sleep. The next day repeat. If even full reset
+did not help, I bring apologies. :-)
+
+
+
diff --git a/iputils/MODULE_LICENSE_BSD b/iputils/MODULE_LICENSE_BSD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/iputils/MODULE_LICENSE_BSD
diff --git a/iputils/Makefile b/iputils/Makefile
new file mode 100644
index 0000000..89249f5
--- /dev/null
+++ b/iputils/Makefile
@@ -0,0 +1,252 @@
+#
+# Configuration
+#
+
+# CC
+CC=gcc
+# Path to parent kernel include files directory
+LIBC_INCLUDE=/usr/include
+# Libraries
+ADDLIB=
+# Linker flags
+LDFLAG_STATIC=-Wl,-Bstatic
+LDFLAG_DYNAMIC=-Wl,-Bdynamic
+LDFLAG_CAP=-lcap
+LDFLAG_GNUTLS=-lgnutls-openssl
+LDFLAG_CRYPTO=-lcrypto
+LDFLAG_IDN=-lidn
+LDFLAG_RESOLV=-lresolv
+LDFLAG_SYSFS=-lsysfs
+
+#
+# Options
+#
+
+# Capability support (with libcap) [yes|static|no]
+USE_CAP=yes
+# sysfs support (with libsysfs - deprecated) [no|yes|static]
+USE_SYSFS=no
+# IDN support (experimental) [no|yes|static]
+USE_IDN=no
+
+# Do not use getifaddrs [no|yes|static]
+WITHOUT_IFADDRS=no
+# arping default device (e.g. eth0) []
+ARPING_DEFAULT_DEVICE=
+
+# GNU TLS library for ping6 [yes|no|static]
+USE_GNUTLS=yes
+# Crypto library for ping6 [shared|static]
+USE_CRYPTO=shared
+# Resolv library for ping6 [yes|static]
+USE_RESOLV=yes
+# ping6 source routing (deprecated by RFC5095) [no|yes|RFC3542]
+ENABLE_PING6_RTHDR=no
+
+# rdisc server (-r option) support [no|yes]
+ENABLE_RDISC_SERVER=no
+
+# -------------------------------------
+# What a pity, all new gccs are buggy and -Werror does not work. Sigh.
+# CCOPT=-fno-strict-aliasing -Wstrict-prototypes -Wall -Werror -g
+CCOPT=-fno-strict-aliasing -Wstrict-prototypes -Wall -g
+CCOPTOPT=-O3
+GLIBCFIX=-D_GNU_SOURCE
+DEFINES=
+LDLIB=
+
+FUNC_LIB = $(if $(filter static,$(1)),$(LDFLAG_STATIC) $(2) $(LDFLAG_DYNAMIC),$(2))
+
+# USE_GNUTLS: DEF_GNUTLS, LIB_GNUTLS
+# USE_CRYPTO: LIB_CRYPTO
+ifneq ($(USE_GNUTLS),no)
+	LIB_CRYPTO = $(call FUNC_LIB,$(USE_GNUTLS),$(LDFLAG_GNUTLS))
+	DEF_CRYPTO = -DUSE_GNUTLS
+else
+	LIB_CRYPTO = $(call FUNC_LIB,$(USE_CRYPTO),$(LDFLAG_CRYPTO))
+endif
+
+# USE_RESOLV: LIB_RESOLV
+LIB_RESOLV = $(call FUNC_LIB,$(USE_RESOLV),$(LDFLAG_RESOLV))
+
+# USE_CAP:  DEF_CAP, LIB_CAP
+ifneq ($(USE_CAP),no)
+	DEF_CAP = -DCAPABILITIES
+	LIB_CAP = $(call FUNC_LIB,$(USE_CAP),$(LDFLAG_CAP))
+endif
+
+# USE_SYSFS: DEF_SYSFS, LIB_SYSFS
+ifneq ($(USE_SYSFS),no)
+	DEF_SYSFS = -DUSE_SYSFS
+	LIB_SYSFS = $(call FUNC_LIB,$(USE_SYSFS),$(LDFLAG_SYSFS))
+endif
+
+# USE_IDN: DEF_IDN, LIB_IDN
+ifneq ($(USE_IDN),no)
+	DEF_IDN = -DUSE_IDN
+	LIB_IDN = $(call FUNC_LIB,$(USE_IDN),$(LDFLAG_IDN))
+endif
+
+# WITHOUT_IFADDRS: DEF_WITHOUT_IFADDRS
+ifneq ($(WITHOUT_IFADDRS),no)
+	DEF_WITHOUT_IFADDRS = -DWITHOUT_IFADDRS
+endif
+
+# ENABLE_RDISC_SERVER: DEF_ENABLE_RDISC_SERVER
+ifneq ($(ENABLE_RDISC_SERVER),no)
+	DEF_ENABLE_RDISC_SERVER = -DRDISC_SERVER
+endif
+
+# ENABLE_PING6_RTHDR: DEF_ENABLE_PING6_RTHDR
+ifneq ($(ENABLE_PING6_RTHDR),no)
+	DEF_ENABLE_PING6_RTHDR = -DPING6_ENABLE_RTHDR
+ifeq ($(ENABLE_PING6_RTHDR),RFC3542)
+	DEF_ENABLE_PING6_RTHDR += -DPINR6_ENABLE_RTHDR_RFC3542
+endif
+endif
+
+# -------------------------------------
+IPV4_TARGETS=tracepath ping clockdiff rdisc arping tftpd rarpd
+IPV6_TARGETS=tracepath6 traceroute6 ping6
+TARGETS=$(IPV4_TARGETS) $(IPV6_TARGETS)
+
+CFLAGS=$(CCOPTOPT) $(CCOPT) $(GLIBCFIX) $(DEFINES)
+LDLIBS=$(LDLIB) $(ADDLIB)
+
+UNAME_N:=$(shell uname -n)
+LASTTAG:=$(shell git describe HEAD | sed -e 's/-.*//')
+TODAY=$(shell date +%Y/%m/%d)
+DATE=$(shell date --date $(TODAY) +%Y%m%d)
+TAG:=$(shell date --date=$(TODAY) +s%Y%m%d)
+
+
+# -------------------------------------
+.PHONY: all ninfod clean distclean man html check-kernel modules snapshot
+
+all: $(TARGETS)
+
+%.s: %.c
+	$(COMPILE.c) $< $(DEF_$(patsubst %.o,%,$@)) -S -o $@
+%.o: %.c
+	$(COMPILE.c) $< $(DEF_$(patsubst %.o,%,$@)) -o $@
+$(TARGETS): %: %.o
+	$(LINK.o) $^ $(LIB_$@) $(LDLIBS) -o $@
+
+# -------------------------------------
+# arping
+DEF_arping = $(DEF_SYSFS) $(DEF_CAP) $(DEF_IDN) $(DEF_WITHOUT_IFADDRS)
+LIB_arping = $(LIB_SYSFS) $(LIB_CAP) $(LIB_IDN)
+
+ifneq ($(ARPING_DEFAULT_DEVICE),)
+DEF_arping += -DDEFAULT_DEVICE=\"$(ARPING_DEFAULT_DEVICE)\"
+endif
+
+# clockdiff
+DEF_clockdiff = $(DEF_CAP)
+LIB_clockdiff = $(LIB_CAP)
+
+# ping / ping6
+DEF_ping_common = $(DEF_CAP) $(DEF_IDN)
+DEF_ping  = $(DEF_CAP) $(DEF_IDN) $(DEF_WITHOUT_IFADDRS)
+LIB_ping  = $(LIB_CAP) $(LIB_IDN)
+DEF_ping6 = $(DEF_CAP) $(DEF_IDN) $(DEF_WITHOUT_IFADDRS) $(DEF_ENABLE_PING6_RTHDR) $(DEF_CRYPTO)
+LIB_ping6 = $(LIB_CAP) $(LIB_IDN) $(LIB_RESOLV) $(LIB_CRYPTO)
+
+ping: ping_common.o
+ping6: ping_common.o
+ping.o ping_common.o: ping_common.h
+ping6.o: ping_common.h in6_flowlabel.h
+
+# rarpd
+DEF_rarpd =
+LIB_rarpd =
+
+# rdisc
+DEF_rdisc = $(DEF_ENABLE_RDISC_SERVER)
+LIB_rdisc =
+
+# tracepath
+DEF_tracepath = $(DEF_IDN)
+LIB_tracepath = $(LIB_IDN)
+
+# tracepath6
+DEF_tracepath6 = $(DEF_IDN)
+LIB_tracepath6 =
+
+# traceroute6
+DEF_traceroute6 = $(DEF_CAP) $(DEF_IDN)
+LIB_traceroute6 = $(LIB_CAP) $(LIB_IDN)
+
+# tftpd
+DEF_tftpd =
+DEF_tftpsubs =
+LIB_tftpd =
+
+tftpd: tftpsubs.o
+tftpd.o tftpsubs.o: tftp.h
+
+# -------------------------------------
+# ninfod
+ninfod:
+	@set -e; \
+		if [ ! -f ninfod/Makefile ]; then \
+			cd ninfod; \
+			./configure; \
+			cd ..; \
+		fi; \
+		$(MAKE) -C ninfod
+
+# -------------------------------------
+# modules / check-kernel are only for ancient kernels; obsolete
+check-kernel:
+ifeq ($(KERNEL_INCLUDE),)
+	@echo "Please, set correct KERNEL_INCLUDE"; false
+else
+	@set -e; \
+	if [ ! -r $(KERNEL_INCLUDE)/linux/autoconf.h ]; then \
+		echo "Please, set correct KERNEL_INCLUDE"; false; fi
+endif
+
+modules: check-kernel
+	$(MAKE) KERNEL_INCLUDE=$(KERNEL_INCLUDE) -C Modules
+
+# -------------------------------------
+man:
+	$(MAKE) -C doc man
+
+html:
+	$(MAKE) -C doc html
+
+clean:
+	@rm -f *.o $(TARGETS)
+	@$(MAKE) -C Modules clean
+	@$(MAKE) -C doc clean
+	@set -e; \
+		if [ -f ninfod/Makefile ]; then \
+			$(MAKE) -C ninfod clean; \
+		fi
+
+distclean: clean
+	@set -e; \
+		if [ -f ninfod/Makefile ]; then \
+			$(MAKE) -C ninfod distclean; \
+		fi
+
+# -------------------------------------
+snapshot:
+	@if [ x"$(UNAME_N)" != x"pleiades" ]; then echo "Not authorized to advance snapshot"; exit 1; fi
+	@echo "[$(TAG)]" > RELNOTES.NEW
+	@echo >>RELNOTES.NEW
+	@git log --no-merges $(LASTTAG).. | git shortlog >> RELNOTES.NEW
+	@echo >> RELNOTES.NEW
+	@cat RELNOTES >> RELNOTES.NEW
+	@mv RELNOTES.NEW RELNOTES
+	@sed -e "s/^%define ssdate .*/%define ssdate $(DATE)/" iputils.spec > iputils.spec.tmp
+	@mv iputils.spec.tmp iputils.spec
+	@echo "static char SNAPSHOT[] = \"$(TAG)\";" > SNAPSHOT.h
+	@$(MAKE) -C doc snapshot
+	@$(MAKE) man
+	@git commit -a -m "iputils-$(TAG)"
+	@git tag -s -m "iputils-$(TAG)" $(TAG)
+	@git archive --format=tar --prefix=iputils-$(TAG)/ $(TAG) | bzip2 -9 > ../iputils-$(TAG).tar.bz2
+
diff --git a/iputils/Modules/Makefile b/iputils/Modules/Makefile
new file mode 100644
index 0000000..eb84d21
--- /dev/null
+++ b/iputils/Modules/Makefile
@@ -0,0 +1,12 @@
+KERNEL_INCLUDE=/usr/src/linux/include
+
+
+CC=gcc
+CCOPT=-O2 -Wstrict-prototypes -Wall -Werror -fno-strict-aliasing -fno-common
+CFLAGS=-DMODULE -D__KERNEL__ -I$(KERNEL_INCLUDE) $(CCOPT)
+
+
+all: pg3.o
+
+clean:
+	@rm -f *.o
diff --git a/iputils/Modules/pg3.c b/iputils/Modules/pg3.c
new file mode 100644
index 0000000..73e88f9
--- /dev/null
+++ b/iputils/Modules/pg3.c
@@ -0,0 +1,735 @@
+/* pg3.c: Packet Generator for packet performance testing.
+ *
+ * Copyright 2001 by Robert Olsson <robert.olsson@its.uu.se>
+ *                                 Uppsala University, Sweden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ *
+ *
+ */
+
+/*
+
+A tool for loading a network with a preconfigurated packets. The tool is
+implemented as a linux module. Parameters as output device IPG interpacket
+packet, number of packets can be configured. pg uses already intalled
+device driver output routine.
+
+
+Additional hacking by:
+
+Jens.Laas@data.slu.se
+Improved by ANK. 010120.
+Improved by ANK even more. 010212.
+MAC address typo fixed. 010417 --ro
+
+
+TODO:
+* could release kernel lock yet.
+
+
+HOWTO:
+
+1. Compile module pg3.o and install it in the place where modprobe may find it.
+2. Cut script "ipg" (see below).
+3. Edit script to set preferred device and destination IP address.
+4. . ipg
+5. After this two commands are defined:
+   A. "pg" to start generator and to get results.
+   B. "pgset" to change generator parameters. F.e.
+      pgset "pkt_size 9014"   sets packet size to 9014
+      pgset "frags 5"         packet will consist of 5 fragments
+      pgset "count 200000"    sets number of packets to send
+      pgset "ipg 5000"        sets artificial gap inserted between packets
+			      to 5000 nanoseconds
+      pgset "dst 10.0.0.1"    sets IP destination address
+			      (BEWARE! This generator is very aggressive!)
+      pgset "dstmac 00:00:00:00:00:00"    sets MAC destination address
+      pgset stop    	      aborts injection
+
+  Also, ^C aborts generator.
+
+---- cut here
+
+#! /bin/sh
+
+modprobe pg3.o
+
+function pgset() {
+    local result
+
+    echo $1 > /proc/net/pg
+
+    result=`cat /proc/net/pg | fgrep "Result: OK:"`
+    if [ "$result" = "" ]; then
+	 cat /proc/net/pg | fgrep Result:
+    fi
+}
+
+function pg() {
+    echo inject > /proc/net/pg
+    cat /proc/net/pg
+}
+
+pgset "odev eth0"
+pgset "dst 0.0.0.0"
+
+---- cut here
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/inet.h>
+#include <asm/byteorder.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/proc_fs.h>
+#include <linux/if_arp.h>
+#include <net/checksum.h>
+
+static char version[] __initdata =
+  "pg3.c: v1.0 010812: Packet Generator for packet performance testing.\n";
+
+
+
+/* Parameters */
+
+char pg_outdev[32], pg_dst[32];
+int pkt_size=ETH_ZLEN;
+int nfrags=0;
+__u32 pg_count = 100000;  /* Default No packets to send */
+__u32 pg_ipg = 0;  /* Default Interpacket gap in nsec */
+
+/* Globar vars */
+
+int debug;
+int forced_stop;
+int pg_cpu_speed;
+int pg_busy;
+
+static __u8 hh[14] = {
+    0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB,
+
+    /* We fill in SRC address later */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x08, 0x00
+};
+
+unsigned char *pg_dstmac = hh;
+char pg_result[512];
+
+
+static struct net_device *pg_setup_inject(u32 *saddrp)
+{
+	int p1, p2;
+	struct net_device *odev;
+	u32 saddr;
+
+	rtnl_lock();
+	odev = __dev_get_by_name(pg_outdev);
+	if (!odev) {
+		sprintf(pg_result, "No such netdevice: \"%s\"", pg_outdev);
+		goto out_unlock;
+	}
+
+	if (odev->type != ARPHRD_ETHER) {
+		sprintf(pg_result, "Not ethernet device: \"%s\"", pg_outdev);
+		goto out_unlock;
+	}
+
+	if (!netif_running(odev)) {
+		sprintf(pg_result, "Device is down: \"%s\"", pg_outdev);
+		goto out_unlock;
+	}
+
+	for(p1=6,p2=0; p1 < odev->addr_len+6;p1++)
+		hh[p1]=odev->dev_addr[p2++];
+
+	saddr = 0;
+	if (odev->ip_ptr) {
+		struct in_device *in_dev = odev->ip_ptr;
+
+		if (in_dev->ifa_list)
+			saddr = in_dev->ifa_list->ifa_address;
+	}
+	atomic_inc(&odev->refcnt);
+	rtnl_unlock();
+
+	*saddrp = saddr;
+	return odev;
+
+out_unlock:
+	rtnl_unlock();
+	return NULL;
+}
+
+
+u32 idle_acc_lo, idle_acc_hi;
+
+void nanospin(int pg_ipg)
+{
+	u32 idle_start, idle;
+
+	idle_start = get_cycles();
+
+	for (;;) {
+		barrier();
+		idle = get_cycles() - idle_start;
+		if (idle*1000 >= pg_ipg*pg_cpu_speed)
+			break;
+	}
+	idle_acc_lo += idle;
+	if (idle_acc_lo < idle)
+		idle_acc_hi++;
+}
+
+int calc_mhz(void)
+{
+	struct timeval start, stop;
+	u32 start_s, elapsed;
+
+	do_gettimeofday(&start);
+	start_s = get_cycles();
+	do {
+		barrier();
+		elapsed = get_cycles() - start_s;
+		if (elapsed == 0)
+			return 0;
+	} while (elapsed < 1000*50000);
+	do_gettimeofday(&stop);
+	return elapsed/(stop.tv_usec-start.tv_usec+1000000*(stop.tv_sec-start.tv_sec));
+}
+
+static void cycles_calibrate(void)
+{
+	int i;
+
+	for (i=0; i<3; i++) {
+		int res = calc_mhz();
+		if (res > pg_cpu_speed)
+			pg_cpu_speed = res;
+	}
+}
+
+struct sk_buff *
+fill_packet(struct net_device *odev, __u32 saddr)
+{
+	struct sk_buff *skb;
+	__u8 *eth;
+	struct udphdr *udph;
+	int datalen, iplen;
+	struct iphdr *iph;
+
+	skb = alloc_skb(pkt_size+64+16, GFP_ATOMIC);
+	if (!skb) {
+		sprintf(pg_result, "No memory");
+		return NULL;
+	}
+
+	skb_reserve(skb, 16);
+
+	/*  Reserve for ethernet and IP header  */
+	eth = (__u8 *) skb_push(skb, 14);
+	iph = (struct iphdr*)skb_put(skb, sizeof( struct iphdr));
+	udph = (struct udphdr*)skb_put(skb, sizeof( struct udphdr));
+
+	/*  Copy the ethernet header  */
+	memcpy(eth, hh, 14);
+
+	datalen = pkt_size-14-20-8; /* Eth + IPh + UDPh */
+	if (datalen < 0)
+		datalen = 0;
+
+	udph->source= htons(9);
+	udph->dest= htons(9);
+	udph->len= htons(datalen+8); /* DATA + udphdr */
+	udph->check=0;  /* No checksum */
+
+	iph->ihl=5;
+	iph->version=4;
+	iph->ttl=3;
+	iph->tos=0;
+	iph->protocol = IPPROTO_UDP; /* UDP */
+	iph->saddr =  saddr;
+	iph->daddr =  in_aton(pg_dst);
+	iph->frag_off = 0;
+	iplen = 20 + 8 + datalen;
+	iph->tot_len = htons(iplen);
+	iph->check = 0;
+	iph->check = ip_fast_csum((void *)iph, iph->ihl);
+	skb->protocol = __constant_htons(ETH_P_IP);
+	skb->mac.raw = ((u8*)iph) - 14;
+	skb->dev = odev;
+	skb->pkt_type = PACKET_HOST;
+
+	if (nfrags<=0) {
+		skb_put(skb, datalen);
+	} else {
+		int frags = nfrags;
+		int i;
+
+		if (frags > MAX_SKB_FRAGS)
+			frags = MAX_SKB_FRAGS;
+		if (datalen > frags*PAGE_SIZE) {
+			skb_put(skb, datalen-frags*PAGE_SIZE);
+			datalen = frags*PAGE_SIZE;
+		}
+
+		i = 0;
+		while (datalen > 0) {
+			struct page *page = alloc_pages(GFP_KERNEL, 0);
+			skb_shinfo(skb)->frags[i].page = page;
+			skb_shinfo(skb)->frags[i].page_offset = 0;
+			skb_shinfo(skb)->frags[i].size = (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
+			datalen -= skb_shinfo(skb)->frags[i].size;
+			skb->len += skb_shinfo(skb)->frags[i].size;
+			skb->data_len += skb_shinfo(skb)->frags[i].size;
+			i++;
+			skb_shinfo(skb)->nr_frags = i;
+		}
+
+		while (i < frags) {
+			int rem;
+
+			if (i == 0)
+				break;
+
+			rem = skb_shinfo(skb)->frags[i-1].size/2;
+			if (rem == 0)
+				break;
+
+			skb_shinfo(skb)->frags[i-1].size -= rem;
+
+			skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i-1];
+			get_page(skb_shinfo(skb)->frags[i].page);
+			skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i-1].page;
+			skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i-1].size;
+			skb_shinfo(skb)->frags[i].size = rem;
+			i++;
+			skb_shinfo(skb)->nr_frags = i;
+		}
+	}
+
+	return skb;
+}
+
+
+static void pg_inject(void)
+{
+	u32 saddr;
+	struct net_device *odev;
+	struct sk_buff *skb;
+	struct timeval start, stop;
+	u32 total, idle;
+	int pc, lcount;
+
+	odev = pg_setup_inject(&saddr);
+	if (!odev)
+		return;
+
+	skb = fill_packet(odev, saddr);
+	if (skb == NULL)
+		goto out_reldev;
+
+	forced_stop = 0;
+	idle_acc_hi = 0;
+	idle_acc_lo = 0;
+	pc = 0;
+	lcount = pg_count;
+	do_gettimeofday(&start);
+
+	for(;;) {
+		spin_lock_bh(&odev->xmit_lock);
+		atomic_inc(&skb->users);
+		if (!netif_queue_stopped(odev)) {
+			if (odev->hard_start_xmit(skb, odev)) {
+				kfree_skb(skb);
+				if (net_ratelimit())
+					printk(KERN_INFO "Hard xmit error\n");
+			}
+			pc++;
+		} else {
+			kfree_skb(skb);
+		}
+		spin_unlock_bh(&odev->xmit_lock);
+
+		if (pg_ipg)
+			nanospin(pg_ipg);
+		if (forced_stop)
+			goto out_intr;
+		if (signal_pending(current))
+			goto out_intr;
+
+		if (--lcount == 0) {
+			if (atomic_read(&skb->users) != 1) {
+				u32 idle_start, idle;
+
+				idle_start = get_cycles();
+				while (atomic_read(&skb->users) != 1) {
+					if (signal_pending(current))
+						goto out_intr;
+					schedule();
+				}
+				idle = get_cycles() - idle_start;
+				idle_acc_lo += idle;
+				if (idle_acc_lo < idle)
+					idle_acc_hi++;
+			}
+			break;
+		}
+
+		if (netif_queue_stopped(odev) || current->need_resched) {
+			u32 idle_start, idle;
+
+			idle_start = get_cycles();
+			do {
+				if (signal_pending(current))
+					goto out_intr;
+				if (!netif_running(odev))
+					goto out_intr;
+				if (current->need_resched)
+					schedule();
+				else
+					do_softirq();
+			} while (netif_queue_stopped(odev));
+			idle = get_cycles() - idle_start;
+			idle_acc_lo += idle;
+			if (idle_acc_lo < idle)
+				idle_acc_hi++;
+		}
+	}
+
+	do_gettimeofday(&stop);
+
+	total = (stop.tv_sec - start.tv_sec)*1000000 +
+		stop.tv_usec - start.tv_usec;
+
+	idle = (((idle_acc_hi<<20)/pg_cpu_speed)<<12)+idle_acc_lo/pg_cpu_speed;
+
+	if (1) {
+		char *p = pg_result;
+
+		p += sprintf(p, "OK: %u(c%u+d%u) usec, %u (%dbyte,%dfrags) %upps %uMB/sec",
+			     total, total-idle, idle,
+			     pc, skb->len, skb_shinfo(skb)->nr_frags,
+			     ((pc*1000)/(total/1000)),
+			     (((pc*1000)/(total/1000))*pkt_size)/1024/1024
+			     );
+	}
+
+out_relskb:
+	kfree_skb(skb);
+out_reldev:
+	dev_put(odev);
+	return;
+
+out_intr:
+	sprintf(pg_result, "Interrupted");
+	goto out_relskb;
+}
+
+/* proc/net/pg */
+
+static struct proc_dir_entry *pg_proc_ent = 0;
+static struct proc_dir_entry *pg_busy_proc_ent = 0;
+
+int proc_pg_busy_read(char *buf , char **start, off_t offset,
+		      int len, int *eof, void *data)
+{
+	char *p;
+
+	p = buf;
+	p += sprintf(p, "%d\n", pg_busy);
+	*eof = 1;
+
+	return p-buf;
+}
+
+int proc_pg_read(char *buf , char **start, off_t offset,
+		 int len, int *eof, void *data)
+{
+	char *p;
+	int i;
+
+	p = buf;
+	p += sprintf(p, "Params: count=%u pkt_size=%u frags %d ipg %u odev \"%s\" dst %s dstmac ",
+		     pg_count, pkt_size, nfrags, pg_ipg,
+		     pg_outdev, pg_dst);
+	for(i=0;i<6;i++)
+		p += sprintf(p, "%02X%s", pg_dstmac[i], i == 5 ? "\n" : ":");
+
+	if(pg_result[0])
+		p += sprintf(p, "Result: %s\n", pg_result);
+	else
+		p += sprintf(p, "Result: Idle\n");
+	*eof = 1;
+	return p-buf;
+}
+
+int count_trail_chars(const char *buffer, unsigned int maxlen)
+{
+	int i;
+
+	for(i=0; i<maxlen;i++) {
+		switch(buffer[i]) {
+		case '\"':
+		case '\n':
+		case '\r':
+		case '\t':
+		case ' ':
+		case '=':
+			break;
+		default:
+			goto done;
+		}
+	}
+done:
+	return i;
+}
+
+unsigned long num_arg(const char *buffer, unsigned long maxlen,
+		      unsigned long *num)
+{
+	int i=0;
+	*num = 0;
+
+	for(; i<maxlen;i++) {
+		if( (buffer[i] >= '0') && (buffer[i] <= '9')) {
+			*num *= 10;
+			*num += buffer[i] -'0';
+		}
+		else
+			break;
+	}
+	return i;
+}
+
+int strn_len(const char *buffer, unsigned int maxlen)
+{
+	int i=0;
+
+	for(; i<maxlen;i++)
+		switch(buffer[i]) {
+		case '\"':
+		case '\n':
+		case '\r':
+		case '\t':
+		case ' ':
+			goto done_str;
+		default:
+		}
+done_str:
+	return i;
+}
+
+int proc_pg_write(struct file *file, const char *buffer,
+		     unsigned long count, void *data)
+{
+	int i=0, max, len;
+	char name[16], valstr[32];
+	unsigned long value = 0;
+
+	if (count < 1) {
+		sprintf(pg_result, "Wrong command format");
+		return -EINVAL;
+	}
+
+	max = count -i;
+	i += count_trail_chars(&buffer[i], max);
+
+	/* Read variable name */
+
+	len = strn_len(&buffer[i], sizeof(name)-1);
+	memset(name, 0, sizeof(name));
+	strncpy(name, &buffer[i], len);
+	i += len;
+
+	max = count -i;
+	len = count_trail_chars(&buffer[i], max);
+	i += len;
+
+	if (debug)
+		printk("pg: %s,%lu\n", name, count);
+
+	/* Only stop is allowed when we are running */
+
+	if(!strcmp(name, "stop")) {
+		forced_stop=1;
+		if (pg_busy)
+			strcpy(pg_result, "Stopping");
+		return count;
+	}
+
+	if (pg_busy) {
+		strcpy(pg_result, "Busy");
+		return -EINVAL;
+	}
+
+	if(!strcmp(name, "pkt_size")) {
+		len = num_arg(&buffer[i], 10, &value);
+		i += len;
+		if (value < 14+20+8)
+			value = 14+20+8;
+		pkt_size = value;
+		sprintf(pg_result, "OK: pkt_size=%u", pkt_size);
+		return count;
+	}
+	if(!strcmp(name, "frags")) {
+		len = num_arg(&buffer[i], 10, &value);
+		i += len;
+		nfrags = value;
+		sprintf(pg_result, "OK: frags=%u", nfrags);
+		return count;
+	}
+	if(!strcmp(name, "ipg")) {
+		len = num_arg(&buffer[i], 10, &value);
+		i += len;
+		pg_ipg = value;
+		sprintf(pg_result, "OK: ipg=%u", pg_ipg);
+		return count;
+	}
+	if(!strcmp(name, "count")) {
+		len = num_arg(&buffer[i], 10, &value);
+		i += len;
+		pg_count = value;
+		sprintf(pg_result, "OK: count=%u", pg_count);
+		return count;
+	}
+	if(!strcmp(name, "odev")) {
+		len = strn_len(&buffer[i], sizeof(pg_outdev)-1);
+		memset(pg_outdev, 0, sizeof(pg_outdev));
+		strncpy(pg_outdev, &buffer[i], len);
+		i += len;
+		sprintf(pg_result, "OK: odev=%s", pg_outdev);
+		return count;
+	}
+	if(!strcmp(name, "dst")) {
+		len = strn_len(&buffer[i], sizeof(pg_dst)-1);
+		memset(pg_dst, 0, sizeof(pg_dst));
+		strncpy(pg_dst, &buffer[i], len);
+		if(debug)
+			printk("pg: dst set to: %s\n", pg_dst);
+		i += len;
+		sprintf(pg_result, "OK: dst=%s", pg_dst);
+		return count;
+	}
+	if(!strcmp(name, "dstmac")) {
+		char *v = valstr;
+		unsigned char *m = pg_dstmac;
+
+		len = strn_len(&buffer[i], sizeof(valstr)-1);
+		memset(valstr, 0, sizeof(valstr));
+		strncpy(valstr, &buffer[i], len);
+		i += len;
+
+		for(*m = 0;*v && m < pg_dstmac+6;v++) {
+			if(*v >= '0' && *v <= '9') {
+				*m *= 16;
+				*m += *v - '0';
+			}
+			if(*v >= 'A' && *v <= 'F') {
+				*m *= 16;
+				*m += *v - 'A' + 10;
+			}
+			if(*v >= 'a' && *v <= 'f') {
+				*m *= 16;
+				*m += *v - 'a' + 10;
+			}
+			if(*v == ':') {
+				m++;
+				*m = 0;
+			}
+		}
+		sprintf(pg_result, "OK: dstmac");
+		return count;
+	}
+
+	if (!strcmp(name, "inject") || !strcmp(name, "start") ) {
+		MOD_INC_USE_COUNT;
+		pg_busy = 1;
+		strcpy(pg_result, "Starting");
+		pg_inject();
+		pg_busy = 0;
+		MOD_DEC_USE_COUNT;
+		return count;
+	}
+
+	sprintf(pg_result, "No such parameter \"%s\"", name);
+	return -EINVAL;
+}
+
+static int pg_init(void)
+{
+	printk(version);
+	cycles_calibrate();
+	if (pg_cpu_speed == 0) {
+		printk("pg3: Error: your machine does not have working cycle counter.\n");
+		return -EINVAL;
+	}
+	if(!pg_proc_ent) {
+		pg_proc_ent = create_proc_entry("net/pg", 0600, 0);
+		if (pg_proc_ent) {
+			pg_proc_ent->read_proc = proc_pg_read;
+			pg_proc_ent->write_proc = proc_pg_write;
+			pg_proc_ent->data = 0;
+		}
+		pg_busy_proc_ent = create_proc_entry("net/pg_busy", 0, 0);
+		if (pg_busy_proc_ent) {
+			pg_busy_proc_ent->read_proc = proc_pg_busy_read;
+			pg_busy_proc_ent->data = 0;
+		}
+	}
+	return 0;
+}
+
+void pg_cleanup(void)
+{
+	if (pg_proc_ent) {
+		remove_proc_entry("net/pg", NULL);
+		pg_proc_ent = 0;
+		remove_proc_entry("net/pg_busy", NULL);
+		pg_busy_proc_ent = 0;
+	}
+}
+
+module_init(pg_init);
+module_exit(pg_cleanup);
+
+
+#if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se");
+MODULE_DESCRIPTION("Packet Generator tool");
+MODULE_PARM(pg_count, "i");
+MODULE_PARM(pg_ipg, "i");
+MODULE_PARM(pg_cpu_speed, "i");
+#endif
+
+/*
+ * Local variables:
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c pg3.c"
+ * End:
+ */
diff --git a/iputils/NOTICE b/iputils/NOTICE
new file mode 100644
index 0000000..59bdf39
--- /dev/null
+++ b/iputils/NOTICE
@@ -0,0 +1,33 @@
+Copyright (c) 1989 The Regents of the University of California.
+All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Mike Muuss.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+     This product includes software developed by the University of
+     California, Berkeley and its contributors.
+4. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/iputils/RELNOTES b/iputils/RELNOTES
new file mode 100644
index 0000000..043fca2
--- /dev/null
+++ b/iputils/RELNOTES
@@ -0,0 +1,667 @@
+[s20121221]
+
+YOSHIFUJI Hideaki (14):
+      ninfod: Use unsigned int for digest.
+      ninfod: nanosleep(3) needs <time.h>.
+      ninfod: Too many arguments for syslog(3)/fprintf(3) via DEBUG().
+      ninfod: Fix several warnings on ununsed variables.
+      ping6: Print unknown ICMP type.
+      ping6: Fix flowlabel switch (-F option).
+      arping: Fix sysfs decimal/hexadecimal parser for libsysfs support.
+      ping6: Use GNU TLS by default.
+      ninfod: Fix memory leakage in error path.
+      ninfod: Fix off-by-one error to check possible programming error (again).
+      ninfod: Do not expose freed buffer to caller.
+      ping6: Ensure to initialize msghdr.
+      ninfod: Support GNU TLS.
+      ninfod: Allow printing usage without permission errors.
+
+
+[s20121207]
+
+YOSHIFUJI Hideaki (2):
+      RELNOTES: Typos.
+      ping,ping6: Check outgoing device only if specified.
+
+
+[s20121205]
+
+Jan Synacek (1):
+      ping,tracepath doc: Fix missing end tags.
+
+YOSHIFUJI Hideaki (35):
+      tracepath6: packet length option (-l) did not have any effect.
+      tracepath,tracepath6: Fix pktlen message.
+      tracepath,tracepath6: Use calloc(3) instead of using stack.
+      tracepath6: Ignore families other than IPv4 and IPv6.
+      ping6: Improve randomness of NI Nonce.
+      tracepath,tracepath6 doc: Fix default pktlen.
+      ping,rdisc: Optimize checksumming.
+      makefile: Static link support for crypto, resolv, cap and sysfs.
+      doc: Ajdust spaces around sqare brackets.
+      ping,rdisc: Use macro to get odd byte when checksumming.
+      ping6: Do not try to free memory pointed by uninitialized variable on error path.
+      arping: Allow building without default interface.
+      arping: No default interface by default.
+      arping: Allow printing usage without permission errors.
+      ping,ping6: Allow printing usage without permission errors.
+      ping,ping6: Fix cap_t leakage.
+      arping,ping,ping6: Do not ideologically check return value from cap_free,cap_{set,get}_flag().
+      arping: Fix sysfs_class leakage on error path.
+      arping: Some comments for new functions for finding devices support.
+      arping: Typo in type declaration.
+      makefile: Use call function for external libraries.
+      makefile: Add more comments.
+      arping: Ensure to fail if no appropriate device found with sysfs.
+      arping: Enforce user to specify device (-I) if multiple devices found.
+      Makefile: parameterize options for linking libraries.
+      Makefile: Use shell function instead if backquotes.
+      Makefile: Ensure to have same date when making snapshot.
+      spec: Maintainer does not use ipsec.spec.
+      spec: partially sync with fedora.
+      Makefile: Bump date in iputils.spec as well.
+      spec: Add exmple lines for suid-root installation
+      spec: Sort changelog.
+      ping: Exit on SO_BINDTODEVICE failure.
+      ping: Warn if kernel has selected source address from other interface.
+      ping: Clarify difference between -I device and -I addr.
+
+
+[s20121126]
+
+YOSHIFUJI Hideaki (5):
+      tracepath: Repair tracepath without -p option.
+      tracepath,tracepath6: -p option in usage.
+      ping,ping6: Use MAX_DUP_CHK directly, not using mx_dup_chk variable.
+      ping,ping6: Abstract received bitmap macros/definitions.
+      ping,ping6: Use __u64 or __u32 for bitmap.
+
+
+[s20121125]
+
+YOSHIFUJI Hideaki (30):
+      ping6: Use IN6_IS_ADDR_UNSPECIFIED() instead of our own helper function.
+      ping6 doc: Explicitly describe ping6 is IPv6 version if ping.
+      ping6: Deprecate source routing by default (RFC5095).
+      ping6: Use RFC3542 functions and definition for source routing.
+      ping6: Introduce niquery_is_enabled() for readability.
+      arping doc: interface is optional (-I option).
+      ping: Eliminate dirty hack to cope with ancient egcs bug.
+      Makefile: Fix missing right parenthes in comment.
+      arping: Fix build failure with USE_SYSFS=yes and/or WITHOUT_IFADDRS=yes
+      arping: Unify source files.
+      arping: Reorder functions and comment out unsued code.
+      arping,ping,ping6,tracepath,traceroute6 Makefile: Support static link of libidn by USE_IDN=static.
+      Makefile: Minimize statically linked libraries.
+      ping6: Do not clear seq check array twice for NI.
+      ping6: Use MD5_DIGEST_LENGTH instead of magic value 16.
+      ping6: Introduce helper functions for nonce in NI.
+      ping6: Introduce NI_NONCE_SIZE macro instead of magic value 8.
+      ping6: Ensure to call srand() to get some randomness in NI Nonce.
+      ping6: Generate different NI Nonce in each NI Query (Memory version).
+      ping6: Generate different NI Nonce in each NI Query (MD5 version).
+      ping6: Cache NI Nonce.
+      ping6: Print 'sequence number' embedded in NI Nonce.
+      ninfod: Do noy try to memcpy to self.
+      ninfod Makefile: More precise dependencies.
+      ninfod: Discard multicat packet outside linklocal scope.
+      ninfod: Apply default policy to refuse queries from global addresses.
+      ninfod: Normalize timespec for delay.
+      ninfod: Fix double-free without pthreads.
+      ninfod: Do not mix output from multiple threads.
+      ninfod: Employ internal buffer in stderrlog() for common case.
+
+
+[s20121121]
+
+Jan Synacek (2):
+      ping,ping6: Add newline to error message.
+      ping: Don't free an unintialized value.
+
+YOSHIFUJI Hideaki (31):
+      arping,clockdiff,ping,rarpd,rdisc,traceroute6 doc: s/CAP_NET_RAWIO/CAP_NET_RAW/.
+      ping,ping6: Do not assume radix point is denoted by '.' (-i option).
+      arping,ping,ping6,rdisc,traceroute6: Fix version string.
+      makefile: Give -fno-strict-aliasing to compiler by default.
+      ping6: Use SCOPE_DELIMITER.
+      Makefile: Remove -lm from ADDLIB.
+      rdisc_srv,Makefile: Fix build.
+      rdisc_srv,Makefile: Build rdisc_srv with make all.
+      arping: set_device_broadcast() does not need to store return value of sub-functions.
+      arping,Makefile: Make default interface configurable.
+      arping: Do not allow empty device name (-I option).
+      arping: Introduce check_ifflags() helper function.
+      arping: Introduce device structure to hold output device information.
+      arping: ALlow no default interface and select one by getifaddrs().
+      arping: Introduce 2nd (legacy) method to select interface by ioctls.
+      arping,Makefile: Allow build without getifaddrs() with WITHOUT_IFADDRS=yes.
+      Makefile: Use $< instead of $^ to complile C source code.
+      ping,ping6: Reorder command-line options in alphabetical order.
+      ping6: Show suboptions for Node Information Queries if -N suboption is invalid.
+      ping,ping6 doc: Readability for TOS (-Q) option.
+      rdisc: Missing new line after usage.
+      rdisc: Make rdisc with responder support if configured.
+      Makefile: distclean depends on clean.
+      Makefile: Default to -O3.
+      Makefile: Minimize options to gcc.
+      Makefile: Add rule to build assembly files.
+      arping,Makefile: 3rd legacy implementation to check network devices.
+      arping: Less ifdefs.
+      rdisc doc: Document -r, -p and -T options.
+      ping6: NI Subjecet address did not work (-N subject-{ipv6,ipv4] suboptions).
+      ping6: Ensure to detect subject type conflicts.
+
+
+[s20121114]
+
+Jan Synacek (2):
+      clockdiff: remove unused variable
+      ping: Wrap SO_BINDTODEVICE with the correct capability.
+
+YOSHIFUJI Hideaki (13):
+      ping: IP_MULTICAST_IF does not need CAP_NET_RAW.
+      ping6: Check ranges of flowlabel (-F option) and tclass (-Q option) arguments.
+      ping6: Accept 0x-notation for flowlabel (-F option) and tclass (-Q option) arguments.
+      ping,ping6: Manual update regarding -F, -Q and -N option.
+      arping,ping,ping6: Defer exitting to allow users to see usage.
+      arping,ping,ping6,ninfod: Change euid to uid (non-root) even if capabiliy is enabled.
+      ninfod: Add configure.
+      ninfod: libcap support to drop capabilities.
+      ninfod: Add run as user (-u user) option.
+      ninfod: Fix usage message.
+      arping,clockdiff,rarpd,rdisc,tftpd: Change RFC source to tools.ietf.org.
+      ninfod: Add ninfod(8) manpage.
+      makefile: Add ninfod, distclean targets.
+
+
+[s20121112]
+
+Sergey Fionov (1):
+      ping,ping6: Fallback to numeric addresses while exiting
+
+YOSHIFUJI Hideaki (18):
+      ping,ping6: Rework capability support and Make sure -m and -I options work.
+      ping,tracepath: Spelling fixes in manpages.
+      ping,ping6: Fix integer overflow with large interval value (-i option).
+      clockdiff: Make it work with large pid.
+      ping,ping6: Make in_pr_addr volatile.
+      arping: Do not quit too early with large deadline value (-w option).
+      arping: Maintain minimum capabilities for SO_BINDTODEVICE(-I option).
+      ping: Fix recorded route comparison.
+      arping: Use getifaddrs() to get broadcast address.
+      ping6: Fix typo in error message.
+      ping6: Generate NI Group Address and Subject Name at once.
+      ping,ping6: Unmask signals on start-up.
+      arping: Build with USE_CAP=no.
+      arping,ping,ping6,tracepath,tracepath6,traceroute6: Experimental IDN support.
+      ping6: IDN support for the Subject Name in NI Query.
+      tracepath,tracepath6: Introduce -p option for port.
+      ping6: Add missing definitions/declarations for flowlabel management (-F option).
+      makefile: Do not include merge commits in RELNOTES.
+
+
+[s20121106]
+
+YOSHIFUJI Hideaki (5):
+      ninfod: Attatch configure and renew config.h.in.
+      makefile: clean-up
+      tracepath6: Print reason on getadrinfo() failure.
+      ping,ping6: Fix hang with -f option.
+      ping: Make sure to print C if checksum failed with -f option.
+
+
+[s20121011]
+
+Jan Synacek (2):
+      ping,ping6: Defer the dropping if the "-m" is specified and correct capability is set.
+      ping: Fix typo in echo reply
+
+Ole Bjorn Hessen (1):
+      ping: report outstanding packets before sending next packet
+
+YOSHIFUJI Hideaki (32):
+      ping,ping6: Add -D to synopsis.
+      ping: More icmp code descriptions.
+      ping,ping6: Hide ipg/ewma info without packets received.
+      ping6: Remove unused variable.
+      ping6: Help for -N suboptions.
+      tracepath,tracepath6: Use argument type of int for field width specifier.
+      clockdiff: Call nice() before changing effective uid.
+      rdisc: Use fputs() instead of fprintf() to shut up gcc warning.
+      rarpd: Check return value of chdir().
+      makefile: Introduce new variable for capability support.
+      ping,ping6: Check return value of write(2) for stdout.
+      ping6,tracepath,tracepath6: Do not dereference type-punned pointer directly.
+      Makefile: host changed from takos to pleiades.
+      ping6: Provide enough buffer for dn_comp() and make NI Query with Name subject work.
+      ping6: Consolidate error path of niquery_option_subject_name_handler().
+      ninfod: Node Information Query (RFC4620) daemon from USAGI Project.
+      ninfod: struct in6_pktinfo requires -D_GNU_SOURCE.
+      ninfod: Use %zu format string for size_t variable.
+      ninfod: Add missing entry for ENABLE_SUPTYPES in config.h.in.
+      ninfod: Support newer environment supporting RFC3542.
+      ninfod: Fix format string for string returned from strerror(3).
+      ninfod: Check return value of fscanf(3).
+      ninfod: Fix off-by-one error to check possible programming error.
+      ninfod: Add datarootdir.
+      ninfod: Use __func__ instead of __FUNCTION__.
+      ninfod: Introduce ARRAY_SIZE macro for counting number of elements in an array.
+      ninfod: Delete ninfod.sh by make distclean, not by make clean.
+      ping6: Do not try to use result buffer when dn_comp(3) failed.
+      ping,ping6: ifdef guard for inline function for capability support and fix build with USE_CAP=no.
+      makefile: Do not use "-llib" dependency.
+      arping: build without sysfs support (USE_SYSFS=no).
+
+Ángel González (1):
+      iputils: Add capability dropping
+
+
+[s20101006]
+
+Chris Caputo (1):
+      ping,ping6: avoid gethostbyaddr during ping flood.
+
+Paul Martin (1):
+      arping: Set correct broadcast address.
+
+YOSHIFUJI Hideaki (4):
+      tracepath: Fix some small typos in tracepath.sgml.
+      ping: Fix resource consumption triggered by specially crafted ICMP Echo Reply (CVE-2010-2529)
+      Makefile: migrate main machine from beatrice to takos.
+      Makefile: Use newer git subcommand style instead of git-subcommand.
+
+
+[s20100418]
+
+YOSHIFUJI Hideaki (28):
+      ping6: Use IPV6_TCLASS to set outgoing traffic class if available.
+      ping: Make build_echo(), gather_statistics() more generic.
+      ping6: Experimental support for Node Information Queries (RFC4620).
+      ping: simplify usage hint.
+      ping: Rename constant names
+      Extend -N option for NI Query options.
+      ping6: Make length-check qtype-specific.
+      ping6: Remove too many spaces between names.
+      ping6: ping6_niquery.h needs asm/byteorder.h.
+      ping6: Support Qtypes for IPv6/IPv4 Addresses.
+      ping6: Split pr_niquery_reply().
+      ping6: Handle ICMPv6 code in NI Reply.
+      ping6: Add subject-ipv6 and subject-ipv4 NI sub-option for subject address.
+      ping6: Support subject name.
+      ping6: Free old memory when reassign pointers.
+      ping6: Always enable IPv6 Node Information Queries.
+      makefile: Do not always link libresolv and libcrypto.
+      ping,traceroute6,clockdiff: Enlarge hostname buffer.
+      ping6: do not allow too large packet size by -s option.
+      ping: needless space when printing usage.
+      rdisc: Fix typo in error message.
+      rdisc: Allow multiple addresses on one interface.
+      arping: Support link-layer type with larger link-layer address.
+      tracepath6: resolve target even if -n option is supplied.
+      tracepath,tracepath6: sync tracepath and tracepath6.
+      tracepath6: Make it more protocol independent.
+
+
+[s20100214]
+
+Jamal Hadi Salim (2):
+      ping: ping by mark
+      ping: ping by mark doc update
+
+Jamie Le Tual (1):
+      ping: set un.echo.id to network byte order
+
+YOSHIFUJI Hideaki (11):
+      [PING6,TRACEROUTE6]: Ignore error in setting IPV6_CHECKSUM socket option for ICMPv6 socket.
+      [PING6]: Use if_nametoindex() to convert ifname to ifindex.
+      [PING6]: Allow to specify source address with interface in a single -I option.
+      ping6: Try using IPV6_PKTINFO sticky option to specify outgoing interface.
+      rdisc: Use FOPEN_MAX if OPEN_MAX is undefined.
+      ping6: Fix source routing with source interface set.
+      ping,ping6: Don't print extra ', ' in finish().
+      tracepath: Fix documentation typo.
+      Use sysconf(_SC_OPEN_MAX) instead of OPEN_MAX.
+      ping,ping6: Add -D option to print timestamp.
+
+
+[s20071127]
+
+John Heffner (6):
+      [iputils] tracepath: Add length flag to set initial MTU.
+      [iputils] tracepath: Add documentation for the -l flag.
+      [iputils] tracepath: Use PMTUDISC_PROBE mode if it exists.
+      [iputils] tracepath: Document -n flag.
+      [iputils] tracepath: Fix asymm messages.
+      [iputils] tracepath: Re-probe at same TTL after MTU reduction.
+
+YOSHIFUJI Hideaki (8):
+      [DOC]: Delete duplicated lines in RELNOTES.
+      Fix white space errors.
+      [CLOCKDIFF,PING,RDISC,TRACEROUTE6]: Support uClibc.
+      [RARPD]: Fixed several signedness issues for char strings.
+      [PING]: Use inet_pton() instead of sscan().
+      [PING6]: Use IN6_IS_ADDR_xxx() macro.
+      [MAKEFILE]: Change authorized host to push snapshots.
+      [MAKEFILE]: Use git-archive instead of git-tar-tree.
+
+
+[s20070202]
+
+Mike Frysinger (2):
+      Use socklen_t in all the right places.
+      [IPG]: handle pktgen setup in newer kernels.
+
+Mitsuru Chinen (2):
+      [CLOCKDIFF]: Fix compilation errors about labels at end of compound statements.
+      [PING6]: Use getaddrinfo() for the name resolution of intermediate nodes.
+
+YOSHIFUJI Hideaki (9):
+      [MAKEFILE] Remove unused -I../include
+      [TRACEPATH] Print usage if we met incorrect option.
+      [PING6]: Fix compilation error with glibc-2.4 and later.
+      [PING6]: Use getaddrinfo() to allow scoped addresses
+      [PING6]: Ensure not to reverse-lookup if target is numeric address.
+
+
+[s20060512]
+
+YOSHIFUJI Hideaki:
+      [BUILD] Build with standard headers.
+      [ARPING,PING6] Build fix for some old systems.
+
+
+[s20060425]
+
+YOSHIFUJI Hideaki:
+      [TRACEROUTE6] Fix ICMPv6 type printing with -v option
+      [TRACEROUTE6] Mark ICMPv6 messages as known
+      [DOC] Maintainer / Contact change
+      [PING6,TRACEPATH6,TRACEROUTE6] Define SOL_IPV6,SOL_ICMPV6 where needed
+      [TRACEROUTE6] Fix source/destination address with -v option
+      [PING6,TRACEPATH6,TRACEROUTE6] Use new RFC3542 advanced API if available
+      [RDISC] Use proper type for is_directly_connected()
+      [PING,PING6] Use proper type for printf()
+      [TRACEROUTE6] Fix inet_pton() error handling
+      [TRACEROUTE6] Use minimum format if 0 is specified for datalen
+      [TRACEROUTE6] Optimize datalen sanity checking code
+      [TRACEPATH6] Use getaddrinfo() to allow scoped addresses
+      [RDISC] Use strerror(errno) instead of sys_errlist[errno]
+      [PING,PING6] Avoid using __constant_htons() if it is really needed
+      [TRACEPATH6] Fix format for subseconds
+      [ARPING,CLOCKDIFF,PING,PING6,TRACEROUTE6] Check return value from setuid().
+      [PING,PING6] ensure to initialize msg.
+      [MAKEFILE] Make snapshot using git
+
+
+[020927]
+* arping.sgml, some options were forgotten.
+* send seqno in network byte order. Me.
+* Mads Martin Jørgensen <mmj@suse.de> Recursive citation:
+"On request of Mads Martin Jørgensen <mmj@suse.de> I've added manpages
+pregenerated from the Docbook sources. One could argue it is redundant
+when the Docbook sources are also there, but the argument of not having
+to install Docbook on a very small system to get the man pages was
+convinving enough to me. To quote Mads Martin: "How would a system
+be without a man page for ping?" 
+  As a chilidish revenge from my side enjoy with cyrillic date in these
+  man pages. :-)
+* Ken Cox <jkc@redhat.com>. Bogus definition of SOCK_DRGAM&SOCK_STREAM on mips.
+* Error returned from recvmsg() resulted in a bogus printout in traceroute6. Me.
+* Use IPV6_CHECKSUM on icmp socket in traceroute6. Me.
+* Noah L. Meyerhans <frodo@morgul.net> Fix to doc.
+!* Noah L. Meyerhans <frodo@morgul.net> What is the problem with "long" triptime?
+!  Reporter does not respond. _Malignantly_.
+* Thomas 'Dent' Mirlacher <dent@cosy.sbg.ac.at> Ping did not exit sometimes!
+* Add option -W to override default 10 second linger timeout. Me.
+* Mads Martin Jørgensen <mmj@suse.de>: ping should not bind to autoselected
+  source address, it used to work when routing changes. Return classic
+  behaviour, option -B is added to enforce binding.
+* Pekka Savola <pekkas@netcore.fi> Forgotten \n messing output of ping6.
+* Noah L. Meyerhans <frodo@morgul.net> traceroute6 -q 1 did not work.
+* Pekka Savola <pekkas@netcore.fi> various sizeof() cleanups in traceroute6.c
+* "Dmitry V. Levin" <ldv@alt-linux.org> wrote:
+  > ping (as well as other utilities) may open raw socket with descriptor <=2;
+  > In case of suid-root, it can be used by malicious user to send data to
+  > this raw socket.
+  > 
+  > Yes, modern glibc and some kernels have workaround for it, but
+  > IMHO iputils shouldn't rely on this feature.
+  Taken into account, but no changes made.
+* "Tilman Heinrich" <tilHeinrich@web.de> said some scripts are broken
+  when word "packet" disappeared from "100% packet loss". Despite of
+  the inarguable fact that such scripts are truly mad and deserve breaking
+  (sigh... exit codes are too smart concept for script writers, I guess),
+  I have to recognize removing this word carrying zero information
+  was not enough motivated. Returned.
+* ping used to retry forever when seeing ENOBUFS/ENOMEM without explicitly
+  given deadline. Being logically correct it is bad in practice f.e. when
+  pinging buggy device which locked up with some packets in queue.
+  So, retry for a finite time... let is be lingertime. Fair? Me.
+* Two "messages" are sent to rpm maintainers to make their wrong patches
+  failed.
+* Fix from RH iputils-20001007-deadline.patch. It was lost in the latest
+  rpms btw.
+* Dax Kelson <dax@gurulabs.com>: added _unsupported_ option to comppile
+  rdisc_srv.
+
+[020124]
+* Michal Kochanowicz <michal@michal.waw.pl> typos in tracepath.8
+* Michael Wardle <michael.wardle@adacel.com>: undo silly change of ss000305
+  (printing rtt in some funny units). Michael noticed that "sec" is not
+  standard abbreviation for time units (bullshit, of course), but real concern
+  is that it is more difficult to interpret with a neglibible improvement
+  to appearance. So, do this as expected: in "ms".
+* Documentation. Wow! I did it. man pages are disassembled to docbook,
+  audited wrt real state, edited... and promised to be maintained
+  in sync with the state of utilities.
+
+[011202]
+* Utz Bacher <utz.bacher@de.ibm.com> Bitops in ping6 were wrong
+  on bigendian machines. Wow, luckily I forgot to acknowledge that patch
+  of 010805 which has gotten rid of kernel bitops and did this so wrongly.
+* Michael Bakunin <bakunin@maphiasoft.org> (:-))
+  found mud in tftpd.c, it will crash when directory supplied in argument
+  is longer ~512 symbols.
+* Alexandr D. Kanevskiy <kad@blackcatlinux.com>: buffer overflow
+  in clockdiff. Very stupid one, the overflowed buffer even was not used. :-)
+* Alexandr D. Kanevskiy <kad@blackcatlinux.com>: shit! Code recognizing
+  kernels with broken IP_RECVERR for raw sockets depended on race
+  and accused even good kernel of being buggy. :-)
+
+[011002]
+* Stepan Koltsov <yozh@mx1.ru>, tracepath/tracepth6 segfaulted when
+  used without address.
+* Alexandr D. Kanevskiy <kad@blackcatlinux.com>: arping printed
+  "permission denied" instead of showing help page to non-superuser.
+
+[010824]
+* Alexandr D. Kanevskiy <kad@blackcatlinux.com>: ping compiled
+  for linux-2.4 forgot to send the second packet, when used with linux-2.2
+* Chris Evans <chris@scary.beasts.org>: buffer overflow in traceroute6.
+  datalen was messed: counting header in half of places.
+  Funny, looking into LBL traceroute, it is even worse :-)
+* Alexandr D. Kanevskiy <kad@blackcatlinux.com>: relayed patches
+  by Solar_Diz. Only missing description of option -q is accepted.
+* <ipatel@wilnetonline.net> ping6 printed wrong mtu.
+* Alexandr D. Kanevskiy <kad@blackcatlinux.com>: -Werror is removed.
+  Newer gcc are buggy and generates some wrong warnings about
+  uninitalized variables, which are evidently initialized.
+
+[010805]
+* Some news from Pekka Savola <pekkas@netcore.fi> around setting tos bits.
+* arping: broadcast-only mode by Ard van Breemen <ard@telegraafnet.nl>
+* ping6/traceroute6: parse ICMP errors with extension headers (me)
+  traceroute6 works with size > mtu now. Nice.
+* ping: Erik Quanstrom <quanstro@clark.net>. Serious patch.
+  ping interval timer was not very broken, but very unintelligible.
+  Though I remade the code to use leaky bucket logic, which
+  is the most transparent one. Anyway, contribution by Eric is
+  the most important one since the previous release.
+  Short theory of operation: option -i (interval) sets rate r=1/interval pps,
+  option -l (preload) sets burst size of l packets. So, ping sends
+  at most r*t+l packets for an arbitrary interval t.
+  Default values: l=1 and for non-flood case: r=1pps, for flood r=infinity.
+  Nice? Exact algorithm is:
+
+  Let N(t) be l/r=l*i initially and N(t) grow continuously with time as:
+
+	N(t+delta) = min{l*i, N(t) + delta}
+
+  Packet can be transmitted only at the time t_* when 1/r=i <= N(t_*)
+  and in this case N(t) jumps:
+
+	N(t_* + 0) = N(t_* - 0) - i.
+
+  When interval is zero, algo degenerates allowing to send any amount
+  of messages. In this case we modify it using l as limit on amount
+  of unanswered requests and waiting for 10msec, when something is not
+  answered. Note that the last thing (10msec) is just to be compatible with
+  BSD manual pages. BSD ping is simply not able to avoid delay technically,
+  we are able now.
+
+  In result we got some new facilities:
+  * "-f -l 100" becomes very aggressive, in fact on good link
+    it holds permanently 100 packets in flight, which is very different
+    of earlier bevaviour (one packet in flight).
+  * -f and -i are not incompatible more. In fact, "-f -i 1" is equivalent
+    to plain ping, only output is different (dotted). Essentially,
+    change of output format is the only effect. "ping -i 0" is flood
+    printing output in normal format.
+
+  Moved some parts of code to ping_common.c. Common part is not fully
+  trivial now. :-)
+
+* ping: Ian Lynagh <igloo@earth.li>, larger and dynamic dup detector.
+  Also, Ian submitted two large patches, one fixing formatting, another
+  doing something with signedness/longness. Not now...
+  Later note: found not working. x + 7 / 8 :-). Sorry... dubious, withdrawn.
+  size of table increased to maximal value instead (8K of memory,
+  not a big deal).
+* tftpd: an old misprint. left@sbor.spb.su (Igor A. Lefterov)
+* clockdiff: do not fail, if reversed resolution failed.
+  Tommy Lacroix <tommyl@zeroknowledge.com>
+* ping: audible ping by Patrik Schilt <patrik@bnc.ch>
+  Patrick's option renamed to -a to align to freebsd.
+* ping: react to device queue overflows using IP_RECVERR. me.
+* ping: option -S allows to change sndbuf 
+* rarpd is moved from separate package here (people asked)
+* ping6: kernel style bitops are not used more.
+* Option -A to adapt to network rtt.
+* Use BPF, when multiple pings are detected.
+
+[001110]
+* ping is able to select TOS. By Pekka Savola <pekkas@netcore.fi>
+* tracepath* DNS names. By Pawel Krawczyk <kravietz@ceti.com.pl> and
+  Arkadiusz Miskiewicz <misiek@pld.org.pl>
+* ping6 is expected to be compiled with linux-2.2.
+
+[001011]
+* RH bugid#16677: segfault, when ping is used by root and size
+  is large enough. Fix is to allow oversize by root (it is necessary
+  to check kernel side), but clamp it at some safe value.
+
+[001010]
+* More bug fixes from Chris Evans <chris@ferret.lmh.ox.ac.uk>
+  - do not trust h_length returned by system resolver.
+    This value is meaningless in any case.
+  - ping: buffer overflow in fill()!!! Disgraceful bug.
+
+* ping: allow not-priviledged users to use broadcasts. It was paranoia.
+  Multicasts were allowed. 8)
+* ping: but force broadcasts&multicasts not to fragment. BSD does
+  not allow to do this to anyone, we still allow this for superuser.
+* Option -M to control path mtu discovery.
+
+[001007]
+* By Pekka Savola <pekkas@netcore.fi>
+  - SIOCGSTAMP/SO_TIMESTAMP are sensitive to bug in kernel.
+    When get_fast_time != gettimeofday (f.e. timestampless x86),
+    returned stamp can be out of sync with gettimeofday.
+    Workaround is not to use SIOCGSTAMP/SO_TIMESTAMP on such systems.
+  - fixes in man pages
+  - compiles under rh-7.0
+* Chris Evans <chris@ferret.lmh.ox.ac.uk>
+  - ping: possible buffer overflow in pr_addr().
+
+[000928]
+* Sorry. I have lost all the CVS with changes made since 000418.
+  If someone sent me a patch after this date, please, resubmit.
+  Restored from the last backup and mailboxes:
+
+* ping*, SO_TIMESTAMP support.
+* ping*, allow zero data length (reported by Damjan Lango <damjan.lango@hermes.si>)
+* iputils man and help updates. Pekka Savola <Pekka.Savola@netcore.fi>
+* ping.8, fix to ping man page. By Dadid Eisner <cradle@glue.umd.edu>
+* ping prints addresses in numeric, if destination is numeric.
+  Proposed by Tim Waugh <twaugh@meme.surrey.redhat.com>
+
+New:
+* ping: strncpy bug <typo@inferno.tusculum.edu>
+* arping: improvements by Charles Howes <croot@micro-logistics.com>
+	- a feature to arping: quit as soon as a reply is received.
+	- default to eth0.
+	- spelling
+
+[000418]
+* llsqrt() was buggy again!
+       (noticed by Sam Farin <sfarin@ratol.fi>)
+
+[000404]
+* tracepath*, "NURDUnet-gw" bug workaround.
+	(noticed by Vitaly E.Lavrov <lve@aanet.ru>)
+* tracepath*, handle case of routers initializing rtt to 128.
+	Vitaly E.Lavrov <lve@aanet.ru>
+* shadowed icmp_sock in ping6. James Morris <jmorris@@intercode.com.au>
+* Bug in ping -f, introduced with SO_RCVTIMEO. me.
+* llsqrt() (ping, ping6) was wrong yet. me.
+
+[000310]
+* Print mean deviation of RTT in ping/ping6.
+* Use SIOCGSTAMP in ping/ping6. Old behaviour calculating
+  true user-to-user latency is restored with option -U.
+  Reason for this stupid change is mainly political; people
+  wonder why freebsd has twice less latency on loopback.
+  If to follow along this line, we have to print rtt equal to 0. 8)
+  [ LATER NOTE: actually, the change is _right_ without any doubts.
+    Ping has another bug: nameresolver is blocking, so that
+    when it dies not respond, ping shows evenly increasing by 1 sec
+    RTT. It is very confusing (look through linux-kernel maillists
+    to count number of people, who were cheated by misconfigured dns). ]
+* Use SO_RCVTIMEO instead of poll() with ping/ping6 -f.
+* Added -V option to arping/ping/ping6/traceroute6/rdisc
+  to print snapshot number.
+
+[000305]
+* rdisc: ugly bug in getting interface list. me.
+* ping/ping6: ping -i N, N>=3 did not work. Jeff Jonson <jbj@redhat.com>
+* ping/ping6: microsecond rtt measurements. me.
+
+[000120]
+* ping/ping6: non-zero exit code even without -w.
+
+[991024]
+* Option "-i" to ping/ping6 takes fractional time now, so that
+  "ping -i 0.3 xxx" pings each 300 msec. The idea is by
+  Marc Boucher <marc@mbsi.ca>
+* alpha/glibc-2.1 alignment problems in ping are fixed (struct timeval
+  was wrongly aligned).
+
+[990915]
+* ping/ping6 worked only with kernels 2.3.15+ in 990824.
+
+[990824]
+* tftpd is added. It uses MSG_CONFIRM to confirm arp entries.
+* ping6: workaround for bug in some egcs versions.
+
+[990610]
+* ping: output buffer was too small for full sized ping.
+* ping: silly restriction on ping size is removed.
+
+[990530]
+* short man pages (Oleg M. Shumsky <oms@cp.tomsk.su>)
+* ping6: get and print hop limit of reply packets (ME)
+* rdisc deletes routes before exit with -TERM
+* ping/ping6: option -w TIMEOUT 
+* arping: exit with error, if received no replies in normal
+  (not DAD and not unsilicited ARP) mode.
+
diff --git a/iputils/SNAPSHOT.h b/iputils/SNAPSHOT.h
new file mode 100644
index 0000000..702ccd3
--- /dev/null
+++ b/iputils/SNAPSHOT.h
@@ -0,0 +1 @@
+static char SNAPSHOT[] = "s20121221";
diff --git a/iputils/arping.c b/iputils/arping.c
new file mode 100644
index 0000000..35408c1
--- /dev/null
+++ b/iputils/arping.c
@@ -0,0 +1,1233 @@
+/*
+ * arping.c
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ * 		YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ */
+
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <linux/sockios.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/signal.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h>
+#include <net/if_arp.h>
+#include <sys/uio.h>
+#ifdef CAPABILITIES
+#include <sys/prctl.h>
+#include <sys/capability.h>
+#endif
+
+#include <netdb.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifdef USE_SYSFS
+#include <sysfs/libsysfs.h>
+struct sysfs_devattr_values;
+#endif
+
+#ifndef WITHOUT_IFADDRS
+#include <ifaddrs.h>
+#endif
+
+#ifdef USE_IDN
+#include <idna.h>
+#include <locale.h>
+#endif
+
+#include "SNAPSHOT.h"
+
+static void usage(void) __attribute__((noreturn));
+
+#ifdef DEFAULT_DEVICE
+# define DEFAULT_DEVICE_STR	DEFAULT_DEVICE
+#else
+# define DEFAULT_DEVICE		NULL
+#endif
+
+struct device {
+	char *name;
+	int ifindex;
+#ifndef WITHOUT_IFADDRS
+	struct ifaddrs *ifa;
+#endif
+#ifdef USE_SYSFS
+	struct sysfs_devattr_values *sysfs;
+#endif
+};
+
+int quit_on_reply=0;
+struct device device = {
+	.name = DEFAULT_DEVICE,
+};
+char *source;
+struct in_addr src, dst;
+char *target;
+int dad, unsolicited, advert;
+int quiet;
+int count=-1;
+int timeout;
+int unicasting;
+int s;
+int broadcast_only;
+
+struct sockaddr_storage me;
+struct sockaddr_storage he;
+
+struct timeval start, last;
+
+int sent, brd_sent;
+int received, brd_recv, req_recv;
+
+#ifndef CAPABILITIES
+static uid_t euid;
+#endif
+
+#define MS_TDIFF(tv1,tv2) ( ((tv1).tv_sec-(tv2).tv_sec)*1000 + \
+			   ((tv1).tv_usec-(tv2).tv_usec)/1000 )
+
+#define OFFSET_OF(name,ele)	((size_t)(((name *)0)->ele))
+
+static inline socklen_t sll_len(size_t halen)
+{
+	socklen_t len = OFFSET_OF(struct sockaddr_ll, sll_addr) + halen;
+	if (len < sizeof(struct sockaddr_ll))
+		len = sizeof(struct sockaddr_ll);
+	return len;
+}
+
+#define SLL_LEN(hln)		sll_len(hln)
+
+void usage(void)
+{
+	fprintf(stderr,
+		"Usage: arping [-fqbDUAV] [-c count] [-w timeout] [-I device] [-s source] destination\n"
+		"  -f : quit on first reply\n"
+		"  -q : be quiet\n"
+		"  -b : keep broadcasting, don't go unicast\n"
+		"  -D : duplicate address detection mode\n"
+		"  -U : Unsolicited ARP mode, update your neighbours\n"
+		"  -A : ARP answer mode, update your neighbours\n"
+		"  -V : print version and exit\n"
+		"  -c count : how many packets to send\n"
+		"  -w timeout : how long to wait for a reply\n"
+		"  -I device : which ethernet device to use"
+#ifdef DEFAULT_DEVICE_STR
+			" (" DEFAULT_DEVICE_STR ")"
+#endif
+			"\n"
+		"  -s source : source ip address\n"
+		"  destination : ask for what ip address\n"
+		);
+	exit(2);
+}
+
+void set_signal(int signo, void (*handler)(void))
+{
+	struct sigaction sa;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = (void (*)(int))handler;
+	sa.sa_flags = SA_RESTART;
+	sigaction(signo, &sa, NULL);
+}
+
+#ifdef CAPABILITIES
+static const cap_value_t caps[] = { CAP_NET_RAW, };
+static cap_flag_value_t cap_raw = CAP_CLEAR;
+#endif
+
+void limit_capabilities(void)
+{
+#ifdef CAPABILITIES
+	cap_t cap_p;
+
+	cap_p = cap_get_proc();
+	if (!cap_p) {
+		perror("arping: cap_get_proc");
+		exit(-1);
+	}
+
+	cap_get_flag(cap_p, CAP_NET_RAW, CAP_PERMITTED, &cap_raw);
+
+	if (cap_raw != CAP_CLEAR) {
+		if (cap_clear(cap_p) < 0) {
+			perror("arping: cap_clear");
+			exit(-1);
+		}
+
+		cap_set_flag(cap_p, CAP_PERMITTED, 1, caps, CAP_SET);
+
+		if (cap_set_proc(cap_p) < 0) {
+			perror("arping: cap_set_proc");
+			if (errno != EPERM)
+				exit(-1);
+		}
+	}
+
+	if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+		perror("arping: prctl");
+		exit(-1);
+	}
+
+	if (setuid(getuid()) < 0) {
+		perror("arping: setuid");
+		exit(-1);
+	}
+
+	if (prctl(PR_SET_KEEPCAPS, 0) < 0) {
+		perror("arping: prctl");
+		exit(-1);
+	}
+
+	cap_free(cap_p);
+#else
+	euid = geteuid();
+#endif
+}
+
+int modify_capability_raw(int on)
+{
+#ifdef CAPABILITIES
+	cap_t cap_p;
+
+	if (cap_raw != CAP_SET)
+		return on ? -1 : 0;
+
+	cap_p = cap_get_proc();
+	if (!cap_p) {
+		perror("arping: cap_get_proc");
+		return -1;
+	}
+
+	cap_set_flag(cap_p, CAP_EFFECTIVE, 1, caps, on ? CAP_SET : CAP_CLEAR);
+
+	if (cap_set_proc(cap_p) < 0) {
+		perror("arping: cap_set_proc");
+		return -1;
+	}
+
+	cap_free(cap_p);
+#else
+	if (setuid(on ? euid : getuid())) {
+		perror("arping: setuid");
+		return -1;
+	}
+#endif
+	return 0;
+}
+
+static inline int enable_capability_raw(void)
+{
+	return modify_capability_raw(1);
+}
+
+static inline int disable_capability_raw(void)
+{
+	return modify_capability_raw(0);
+}
+
+void drop_capabilities(void)
+{
+#ifdef CAPABILITIES
+	cap_t cap_p = cap_init();
+
+	if (!cap_p) {
+		perror("arping: cap_init");
+		exit(-1);
+	}
+
+	if (cap_set_proc(cap_p) < 0) {
+		perror("arping: cap_set_proc");
+		exit(-1);
+	}
+
+	cap_free(cap_p);
+#else
+	if (setuid(getuid()) < 0) {
+		perror("arping: setuid");
+		exit(-1);
+	}
+#endif
+}
+
+int send_pack(int s, struct in_addr src, struct in_addr dst,
+	      struct sockaddr_ll *ME, struct sockaddr_ll *HE)
+{
+	int err;
+	struct timeval now;
+	unsigned char buf[256];
+	struct arphdr *ah = (struct arphdr*)buf;
+	unsigned char *p = (unsigned char *)(ah+1);
+
+	ah->ar_hrd = htons(ME->sll_hatype);
+	if (ah->ar_hrd == htons(ARPHRD_FDDI))
+		ah->ar_hrd = htons(ARPHRD_ETHER);
+	ah->ar_pro = htons(ETH_P_IP);
+	ah->ar_hln = ME->sll_halen;
+	ah->ar_pln = 4;
+	ah->ar_op  = advert ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
+
+	memcpy(p, &ME->sll_addr, ah->ar_hln);
+	p+=ME->sll_halen;
+
+	memcpy(p, &src, 4);
+	p+=4;
+
+	if (advert)
+		memcpy(p, &ME->sll_addr, ah->ar_hln);
+	else
+		memcpy(p, &HE->sll_addr, ah->ar_hln);
+	p+=ah->ar_hln;
+
+	memcpy(p, &dst, 4);
+	p+=4;
+
+	gettimeofday(&now, NULL);
+	err = sendto(s, buf, p-buf, 0, (struct sockaddr*)HE, SLL_LEN(ah->ar_hln));
+	if (err == p-buf) {
+		last = now;
+		sent++;
+		if (!unicasting)
+			brd_sent++;
+	}
+	return err;
+}
+
+void finish(void)
+{
+	if (!quiet) {
+		printf("Sent %d probes (%d broadcast(s))\n", sent, brd_sent);
+		printf("Received %d response(s)", received);
+		if (brd_recv || req_recv) {
+			printf(" (");
+			if (req_recv)
+				printf("%d request(s)", req_recv);
+			if (brd_recv)
+				printf("%s%d broadcast(s)",
+				       req_recv ? ", " : "",
+				       brd_recv);
+			printf(")");
+		}
+		printf("\n");
+		fflush(stdout);
+	}
+	if (dad)
+		exit(!!received);
+	if (unsolicited)
+		exit(0);
+	exit(!received);
+}
+
+void catcher(void)
+{
+	struct timeval tv, tv_s, tv_o;
+
+	gettimeofday(&tv, NULL);
+
+	if (start.tv_sec==0)
+		start = tv;
+
+	timersub(&tv, &start, &tv_s);
+	tv_o.tv_sec = timeout;
+	tv_o.tv_usec = 500 * 1000;
+
+	if (count-- == 0 || (timeout && timercmp(&tv_s, &tv_o, >)))
+		finish();
+
+	timersub(&tv, &last, &tv_s);
+	tv_o.tv_sec = 0;
+
+	if (last.tv_sec==0 || timercmp(&tv_s, &tv_o, >)) {
+		send_pack(s, src, dst,
+			  (struct sockaddr_ll *)&me, (struct sockaddr_ll *)&he);
+		if (count == 0 && unsolicited)
+			finish();
+	}
+	alarm(1);
+}
+
+void print_hex(unsigned char *p, int len)
+{
+	int i;
+	for (i=0; i<len; i++) {
+		printf("%02X", p[i]);
+		if (i != len-1)
+			printf(":");
+	}
+}
+
+int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
+{
+	struct timeval tv;
+	struct arphdr *ah = (struct arphdr*)buf;
+	unsigned char *p = (unsigned char *)(ah+1);
+	struct in_addr src_ip, dst_ip;
+
+	gettimeofday(&tv, NULL);
+
+	/* Filter out wild packets */
+	if (FROM->sll_pkttype != PACKET_HOST &&
+	    FROM->sll_pkttype != PACKET_BROADCAST &&
+	    FROM->sll_pkttype != PACKET_MULTICAST)
+		return 0;
+
+	/* Only these types are recognised */
+	if (ah->ar_op != htons(ARPOP_REQUEST) &&
+	    ah->ar_op != htons(ARPOP_REPLY))
+		return 0;
+
+	/* ARPHRD check and this darned FDDI hack here :-( */
+	if (ah->ar_hrd != htons(FROM->sll_hatype) &&
+	    (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
+		return 0;
+
+	/* Protocol must be IP. */
+	if (ah->ar_pro != htons(ETH_P_IP))
+		return 0;
+	if (ah->ar_pln != 4)
+		return 0;
+	if (ah->ar_hln != ((struct sockaddr_ll *)&me)->sll_halen)
+		return 0;
+	if (len < sizeof(*ah) + 2*(4 + ah->ar_hln))
+		return 0;
+	memcpy(&src_ip, p+ah->ar_hln, 4);
+	memcpy(&dst_ip, p+ah->ar_hln+4+ah->ar_hln, 4);
+	if (!dad) {
+		if (src_ip.s_addr != dst.s_addr)
+			return 0;
+		if (src.s_addr != dst_ip.s_addr)
+			return 0;
+		if (memcmp(p+ah->ar_hln+4, ((struct sockaddr_ll *)&me)->sll_addr, ah->ar_hln))
+			return 0;
+	} else {
+		/* DAD packet was:
+		   src_ip = 0 (or some src)
+		   src_hw = ME
+		   dst_ip = tested address
+		   dst_hw = <unspec>
+
+		   We fail, if receive request/reply with:
+		   src_ip = tested_address
+		   src_hw != ME
+		   if src_ip in request was not zero, check
+		   also that it matches to dst_ip, otherwise
+		   dst_ip/dst_hw do not matter.
+		 */
+		if (src_ip.s_addr != dst.s_addr)
+			return 0;
+		if (memcmp(p, ((struct sockaddr_ll *)&me)->sll_addr, ((struct sockaddr_ll *)&me)->sll_halen) == 0)
+			return 0;
+		if (src.s_addr && src.s_addr != dst_ip.s_addr)
+			return 0;
+	}
+	if (!quiet) {
+		int s_printed = 0;
+		printf("%s ", FROM->sll_pkttype==PACKET_HOST ? "Unicast" : "Broadcast");
+		printf("%s from ", ah->ar_op == htons(ARPOP_REPLY) ? "reply" : "request");
+		printf("%s [", inet_ntoa(src_ip));
+		print_hex(p, ah->ar_hln);
+		printf("] ");
+		if (dst_ip.s_addr != src.s_addr) {
+			printf("for %s ", inet_ntoa(dst_ip));
+			s_printed = 1;
+		}
+		if (memcmp(p+ah->ar_hln+4, ((struct sockaddr_ll *)&me)->sll_addr, ah->ar_hln)) {
+			if (!s_printed)
+				printf("for ");
+			printf("[");
+			print_hex(p+ah->ar_hln+4, ah->ar_hln);
+			printf("]");
+		}
+		if (last.tv_sec) {
+			long usecs = (tv.tv_sec-last.tv_sec) * 1000000 +
+				tv.tv_usec-last.tv_usec;
+			long msecs = (usecs+500)/1000;
+			usecs -= msecs*1000 - 500;
+			printf(" %ld.%03ldms\n", msecs, usecs);
+		} else {
+			printf(" UNSOLICITED?\n");
+		}
+		fflush(stdout);
+	}
+	received++;
+	if (FROM->sll_pkttype != PACKET_HOST)
+		brd_recv++;
+	if (ah->ar_op == htons(ARPOP_REQUEST))
+		req_recv++;
+	if (quit_on_reply)
+		finish();
+	if(!broadcast_only) {
+		memcpy(((struct sockaddr_ll *)&he)->sll_addr, p, ((struct sockaddr_ll *)&me)->sll_halen);
+		unicasting=1;
+	}
+	return 1;
+}
+
+#ifdef USE_SYSFS
+union sysfs_devattr_value {
+	unsigned long	ulong;
+	void		*ptr;
+};
+
+enum {
+	SYSFS_DEVATTR_IFINDEX,
+	SYSFS_DEVATTR_FLAGS,
+	SYSFS_DEVATTR_ADDR_LEN,
+#if 0
+	SYSFS_DEVATTR_TYPE,
+	SYSFS_DEVATTR_ADDRESS,
+#endif
+	SYSFS_DEVATTR_BROADCAST,
+	SYSFS_DEVATTR_NUM
+};
+
+struct sysfs_devattr_values
+{
+	char *ifname;
+	union sysfs_devattr_value	value[SYSFS_DEVATTR_NUM];
+};
+
+static int sysfs_devattr_ulong_dec(char *ptr, struct sysfs_devattr_values *v, unsigned idx);
+static int sysfs_devattr_ulong_hex(char *ptr, struct sysfs_devattr_values *v, unsigned idx);
+static int sysfs_devattr_macaddr(char *ptr, struct sysfs_devattr_values *v, unsigned idx);
+
+struct sysfs_devattrs {
+	const char *name;
+	int (*handler)(char *ptr, struct sysfs_devattr_values *v, unsigned int idx);
+	int free;
+} sysfs_devattrs[SYSFS_DEVATTR_NUM] = {
+	[SYSFS_DEVATTR_IFINDEX] = {
+		.name		= "ifindex",
+		.handler	= sysfs_devattr_ulong_dec,
+	},
+	[SYSFS_DEVATTR_ADDR_LEN] = {
+		.name		= "addr_len",
+		.handler	= sysfs_devattr_ulong_dec,
+	},
+	[SYSFS_DEVATTR_FLAGS] = {
+		.name		= "flags",
+		.handler	= sysfs_devattr_ulong_hex,
+	},
+#if 0
+	[SYSFS_DEVATTR_TYPE] = {
+		.name		= "type",
+		.handler	= sysfs_devattr_ulong_dec,
+	},
+	[SYSFS_DEVATTR_ADDRESS] = {
+		.name		= "address",
+		.handler	= sysfs_devattr_macaddr,
+		.free		= 1,
+	},
+#endif
+	[SYSFS_DEVATTR_BROADCAST] = {
+		.name		= "broadcast",
+		.handler	= sysfs_devattr_macaddr,
+		.free		= 1,
+	},
+};
+#endif
+
+/*
+ * find_device()
+ *
+ * This function checks 1) if the device (if given) is okay for ARP,
+ * or 2) find fist appropriate device on the system.
+ *
+ * Return value:
+ *	>0	: Succeeded, and appropriate device not found.
+ *		  device.ifindex remains 0.
+ *	0	: Succeeded, and approptiate device found.
+ *		  device.ifindex is set.
+ *	<0	: Failed.  Support not found, or other
+ *		: system error.  Try other method.
+ *
+ * If an appropriate device found, it is recorded inside the
+ * "device" variable for later reference.
+ *
+ * We have several implementations for this.
+ *	by_ifaddrs():	requires getifaddr() in glibc, and rtnetlink in
+ *			kernel. default and recommended for recent systems.
+ *	by_sysfs():	requires libsysfs , and sysfs in kernel.
+ *	by_ioctl():	unable to list devices without ipv4 address; this
+ *			means, you need to supply the device name for
+ *			DAD purpose.
+ */
+/* Common check for ifa->ifa_flags */
+static int check_ifflags(unsigned int ifflags, int fatal)
+{
+	if (!(ifflags & IFF_UP)) {
+		if (fatal) {
+			if (!quiet)
+				printf("Interface \"%s\" is down\n", device.name);
+			exit(2);
+		}
+		return -1;
+	}
+	if (ifflags & (IFF_NOARP | IFF_LOOPBACK)) {
+		if (fatal) {
+			if (!quiet)
+				printf("Interface \"%s\" is not ARPable\n", device.name);
+			exit(dad ? 0 : 2);
+		}
+		return -1;
+	}
+	return 0;
+}
+
+static int find_device_by_ifaddrs(void)
+{
+#ifndef WITHOUT_IFADDRS
+	int rc;
+	struct ifaddrs *ifa0, *ifa;
+	int count = 0;
+
+	rc = getifaddrs(&ifa0);
+	if (rc) {
+		perror("getifaddrs");
+		return -1;
+	}
+
+	for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
+		if (!ifa->ifa_addr)
+			continue;
+		if (ifa->ifa_addr->sa_family != AF_PACKET)
+			continue;
+		if (device.name && ifa->ifa_name && strcmp(ifa->ifa_name, device.name))
+			continue;
+
+		if (check_ifflags(ifa->ifa_flags, device.name != NULL) < 0)
+			continue;
+
+		if (!((struct sockaddr_ll *)ifa->ifa_addr)->sll_halen)
+			continue;
+		if (!ifa->ifa_broadaddr)
+			continue;
+
+		device.ifa = ifa;
+
+		if (count++)
+			break;
+	}
+
+	if (count == 1 && device.ifa) {
+		device.ifindex = if_nametoindex(device.ifa->ifa_name);
+		if (!device.ifindex) {
+			perror("arping: if_nametoindex");
+			freeifaddrs(ifa0);
+			return -1;
+		}
+		device.name  = device.ifa->ifa_name;
+		return 0;
+	}
+	return 1;
+#else
+	return -1;
+#endif
+}
+
+#ifdef USE_SYSFS
+static void sysfs_devattr_values_init(struct sysfs_devattr_values *v, int do_free)
+{
+	int i;
+	if (do_free) {
+		free(v->ifname);
+		for (i = 0; i < SYSFS_DEVATTR_NUM; i++) {
+			if (sysfs_devattrs[i].free)
+				free(v->value[i].ptr);
+		}
+	}
+	memset(v, 0, sizeof(*v));
+}
+
+static int sysfs_devattr_ulong(char *ptr, struct sysfs_devattr_values *v, unsigned int idx,
+				     unsigned int base)
+{
+	unsigned long *p;
+	char *ep;
+
+	if (!ptr || !v)
+		return -1;
+
+	p = &v->value[idx].ulong;
+	errno = 0;
+	*p = strtoul(ptr, &ep, base);
+	if ((*ptr && isspace(*ptr & 0xff)) || errno || (*ep != '\0' && *ep != '\n'))
+		goto out;
+
+	return 0;
+out:
+	return -1;
+}
+
+static int sysfs_devattr_ulong_dec(char *ptr, struct sysfs_devattr_values *v, unsigned int idx)
+{
+	int rc = sysfs_devattr_ulong(ptr, v, idx, 10);
+	return rc;
+}
+
+static int sysfs_devattr_ulong_hex(char *ptr, struct sysfs_devattr_values *v, unsigned int idx)
+{
+	int rc = sysfs_devattr_ulong(ptr, v, idx, 16);
+	return rc;
+}
+
+static int sysfs_devattr_macaddr(char *ptr, struct sysfs_devattr_values *v, unsigned int idx)
+{
+	unsigned char *m;
+	int i;
+	unsigned int addrlen;
+
+	if (!ptr || !v)
+		return -1;
+
+	addrlen = v->value[SYSFS_DEVATTR_ADDR_LEN].ulong;
+	m = malloc(addrlen);
+
+	for (i = 0; i < addrlen; i++) {
+		if (i && *(ptr + i * 3 - 1) != ':')
+			goto out;
+		if (sscanf(ptr + i * 3, "%02hhx", &m[i]) != 1)
+			goto out;
+	}
+
+	v->value[idx].ptr = m;
+	return 0;
+out:
+	free(m);
+	return -1;
+}
+#endif
+
+int find_device_by_sysfs(void)
+{
+	int rc = -1;
+#ifdef USE_SYSFS
+	struct sysfs_class *cls_net;
+	struct dlist *dev_list;
+	struct sysfs_class_device *dev;
+	struct sysfs_attribute *dev_attr;
+	struct sysfs_devattr_values sysfs_devattr_values;
+	int count = 0;
+
+	if (!device.sysfs) {
+		device.sysfs = malloc(sizeof(*device.sysfs));
+		sysfs_devattr_values_init(device.sysfs, 0);
+	}
+
+	cls_net = sysfs_open_class("net");
+	if (!cls_net) {
+		perror("sysfs_open_class");
+		return -1;
+	}
+
+	dev_list = sysfs_get_class_devices(cls_net);
+	if (!dev_list) {
+		perror("sysfs_get_class_devices");
+		goto out;
+	}
+
+	sysfs_devattr_values_init(&sysfs_devattr_values, 0);
+
+	dlist_for_each_data(dev_list, dev, struct sysfs_class_device) {
+		int i;
+		int rc = -1;
+
+		if (device.name && strcmp(dev->name, device.name))
+			goto do_next;
+
+		sysfs_devattr_values_init(&sysfs_devattr_values, 1);
+
+		for (i = 0; i < SYSFS_DEVATTR_NUM; i++) {
+
+			dev_attr = sysfs_get_classdev_attr(dev, sysfs_devattrs[i].name);
+			if (!dev_attr) {
+				perror("sysfs_get_classdev_attr");
+				rc = -1;
+				break;
+			}
+			if (sysfs_read_attribute(dev_attr)) {
+				perror("sysfs_read_attribute");
+				rc = -1;
+				break;
+			}
+			rc = sysfs_devattrs[i].handler(dev_attr->value, &sysfs_devattr_values, i);
+
+			if (rc < 0)
+				break;
+		}
+
+		if (rc < 0)
+			goto do_next;
+
+		if (check_ifflags(sysfs_devattr_values.value[SYSFS_DEVATTR_FLAGS].ulong,
+				  device.name != NULL) < 0)
+			goto do_next;
+
+		if (!sysfs_devattr_values.value[SYSFS_DEVATTR_ADDR_LEN].ulong)
+			goto do_next;
+
+		if (device.sysfs->value[SYSFS_DEVATTR_IFINDEX].ulong) {
+			if (device.sysfs->value[SYSFS_DEVATTR_FLAGS].ulong & IFF_RUNNING)
+				goto do_next;
+		}
+
+		sysfs_devattr_values.ifname = strdup(dev->name);
+		if (!sysfs_devattr_values.ifname) {
+			perror("malloc");
+			goto out;
+		}
+
+		sysfs_devattr_values_init(device.sysfs, 1);
+		memcpy(device.sysfs, &sysfs_devattr_values, sizeof(*device.sysfs));
+		sysfs_devattr_values_init(&sysfs_devattr_values, 0);
+
+		if (count++)
+			break;
+
+		continue;
+do_next:
+		sysfs_devattr_values_init(&sysfs_devattr_values, 1);
+	}
+
+	if (count == 1) {
+		device.ifindex = device.sysfs->value[SYSFS_DEVATTR_IFINDEX].ulong;
+		device.name = device.sysfs->ifname;
+	}
+	rc = !device.ifindex;
+out:
+	sysfs_close_class(cls_net);
+#endif
+	return rc;
+}
+
+static int check_device_by_ioctl(int s, struct ifreq *ifr)
+{
+	if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
+		perror("ioctl(SIOCGIFINDEX");
+		return -1;
+	}
+
+	if (check_ifflags(ifr->ifr_flags, device.name != NULL) < 0)
+		return 1;
+
+	if (ioctl(s, SIOCGIFINDEX, ifr) < 0) {
+		perror("ioctl(SIOCGIFINDEX");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int find_device_by_ioctl(void)
+{
+	int s;
+	struct ifreq *ifr0, *ifr, *ifr_end;
+	size_t ifrsize = sizeof(*ifr);
+	struct ifconf ifc;
+	static struct ifreq ifrbuf;
+	int count = 0;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		perror("socket");
+		return -1;
+	}
+
+	memset(&ifrbuf, 0, sizeof(ifrbuf));
+
+	if (device.name) {
+		strncpy(ifrbuf.ifr_name, device.name, sizeof(ifrbuf.ifr_name) - 1);
+		if (check_device_by_ioctl(s, &ifrbuf))
+			goto out;
+		count++;
+	} else {
+		do {
+			int rc;
+			ifr0 = malloc(ifrsize);
+			if (!ifr0) {
+				perror("malloc");
+				goto out;
+			}
+
+			ifc.ifc_buf = (char *)ifr0;
+			ifc.ifc_len = ifrsize;
+
+			rc = ioctl(s, SIOCGIFCONF, &ifc);
+			if (rc < 0) {
+				perror("ioctl(SIOCFIFCONF");
+				goto out;
+			}
+
+			if (ifc.ifc_len + sizeof(*ifr0) + sizeof(struct sockaddr_storage) - sizeof(struct sockaddr) <= ifrsize)
+				break;
+			ifrsize *= 2;
+			free(ifr0);
+			ifr0 = NULL;
+		} while(ifrsize < INT_MAX / 2);
+
+		if (!ifr0) {
+			fprintf(stderr, "arping: too many interfaces!?\n");
+			goto out;
+		}
+
+		ifr_end = (struct ifreq *)(((char *)ifr0) + ifc.ifc_len - sizeof(*ifr0));
+		for (ifr = ifr0; ifr <= ifr_end; ifr++) {
+			if (check_device_by_ioctl(s, &ifrbuf))
+				continue;
+			memcpy(&ifrbuf.ifr_name, ifr->ifr_name, sizeof(ifrbuf.ifr_name));
+			if (count++)
+				break;
+		}
+	}
+
+	close(s);
+
+	if (count == 1) {
+		device.ifindex = ifrbuf.ifr_ifindex;
+		device.name = ifrbuf.ifr_name;
+	}
+	return !device.ifindex;
+out:
+	close(s);
+	return -1;
+}
+
+static int find_device(void)
+{
+	int rc;
+	rc = find_device_by_ifaddrs();
+	if (rc >= 0)
+		goto out;
+	rc = find_device_by_sysfs();
+	if (rc >= 0)
+		goto out;
+	rc = find_device_by_ioctl();
+out:
+	return rc;
+}
+
+/*
+ * set_device_broadcast()
+ *
+ * This fills the device "broadcast address"
+ * based on information found by find_device() funcion.
+ */
+static int set_device_broadcast_ifaddrs_one(struct device *device, unsigned char *ba, size_t balen, int fatal)
+{
+#ifndef WITHOUT_IFADDRS
+	struct ifaddrs *ifa;
+	struct sockaddr_ll *sll;
+
+	if (!device)
+		return -1;
+
+	ifa = device->ifa;
+	if (!ifa)
+		return -1;
+
+	sll = (struct sockaddr_ll *)ifa->ifa_broadaddr;
+
+	if (sll->sll_halen != balen) {
+		if (fatal) {
+			if (!quiet)
+				printf("Address length does not match...\n");
+			exit(2);
+		}
+		return -1;
+	}
+	memcpy(ba, sll->sll_addr, sll->sll_halen);
+	return 0;
+#else
+	return -1;
+#endif
+}
+int set_device_broadcast_sysfs(struct device *device, unsigned char *ba, size_t balen)
+{
+#ifdef USE_SYSFS
+	struct sysfs_devattr_values *v;
+	if (!device)
+		return -1;
+	v = device->sysfs;
+	if (!v)
+		return -1;
+	if (v->value[SYSFS_DEVATTR_ADDR_LEN].ulong != balen)
+		return -1;
+	memcpy(ba, v->value[SYSFS_DEVATTR_BROADCAST].ptr, balen);
+	return 0;
+#else
+	return -1;
+#endif
+}
+
+static int set_device_broadcast_fallback(struct device *device, unsigned char *ba, size_t balen)
+{
+	if (!quiet)
+		fprintf(stderr, "WARNING: using default broadcast address.\n");
+	memset(ba, -1, balen);
+	return 0;
+}
+
+static void set_device_broadcast(struct device *dev, unsigned char *ba, size_t balen)
+{
+	if (!set_device_broadcast_ifaddrs_one(dev, ba, balen, 0))
+		return;
+	if (!set_device_broadcast_sysfs(dev, ba, balen))
+		return;
+	set_device_broadcast_fallback(dev, ba, balen);
+}
+
+int
+main(int argc, char **argv)
+{
+	int socket_errno;
+	int ch;
+
+	limit_capabilities();
+
+#ifdef USE_IDN
+	setlocale(LC_ALL, "");
+#endif
+
+	enable_capability_raw();
+
+	s = socket(PF_PACKET, SOCK_DGRAM, 0);
+	socket_errno = errno;
+
+	disable_capability_raw();
+
+	while ((ch = getopt(argc, argv, "h?bfDUAqc:w:s:I:V")) != EOF) {
+		switch(ch) {
+		case 'b':
+			broadcast_only=1;
+			break;
+		case 'D':
+			dad++;
+			quit_on_reply=1;
+			break;
+		case 'U':
+			unsolicited++;
+			break;
+		case 'A':
+			advert++;
+			unsolicited++;
+			break;
+		case 'q':
+			quiet++;
+			break;
+		case 'c':
+			count = atoi(optarg);
+			break;
+		case 'w':
+			timeout = atoi(optarg);
+			break;
+		case 'I':
+			device.name = optarg;
+			break;
+		case 'f':
+			quit_on_reply=1;
+			break;
+		case 's':
+			source = optarg;
+			break;
+		case 'V':
+			printf("arping utility, iputils-%s\n", SNAPSHOT);
+			exit(0);
+		case 'h':
+		case '?':
+		default:
+			usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 1)
+		usage();
+
+	target = *argv;
+
+	if (device.name && !*device.name)
+		device.name = NULL;
+
+	if (s < 0) {
+		errno = socket_errno;
+		perror("arping: socket");
+		exit(2);
+	}
+
+	if (find_device() < 0)
+		exit(2);
+
+	if (!device.ifindex) {
+		if (device.name) {
+			fprintf(stderr, "arping: Device %s not available.\n", device.name);
+			exit(2);
+		}
+		fprintf(stderr, "arping: device (option -I) is required.\n");
+		usage();
+	}
+
+	if (inet_aton(target, &dst) != 1) {
+		struct hostent *hp;
+		char *idn = target;
+#ifdef USE_IDN
+		int rc;
+
+		rc = idna_to_ascii_lz(target, &idn, 0);
+
+		if (rc != IDNA_SUCCESS) {
+			fprintf(stderr, "arping: IDN encoding failed: %s\n", idna_strerror(rc));
+			exit(2);
+		}
+#endif
+
+		hp = gethostbyname2(idn, AF_INET);
+		if (!hp) {
+			fprintf(stderr, "arping: unknown host %s\n", target);
+			exit(2);
+		}
+
+#ifdef USE_IDN
+		free(idn);
+#endif
+
+		memcpy(&dst, hp->h_addr, 4);
+	}
+
+	if (source && inet_aton(source, &src) != 1) {
+		fprintf(stderr, "arping: invalid source %s\n", source);
+		exit(2);
+	}
+
+	if (!dad && unsolicited && src.s_addr == 0)
+		src = dst;
+
+	if (!dad || src.s_addr) {
+		struct sockaddr_in saddr;
+		int probe_fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+		if (probe_fd < 0) {
+			perror("socket");
+			exit(2);
+		}
+		if (device.name) {
+			enable_capability_raw();
+
+			if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device.name, strlen(device.name)+1) == -1)
+				perror("WARNING: interface is ignored");
+
+			disable_capability_raw();
+		}
+		memset(&saddr, 0, sizeof(saddr));
+		saddr.sin_family = AF_INET;
+		if (src.s_addr) {
+			saddr.sin_addr = src;
+			if (bind(probe_fd, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
+				perror("bind");
+				exit(2);
+			}
+		} else if (!dad) {
+			int on = 1;
+			socklen_t alen = sizeof(saddr);
+
+			saddr.sin_port = htons(1025);
+			saddr.sin_addr = dst;
+
+			if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, (char*)&on, sizeof(on)) == -1)
+				perror("WARNING: setsockopt(SO_DONTROUTE)");
+			if (connect(probe_fd, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
+				perror("connect");
+				exit(2);
+			}
+			if (getsockname(probe_fd, (struct sockaddr*)&saddr, &alen) == -1) {
+				perror("getsockname");
+				exit(2);
+			}
+			src = saddr.sin_addr;
+		}
+		close(probe_fd);
+	};
+
+	((struct sockaddr_ll *)&me)->sll_family = AF_PACKET;
+	((struct sockaddr_ll *)&me)->sll_ifindex = device.ifindex;
+	((struct sockaddr_ll *)&me)->sll_protocol = htons(ETH_P_ARP);
+	if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
+		perror("bind");
+		exit(2);
+	}
+
+	if (1) {
+		socklen_t alen = sizeof(me);
+		if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
+			perror("getsockname");
+			exit(2);
+		}
+	}
+	if (((struct sockaddr_ll *)&me)->sll_halen == 0) {
+		if (!quiet)
+			printf("Interface \"%s\" is not ARPable (no ll address)\n", device.name);
+		exit(dad?0:2);
+	}
+
+	he = me;
+
+	set_device_broadcast(&device, ((struct sockaddr_ll *)&he)->sll_addr,
+			     ((struct sockaddr_ll *)&he)->sll_halen);
+
+	if (!quiet) {
+		printf("ARPING %s ", inet_ntoa(dst));
+		printf("from %s %s\n",  inet_ntoa(src), device.name ? : "");
+	}
+
+	if (!src.s_addr && !dad) {
+		fprintf(stderr, "arping: no source address in not-DAD mode\n");
+		exit(2);
+	}
+
+	drop_capabilities();
+
+	set_signal(SIGINT, finish);
+	set_signal(SIGALRM, catcher);
+
+	catcher();
+
+	while(1) {
+		sigset_t sset, osset;
+		unsigned char packet[4096];
+		struct sockaddr_storage from;
+		socklen_t alen = sizeof(from);
+		int cc;
+
+		if ((cc = recvfrom(s, packet, sizeof(packet), 0,
+				   (struct sockaddr *)&from, &alen)) < 0) {
+			perror("arping: recvfrom");
+			continue;
+		}
+
+		sigemptyset(&sset);
+		sigaddset(&sset, SIGALRM);
+		sigaddset(&sset, SIGINT);
+		sigprocmask(SIG_BLOCK, &sset, &osset);
+		recv_pack(packet, cc, (struct sockaddr_ll *)&from);
+		sigprocmask(SIG_SETMASK, &osset, NULL);
+	}
+}
+
+
diff --git a/iputils/clockdiff.c b/iputils/clockdiff.c
new file mode 100644
index 0000000..7c1ea1b
--- /dev/null
+++ b/iputils/clockdiff.c
@@ -0,0 +1,687 @@
+#include <time.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#define TSPTYPES
+#include <protocols/timed.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <linux/types.h>
+#ifdef CAPABILITIES
+#include <sys/capability.h>
+#endif
+
+void usage(void) __attribute__((noreturn));
+
+#define MAX_HOSTNAMELEN	NI_MAXHOST
+
+/*
+ * Checksum routine for Internet Protocol family headers.
+ *
+ * This routine is very heavily used in the network
+ * code and should be modified for each CPU to be as fast as possible.
+ *
+ * This implementation is TAHOE version.
+ */
+
+#undef	ADDCARRY
+#define ADDCARRY(sum) { \
+	if (sum & 0xffff0000) {	\
+		sum &= 0xffff; \
+		sum++; \
+	} \
+}
+
+int in_cksum(u_short *addr, int len)
+{
+	union word {
+		char	c[2];
+		u_short	s;
+	} u;
+	int sum = 0;
+
+	while (len > 0) {
+		/*
+		 * add by words.
+		 */
+		while ((len -= 2) >= 0) {
+			if ((unsigned long)addr & 0x1) {
+				/* word is not aligned */
+				u.c[0] = *(char *)addr;
+				u.c[1] = *((char *)addr+1);
+				sum += u.s;
+				addr++;
+			} else
+				sum += *addr++;
+			ADDCARRY(sum);
+		}
+		if (len == -1)
+			/*
+			 * Odd number of bytes.
+			 */
+			u.c[0] = *(u_char *)addr;
+	}
+	if (len == -1) {
+		/* The last mbuf has odd # of bytes. Follow the
+		   standard (the odd byte is shifted left by 8 bits) */
+		u.c[1] = 0;
+		sum += u.s;
+		ADDCARRY(sum);
+	}
+	return (~sum & 0xffff);
+}
+
+#define ON		1
+#define OFF		0
+
+#define RANGE		1		/* best expected round-trip time, ms */
+#define MSGS 		50
+#define TRIALS		10
+
+#define GOOD		0
+#define UNREACHABLE	2
+#define NONSTDTIME	3
+#define HOSTDOWN 	0x7fffffff
+
+
+int interactive = 0;
+uint16_t id;
+int sock;
+int sock_raw;
+struct sockaddr_in server;
+int ip_opt_len = 0;
+
+#define BIASP	 	43199999
+#define BIASN		-43200000
+#define MODULO	 	86400000
+#define PROCESSING_TIME	0 	/* ms. to reduce error in measurement */
+
+#define PACKET_IN	1024
+
+int measure_delta;
+int measure_delta1;
+static u_short seqno, seqno0, acked;
+long rtt = 1000;
+long min_rtt;
+long rtt_sigma = 0;
+
+/*
+ * Measures the differences between machines' clocks using
+ * ICMP timestamp messages.
+ */
+int
+measure(struct sockaddr_in * addr)
+{
+	socklen_t length;
+	int msgcount;
+	int cc, count;
+	fd_set ready;
+	long sendtime, recvtime, histime;
+	long min1, min2, diff;
+	long delta1, delta2;
+	struct timeval tv1, tout;
+	u_char packet[PACKET_IN], opacket[64];
+	struct icmphdr *icp = (struct icmphdr *) packet;
+	struct icmphdr *oicp = (struct icmphdr *) opacket;
+	struct iphdr *ip = (struct iphdr *) packet;
+
+	min1 = min2 = 0x7fffffff;
+	min_rtt = 0x7fffffff;
+	measure_delta = HOSTDOWN;
+	measure_delta1 = HOSTDOWN;
+
+/* empties the icmp input queue */
+	FD_ZERO(&ready);
+
+empty:
+	tout.tv_sec = tout.tv_usec = 0;
+	FD_SET(sock_raw, &ready);
+	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
+		length = sizeof(struct sockaddr_in);
+		cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0,
+		    (struct sockaddr *)NULL, &length);
+		if (cc < 0)
+			return -1;
+		goto empty;
+	}
+
+	/*
+	 * To measure the difference, select MSGS messages whose round-trip
+	 * time is smaller than RANGE if ckrange is 1, otherwise simply
+	 * select MSGS messages regardless of round-trip transmission time.
+	 * Choose the smallest transmission time in each of the two directions.
+	 * Use these two latter quantities to compute the delta between
+	 * the two clocks.
+	 */
+
+	length = sizeof(struct sockaddr_in);
+	oicp->type = ICMP_TIMESTAMP;
+	oicp->code = 0;
+	oicp->checksum = 0;
+	oicp->un.echo.id = id;
+	((__u32*)(oicp+1))[0] = 0;
+	((__u32*)(oicp+1))[1] = 0;
+	((__u32*)(oicp+1))[2] = 0;
+	FD_ZERO(&ready);
+	msgcount = 0;
+
+	acked = seqno = seqno0 = 0;
+
+	for (msgcount = 0; msgcount < MSGS; ) {
+
+	/*
+	 * If no answer is received for TRIALS consecutive times,
+	 * the machine is assumed to be down
+	 */
+		if (seqno - acked > TRIALS)
+			return HOSTDOWN;
+
+		oicp->un.echo.sequence = ++seqno;
+		oicp->checksum = 0;
+
+		(void)gettimeofday (&tv1, (struct timezone *)0);
+		*(__u32*)(oicp+1) = htonl((tv1.tv_sec % (24*60*60)) * 1000
+					  + tv1.tv_usec / 1000);
+		oicp->checksum = in_cksum((u_short *)oicp, sizeof(*oicp) + 12);
+
+		count = sendto(sock_raw, (char *)opacket, sizeof(*oicp)+12, 0,
+			       (struct sockaddr *)addr, sizeof(struct sockaddr_in));
+
+		if (count < 0)
+			return UNREACHABLE;
+
+		for (;;) {
+			FD_ZERO(&ready);
+			FD_SET(sock_raw, &ready);
+			{
+			  long tmo = rtt + rtt_sigma;
+			  tout.tv_sec =  tmo/1000;
+			  tout.tv_usec = (tmo - (tmo/1000)*1000)*1000;
+			}
+
+			if ((count = select(FD_SETSIZE, &ready, (fd_set *)0,
+			    (fd_set *)0, &tout)) <= 0)
+				break;
+
+			(void)gettimeofday(&tv1, (struct timezone *)0);
+			cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0,
+			    (struct sockaddr *)NULL, &length);
+
+			if (cc < 0)
+				return(-1);
+
+			icp = (struct icmphdr *)(packet + (ip->ihl << 2));
+			if( icp->type == ICMP_TIMESTAMPREPLY &&
+			    icp->un.echo.id == id && icp->un.echo.sequence >= seqno0 &&
+						  icp->un.echo.sequence <= seqno) {
+			  if (acked < icp->un.echo.sequence)
+			    acked = icp->un.echo.sequence;
+
+			  recvtime = (tv1.tv_sec % (24*60*60)) * 1000 +
+				     tv1.tv_usec / 1000;
+			  sendtime = ntohl(*(__u32*)(icp+1));
+			  diff = recvtime - sendtime;
+		/*
+		 * diff can be less than 0 aroud midnight
+		 */
+			  if (diff < 0)
+			    continue;
+			  rtt = (rtt * 3 + diff)/4;
+			  rtt_sigma = (rtt_sigma *3 + abs(diff-rtt))/4;
+			  msgcount++;
+			  histime = ntohl(((__u32*)(icp+1))[1]);
+		/*
+		 * a hosts using a time format different from
+		 * ms. since midnight UT (as per RFC792) should
+		 * set the high order bit of the 32-bit time
+		 * value it transmits.
+		 */
+			if ((histime & 0x80000000) != 0)
+			  return NONSTDTIME;
+
+			if (interactive) {
+			  printf(".");
+			  fflush(stdout);
+			}
+
+			delta1 = histime - sendtime;
+		/*
+		 * Handles wrap-around to avoid that around
+		 * midnight small time differences appear
+		 * enormous. However, the two machine's clocks
+		 * must be within 12 hours from each other.
+		 */
+			if (delta1 < BIASN)
+				delta1 += MODULO;
+			else if (delta1 > BIASP)
+				delta1 -= MODULO;
+
+			delta2 = recvtime - histime;
+			if (delta2 < BIASN)
+				delta2 += MODULO;
+			else if (delta2 > BIASP)
+				delta2 -= MODULO;
+
+			if (delta1 < min1)
+				min1 = delta1;
+			if (delta2 < min2)
+				min2 = delta2;
+			if (delta1 + delta2 < min_rtt) {
+			  min_rtt  = delta1 + delta2;
+			  measure_delta1 = (delta1 - delta2)/2 + PROCESSING_TIME;
+			}
+			if (diff < RANGE) {
+				min1 = delta1;
+				min2 = delta2;
+				goto good_exit;
+			}
+		      }
+		}
+	}
+
+good_exit:
+	measure_delta = (min1 - min2)/2 + PROCESSING_TIME;
+	return GOOD;
+}
+
+char *myname, *hisname;
+
+int
+measure_opt(struct sockaddr_in * addr)
+{
+	socklen_t length;
+	int msgcount;
+	int cc, count;
+	fd_set ready;
+	long sendtime, recvtime, histime, histime1;
+	long min1, min2, diff;
+	long delta1, delta2;
+	struct timeval tv1, tout;
+	u_char packet[PACKET_IN], opacket[64];
+	struct icmphdr *icp = (struct icmphdr *) packet;
+	struct icmphdr *oicp = (struct icmphdr *) opacket;
+	struct iphdr *ip = (struct iphdr *) packet;
+
+	min1 = min2 = 0x7fffffff;
+	min_rtt = 0x7fffffff;
+	measure_delta = HOSTDOWN;
+	measure_delta1 = HOSTDOWN;
+
+/* empties the icmp input queue */
+	FD_ZERO(&ready);
+empty:
+	tout.tv_sec = tout.tv_usec = 0;
+	FD_SET(sock_raw, &ready);
+	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
+		length = sizeof(struct sockaddr_in);
+		cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0,
+		    (struct sockaddr *)NULL, &length);
+		if (cc < 0)
+			return -1;
+		goto empty;
+	}
+
+	/*
+	 * To measure the difference, select MSGS messages whose round-trip
+	 * time is smaller than RANGE if ckrange is 1, otherwise simply
+	 * select MSGS messages regardless of round-trip transmission time.
+	 * Choose the smallest transmission time in each of the two directions.
+	 * Use these two latter quantities to compute the delta between
+	 * the two clocks.
+	 */
+
+	length = sizeof(struct sockaddr_in);
+	oicp->type = ICMP_ECHO;
+	oicp->code = 0;
+	oicp->checksum = 0;
+	oicp->un.echo.id = id;
+	((__u32*)(oicp+1))[0] = 0;
+	((__u32*)(oicp+1))[1] = 0;
+	((__u32*)(oicp+1))[2] = 0;
+
+	FD_ZERO(&ready);
+	msgcount = 0;
+
+	acked = seqno = seqno0 = 0;
+
+	for (msgcount = 0; msgcount < MSGS; ) {
+
+	/*
+	 * If no answer is received for TRIALS consecutive times,
+	 * the machine is assumed to be down
+	 */
+		if ( seqno - acked > TRIALS) {
+			errno = EHOSTDOWN;
+			return HOSTDOWN;
+		}
+		oicp->un.echo.sequence = ++seqno;
+		oicp->checksum = 0;
+
+		gettimeofday (&tv1, NULL);
+		((__u32*)(oicp+1))[0] = htonl((tv1.tv_sec % (24*60*60)) * 1000
+					      + tv1.tv_usec / 1000);
+		oicp->checksum = in_cksum((u_short *)oicp, sizeof(*oicp)+12);
+
+		count = sendto(sock_raw, (char *)opacket, sizeof(*oicp)+12, 0,
+			       (struct sockaddr *)addr, sizeof(struct sockaddr_in));
+
+		if (count < 0) {
+			errno = EHOSTUNREACH;
+			return UNREACHABLE;
+		}
+
+		for (;;) {
+			FD_ZERO(&ready);
+			FD_SET(sock_raw, &ready);
+			{
+				long tmo = rtt + rtt_sigma;
+				tout.tv_sec =  tmo/1000;
+				tout.tv_usec = (tmo - (tmo/1000)*1000)*1000;
+			}
+
+			if ((count = select(FD_SETSIZE, &ready, (fd_set *)0,
+			    (fd_set *)0, &tout)) <= 0)
+				break;
+
+			(void)gettimeofday(&tv1, (struct timezone *)0);
+			cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0,
+				      (struct sockaddr *)NULL, &length);
+
+			if (cc < 0)
+				return(-1);
+
+			icp = (struct icmphdr *)(packet + (ip->ihl << 2));
+			if (icp->type == ICMP_ECHOREPLY &&
+			    packet[20] == IPOPT_TIMESTAMP &&
+			    icp->un.echo.id == id &&
+			    icp->un.echo.sequence >= seqno0 &&
+			    icp->un.echo.sequence <= seqno) {
+				int i;
+				__u8 *opt = packet+20;
+
+				if (acked < icp->un.echo.sequence)
+					acked = icp->un.echo.sequence;
+				if ((opt[3]&0xF) != IPOPT_TS_PRESPEC) {
+					fprintf(stderr, "Wrong timestamp %d\n", opt[3]&0xF);
+					return NONSTDTIME;
+				}
+				if (opt[3]>>4) {
+					if ((opt[3]>>4) != 1 || ip_opt_len != 4+3*8)
+						fprintf(stderr, "Overflow %d hops\n", opt[3]>>4);
+				}
+				sendtime = recvtime = histime = histime1 = 0;
+				for (i=0; i < (opt[2]-5)/8; i++) {
+					__u32 *timep = (__u32*)(opt+4+i*8+4);
+					__u32 t = ntohl(*timep);
+
+					if (t & 0x80000000)
+						return NONSTDTIME;
+
+					if (i == 0)
+						sendtime = t;
+					if (i == 1)
+						histime = histime1 = t;
+					if (i == 2) {
+						if (ip_opt_len == 4+4*8)
+							histime1 = t;
+						else
+							recvtime = t;
+					}
+					if (i == 3)
+						recvtime = t;
+				}
+
+				if (!(sendtime&histime&histime1&recvtime)) {
+					fprintf(stderr, "wrong timestamps\n");
+					return -1;
+				}
+
+				diff = recvtime - sendtime;
+				/*
+				 * diff can be less than 0 aroud midnight
+				 */
+				if (diff < 0)
+					continue;
+				rtt = (rtt * 3 + diff)/4;
+				rtt_sigma = (rtt_sigma *3 + abs(diff-rtt))/4;
+				msgcount++;
+
+				if (interactive) {
+					printf(".");
+					fflush(stdout);
+				}
+
+				delta1 = histime - sendtime;
+				/*
+				 * Handles wrap-around to avoid that around
+				 * midnight small time differences appear
+				 * enormous. However, the two machine's clocks
+				 * must be within 12 hours from each other.
+				 */
+				if (delta1 < BIASN)
+					delta1 += MODULO;
+				else if (delta1 > BIASP)
+					delta1 -= MODULO;
+
+				delta2 = recvtime - histime1;
+				if (delta2 < BIASN)
+					delta2 += MODULO;
+				else if (delta2 > BIASP)
+					delta2 -= MODULO;
+
+				if (delta1 < min1)
+					min1 = delta1;
+				if (delta2 < min2)
+					min2 = delta2;
+				if (delta1 + delta2 < min_rtt) {
+					min_rtt  = delta1 + delta2;
+					measure_delta1 = (delta1 - delta2)/2 + PROCESSING_TIME;
+				}
+				if (diff < RANGE) {
+					min1 = delta1;
+					min2 = delta2;
+					goto good_exit;
+				}
+			}
+		}
+	}
+
+good_exit:
+	measure_delta = (min1 - min2)/2 + PROCESSING_TIME;
+	return GOOD;
+}
+
+
+/*
+ * Clockdiff computes the difference between the time of the machine on
+ * which it is called and the time of the machines given as argument.
+ * The time differences measured by clockdiff are obtained using a sequence
+ * of ICMP TSTAMP messages which are returned to the sender by the IP module
+ * in the remote machine.
+ * In order to compare clocks of machines in different time zones, the time
+ * is transmitted (as a 32-bit value) in milliseconds since midnight UT.
+ * If a hosts uses a different time format, it should set the high order
+ * bit of the 32-bit quantity it transmits.
+ * However, VMS apparently transmits the time in milliseconds since midnight
+ * local time (rather than GMT) without setting the high order bit.
+ * Furthermore, it does not understand daylight-saving time.  This makes
+ * clockdiff behaving inconsistently with hosts running VMS.
+ *
+ * In order to reduce the sensitivity to the variance of message transmission
+ * time, clockdiff sends a sequence of messages.  Yet, measures between
+ * two `distant' hosts can be affected by a small error. The error can, however,
+ * be reduced by increasing the number of messages sent in each measurement.
+ */
+
+void
+usage() {
+  fprintf(stderr, "Usage: clockdiff [-o] <host>\n");
+  exit(1);
+}
+
+void drop_rights(void) {
+#ifdef CAPABILITIES
+	cap_t caps = cap_init();
+	if (cap_set_proc(caps)) {
+		perror("clockdiff: cap_set_proc");
+		exit(-1);
+	}
+	cap_free(caps);
+#endif
+	if (setuid(getuid())) {
+		perror("clockdiff: setuid");
+		exit(-1);
+	}
+}
+
+int
+main(int argc, char *argv[])
+{
+	int measure_status;
+	struct hostent * hp;
+	char hostname[MAX_HOSTNAMELEN];
+	int s_errno = 0;
+	int n_errno = 0;
+
+	if (argc < 2) {
+		drop_rights();
+		usage();
+	}
+
+	sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+	s_errno = errno;
+
+	errno = 0;
+	if (nice(-16) == -1)
+		n_errno = errno;
+	drop_rights();
+
+	if (argc == 3) {
+		if (strcmp(argv[1], "-o") == 0) {
+			ip_opt_len = 4 + 4*8;
+			argv++;
+		} else if (strcmp(argv[1], "-o1") == 0) {
+			ip_opt_len = 4 + 3*8;
+			argv++;
+		} else
+			usage();
+	} else if (argc != 2)
+		usage();
+
+	if (sock_raw < 0)  {
+		errno = s_errno;
+		perror("clockdiff: socket");
+		exit(1);
+	}
+
+	if (n_errno < 0) {
+		errno = n_errno;
+		perror("clockdiff: nice");
+		exit(1);
+	}
+
+	if (isatty(fileno(stdin)) && isatty(fileno(stdout)))
+		interactive = 1;
+
+	id = getpid();
+
+	(void)gethostname(hostname,sizeof(hostname));
+	hp = gethostbyname(hostname);
+	if (hp == NULL) {
+		fprintf(stderr, "clockdiff: %s: my host not found\n", hostname);
+		exit(1);
+	}
+	myname = strdup(hp->h_name);
+
+	hp = gethostbyname(argv[1]);
+	if (hp == NULL) {
+		fprintf(stderr, "clockdiff: %s: host not found\n", argv[1]);
+		exit(1);
+	}
+	hisname = strdup(hp->h_name);
+
+	memset(&server, 0, sizeof(server));
+	server.sin_family = hp->h_addrtype;
+	memcpy(&(server.sin_addr.s_addr), hp->h_addr, 4);
+
+	if (connect(sock_raw, (struct sockaddr*)&server, sizeof(server)) == -1) {
+		perror("connect");
+		exit(1);
+	}
+	if (ip_opt_len) {
+		struct sockaddr_in myaddr;
+		socklen_t addrlen = sizeof(myaddr);
+		unsigned char rspace[ip_opt_len];
+
+		memset(rspace, 0, sizeof(rspace));
+		rspace[0] = IPOPT_TIMESTAMP;
+		rspace[1] = ip_opt_len;
+		rspace[2] = 5;
+		rspace[3] = IPOPT_TS_PRESPEC;
+		if (getsockname(sock_raw, (struct sockaddr*)&myaddr, &addrlen) == -1) {
+			perror("getsockname");
+			exit(1);
+		}
+		((__u32*)(rspace+4))[0*2] = myaddr.sin_addr.s_addr;
+		((__u32*)(rspace+4))[1*2] = server.sin_addr.s_addr;
+		((__u32*)(rspace+4))[2*2] = myaddr.sin_addr.s_addr;
+		if (ip_opt_len == 4+4*8) {
+			((__u32*)(rspace+4))[2*2] = server.sin_addr.s_addr;
+			((__u32*)(rspace+4))[3*2] = myaddr.sin_addr.s_addr;
+		}
+
+		if (setsockopt(sock_raw, IPPROTO_IP, IP_OPTIONS, rspace, ip_opt_len) < 0) {
+			perror("ping: IP_OPTIONS (fallback to icmp tstamps)");
+			ip_opt_len = 0;
+		}
+	}
+
+	if ((measure_status = (ip_opt_len ? measure_opt : measure)(&server)) < 0) {
+		if (errno)
+			perror("measure");
+		else
+			fprintf(stderr, "measure: unknown failure\n");
+		exit(1);
+	}
+
+	switch (measure_status) {
+	case HOSTDOWN:
+		fprintf(stderr, "%s is down\n", hisname);
+		exit(1);
+	case NONSTDTIME:
+		fprintf(stderr, "%s time transmitted in a non-standard format\n", hisname);
+		exit(1);
+	case UNREACHABLE:
+		fprintf(stderr, "%s is unreachable\n", hisname);
+		exit(1);
+	default:
+		break;
+	}
+
+
+	{
+		time_t now = time(NULL);
+
+		if (interactive)
+			printf("\nhost=%s rtt=%ld(%ld)ms/%ldms delta=%dms/%dms %s", hisname,
+			       rtt, rtt_sigma, min_rtt,
+			       measure_delta, measure_delta1,
+			       ctime(&now));
+		else
+			printf("%ld %d %d\n", now, measure_delta, measure_delta1);
+	}
+	exit(0);
+}
diff --git a/iputils/doc/Makefile b/iputils/doc/Makefile
new file mode 100644
index 0000000..7ec4f1c
--- /dev/null
+++ b/iputils/doc/Makefile
@@ -0,0 +1,47 @@
+SGMLFILES=$(shell echo *.sgml)
+HTMLFILES=$(subst .sgml,.html,$(SGMLFILES)) index.html
+MANFILES=$(subst .sgml,.8,$(SGMLFILES))
+
+all: html
+
+html: $(HTMLFILES) iputils.html
+
+man: $(MANFILES)
+
+# docbook scripts are incredibly dirty in the sense that they leak
+# lots of some strange temporary junk directories and files.
+# So, scope it to a temporary dir and clean all after each run.
+
+$(HTMLFILES): index.db
+	@-rm -rf tmp.db2html
+	@mkdir tmp.db2html
+	@set -e; cd tmp.db2html; docbook2html ../$< ; mv *.html ..
+	@-rm -rf tmp.db2html
+
+iputils.html: iputils.db
+	@-rm -rf tmp.db2html
+	@mkdir tmp.db2html
+	@set -e; cd tmp.db2html; docbook2html -u -o html ../$< ; mv html/$@ ..
+	@-rm -rf tmp.db2html
+
+# docbook2man produces utterly ugly output and I did not find
+# any way to customize this but hacking backend perl script a little.
+# Well, hence...
+
+$(MANFILES): index.db
+	@-mkdir tmp.db2man
+	@set -e; cd tmp.db2man; nsgmls ../$< | sgmlspl ../docbook2man-spec.pl ;	mv $@ ..
+	@-rm -rf tmp.db2man
+
+clean:
+	@rm -rf $(MANFILES) $(HTMLFILES) iputils.html tmp.db2html tmp.db2man
+
+snapshot:
+	@date "+%y%m%d" > snapshot.db
+
+
+$(MANFILES): $(SGMLFILES)
+
+$(HTMLFILES): $(SGMLFILES)
+
+
diff --git a/iputils/doc/arping.sgml b/iputils/doc/arping.sgml
new file mode 100644
index 0000000..0688ecb
--- /dev/null
+++ b/iputils/doc/arping.sgml
@@ -0,0 +1,221 @@
+<refentry id="arping">
+
+<refmeta>
+<refentrytitle>arping</refentrytitle>
+<manvolnum>8</manvolnum>
+<refmiscinfo>iputils-&snapshot;</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+<refname>arping</refname>
+<refpurpose>send ARP REQUEST to a neighbour host</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>arping</command>
+<arg choice="opt"><option>-AbDfhqUV</option></arg>
+<arg choice="opt">-c <replaceable/count/</arg>
+<arg choice="opt">-w <replaceable/deadline/</arg>
+<arg choice="opt">-s <replaceable/source/</arg>
+<arg choice="req">-I <replaceable/interface/</arg>
+<arg choice="req"><replaceable/destination/</arg>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+<para>
+Ping <replaceable/destination/ on device <replaceable/interface/ by ARP packets,
+using source address <replaceable/source/.
+</para>
+</refsect1>
+
+<refsect1><title>OPTIONS</title>
+
+<variablelist>
+
+ <varlistentry>
+  <term><option/-A/</term>
+  <listitem><para>
+The same as <option/-U/, but ARP REPLY packets used instead
+of ARP REQUEST.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>-b</option></term>
+  <listitem><para>
+Send only MAC level broadcasts. Normally <command/arping/ starts
+from sending broadcast, and switch to unicast after reply received.
+  </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+  <term><option><anchor id="arping.count">-c <replaceable/count/</option></term>
+  <listitem><para>
+Stop after sending <replaceable/count/ ARP REQUEST
+packets. With 
+<link linkend="arping.deadline"><replaceable/deadline/</link>
+option, <command/arping/ waits for
+<replaceable/count/ ARP REPLY packets, until the timeout expires.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-D/</term>
+  <listitem><para>
+Duplicate address detection mode (DAD). See 
+<ulink url="http://tools.ietf.org/rfc/rfc2131.txt">RFC2131, 4.4.1</ulink>.
+Returns 0, if DAD succeeded i.e. no replies are received
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>-f</option></term>
+  <listitem><para>
+Finish after the first reply confirming that target is alive.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option><anchor id="opt.interface">-I <replaceable/interface/</option></term>
+  <listitem><para>
+Name of network device where to send ARP REQUEST packets.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>-h</option></term>
+  <listitem><para>
+Print help page and exit.
+  </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+  <term><option/-q/</term>
+  <listitem><para>
+Quiet output. Nothing is displayed.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option><anchor id="opt.source">-s <replaceable/source/</option></term>
+  <listitem><para>
+IP source address to use in ARP packets.
+If this option is absent, source address is:
+   <itemizedlist>
+    <listitem><para>
+In DAD mode (with option <option/-D/) set to 0.0.0.0.
+    </para></listitem>
+    <listitem><para>
+In Unsolicited ARP mode (with options <option/-U/ or <option/-A/)
+set to <replaceable/destination/.
+    </para></listitem>
+    <listitem><para>
+Otherwise, it is calculated from routing tables.
+    </para></listitem>
+   </itemizedlist>
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-U/</term>
+  <listitem><para>
+Unsolicited ARP mode to update neighbours' ARP caches.
+No replies are expected.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>-V</option></term>
+  <listitem><para>
+Print version of the program and exit.
+  </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+  <term><option><anchor id="arping.deadline">-w <replaceable/deadline/</option></term>
+  <listitem><para>
+Specify a timeout, in seconds, before
+<command/arping/
+exits regardless of how many
+packets have been sent or received. In this case
+<command/arping/
+does not stop after
+<link linkend="arping.count"><replaceable/count/</link>
+packet are sent, it waits either for
+<link linkend="arping.deadline"><replaceable/deadline/</link>
+expire or until
+<link linkend="arping.count"><replaceable/count/</link>
+probes are answered.
+  </para></listitem>
+ </varlistentry>
+</variablelist>
+</refsect1>
+
+<refsect1><title>SEE ALSO</title>
+<para>
+<link linkend="ping">
+<citerefentry><refentrytitle/ping/<manvolnum/8/</citerefentry></link>,
+<link linkend="clockdiff">
+<citerefentry><refentrytitle/clockdiff/<manvolnum/8/</citerefentry></link>,
+<link linkend="tracepath">
+<citerefentry><refentrytitle/tracepath/<manvolnum/8/</citerefentry></link>.
+</para>
+</refsect1>
+
+<refsect1><title>AUTHOR</title>
+<para>
+<command/arping/ was written by
+<ulink url="mailto:kuznet@ms2.inr.ac.ru">Alexey Kuznetsov
+&lt;kuznet@ms2.inr.ac.ru&gt;</ulink>.
+It is now maintained by
+<ulink url="mailto:yoshfuji@skbuff.net">YOSHIFUJI Hideaki
+&lt;yoshfuji@skbuff.net&gt;</ulink>.
+</para>
+</refsect1>
+
+<refsect1><title>SECURITY</title>
+<para>
+<command/arping/ requires <constant/CAP_NET_RAW/ capability
+to be executed. It is not recommended to be used as set-uid root,
+because it allows user to modify ARP caches of neighbour hosts.
+</para>
+</refsect1>
+
+<refsect1><title>AVAILABILITY</title>
+<para>
+<command/arping/ is part of <filename/iputils/ package
+and the latest versions are  available in source form at
+<ulink url="http://www.skbuff.net/iputils/iputils-current.tar.bz2">
+http://www.skbuff.net/iputils/iputils-current.tar.bz2</ulink>.
+</para>
+</refsect1>
+
+<![IGNORE[
+<refsect1><title>COPYING</title>
+<para>
+<literallayout>
+This documentation is free software; you can redistribute
+it and/or modify it under the terms of the GNU General Public
+License Version 2.
+
+This program is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied
+warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU General Public License for more details.
+ 
+For more details see the file COPYING in the source
+distribution of Linux kernel of version 2.4.
+</literallayout>
+</para>
+</refsect1>
+]]>
+
+
+
+</refentry>
diff --git a/iputils/doc/clockdiff.sgml b/iputils/doc/clockdiff.sgml
new file mode 100644
index 0000000..e5ab592
--- /dev/null
+++ b/iputils/doc/clockdiff.sgml
@@ -0,0 +1,161 @@
+<refentry id="clockdiff">
+
+<refmeta>
+<refentrytitle>clockdiff</refentrytitle>
+<manvolnum>8</manvolnum>
+<refmiscinfo>iputils-&snapshot;</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>clockdiff</refname>
+<refpurpose>measure clock difference between hosts</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>clockdiff</command>
+<arg choice="opt"><option>-o</option></arg>
+<arg choice="opt"><option>-o1</option></arg>
+<arg choice="req"><replaceable/destination/</arg>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+<para>
+<command/clockdiff/ Measures clock difference between us and
+<replaceable/destination/ with 1 msec resolution using ICMP TIMESTAMP
+<link linkend="clockdiff.icmp-timestamp">[2]</link>
+packets or, optionally, IP TIMESTAMP option
+<link linkend="clockdiff.ip-timestamp">[3]</link>
+option added to ICMP ECHO.
+<link linkend="clockdiff.icmp-echo">[1]</link>
+</para>
+</refsect1>
+
+<refsect1><title>OPTIONS</title>
+
+<variablelist>
+
+ <varlistentry>
+  <term><option/-o/</term>
+  <listitem><para>
+Use IP TIMESTAMP with ICMP ECHO instead of ICMP TIMESTAMP
+messages. It is useful with some destinations, which do not support
+ICMP TIMESTAMP (f.e. Solaris &lt;2.4).
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-o1/</term>
+  <listitem><para>
+Slightly different form of <option/-o/, namely it uses three-term
+IP TIMESTAMP with prespecified hop addresses instead of four term one.
+What flavor works better depends on target host. Particularly,
+<option/-o/ is better for Linux.
+  </para></listitem>
+ </varlistentry>
+
+</variablelist>
+
+</refsect1>
+
+<refsect1><title>WARNINGS</title>
+<itemizedlist>
+ <listitem><para>
+Some nodes (Cisco) use non-standard timestamps, which is allowed
+by RFC, but makes timestamps mostly useless.
+ </para></listitem>
+ <listitem><para>
+Some nodes generate messed timestamps (Solaris&gt;2.4), when
+run <command/xntpd/. Seems, its IP stack uses a corrupted clock source,
+which is synchronized to time-of-day clock periodically and jumps
+randomly making timestamps mostly useless. Good news is that you can
+use NTP in this case, which is even better.
+ </para></listitem>
+ <listitem><para>
+<command/clockdiff/ shows difference in time modulo 24 days.
+ </para></listitem>
+</itemizedlist>
+
+</refsect1>
+
+<refsect1><title>SEE ALSO</title>
+<para>
+<link linkend="ping">
+<citerefentry><refentrytitle/ping/<manvolnum/8/</citerefentry></link>,
+<link linkend="arping">
+<citerefentry><refentrytitle/arping/<manvolnum/8/</citerefentry></link>,
+<link linkend="tracepath">
+<citerefentry><refentrytitle/tracepath/<manvolnum/8/</citerefentry></link>.
+</para>
+</refsect1>
+
+<refsect1><title>REFERENCES</title>
+<para>
+[1] <anchor id="clockdiff.icmp-echo">ICMP ECHO,
+<ulink url="http://tools.ietf.org/rfc/rfc792.txt">
+RFC0792, page 14</ulink>.
+</para>
+<para>
+[2] <anchor id="clockdiff.icmp-timestamp">ICMP TIMESTAMP,
+<ulink url="http://tools.ietf.org/rfc/rfc792.txt">
+RFC0792, page 16</ulink>.
+</para>
+<para>
+[3] <anchor id="clockdiff.ip-timestamp">IP TIMESTAMP option,
+<ulink url="http://tools.ietf.org/rfc/rfc791.txt">
+RFC0791, 3.1, page 16</ulink>.
+</para>
+</refsect1>
+
+<refsect1><title>AUTHOR</title>
+<para>
+<command/clockdiff/ was compiled by
+<ulink url="mailto:kuznet@ms2.inr.ac.ru">Alexey Kuznetsov
+&lt;kuznet@ms2.inr.ac.ru&gt;</ulink>. It was based on code borrowed
+from BSD <command/timed/ daemon.
+It is now maintained by
+<ulink url="mailto:yoshfuji@skbuff.net">YOSHIFUJI Hideaki
+&lt;yoshfuji@skbuff.net&gt;</ulink>.
+</para>
+</refsect1>
+
+<refsect1><title>SECURITY</title>
+<para>
+<command/clockdiff/ requires <constant/CAP_NET_RAW/ capability
+to be executed. It is safe to be used as set-uid root.
+</para>
+</refsect1>
+
+<refsect1><title>AVAILABILITY</title>
+<para>
+<command/clockdiff/ is part of <filename/iputils/ package
+and the latest versions are  available in source form at
+<ulink url="http://www.skbuff.net/iputils/iputils-current.tar.bz2">
+http://www.skbuff.net/iputils/iputils-current.tar.bz2</ulink>.
+</para>
+</refsect1>
+
+<![IGNORE[
+<refsect1><title>COPYING</title>
+<para>
+<literallayout>
+This documentation is free software; you can redistribute
+it and/or modify it under the terms of the GNU General Public
+License Version 2.
+
+This program is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied
+warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU General Public License for more details.
+ 
+For more details see the file COPYING in the source
+distribution of Linux kernel of version 2.4.
+</literallayout>
+</para>
+</refsect1>
+]]>
+
+
+
+</refentry>
diff --git a/iputils/doc/docbook2man-spec.pl b/iputils/doc/docbook2man-spec.pl
new file mode 100644
index 0000000..343d8a0
--- /dev/null
+++ b/iputils/doc/docbook2man-spec.pl
@@ -0,0 +1,1164 @@
+=head1 NAME
+
+docbook2man-spec - convert DocBook RefEntries to Unix manpages
+
+=head1 SYNOPSIS
+
+The SGMLSpm package from CPAN.  This contains the sgmlspl script which
+is used to grok this file.  Use it like this:
+
+nsgmls some-docbook-document.sgml | sgmlspl docbook2man-spec.pl
+
+=head1 DESCRIPTION
+
+This is a sgmlspl spec file that produces Unix-style
+manpages from RefEntry markup.
+
+See the accompanying RefEntry man page for 'plain new' documentation. :)
+
+=head1 LIMITATIONS
+
+Trying docbook2man on non-DocBook or non-conformant SGML results in
+undefined behavior. :-)
+
+This program is a slow, dodgy Perl script.
+
+This program does not come close to supporting all the possible markup
+in DocBook, and will produce wrong output in some cases with supported
+markup.
+
+=head1 TODO
+
+Add new element handling and fix existing handling.  Be robust.
+Produce cleanest, readable man output as possible (unlike some
+other converters).  Follow Linux man(7) convention.
+If this results in added logic in this script,
+that's okay.  The code should still be reasonably organized.
+
+Make it faster.  If Perl sucks port it to another language.
+
+=head1 COPYRIGHT
+
+Copyright (C) 1998-1999 Steve Cheng <steve@ggi-project.org>
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+You should have received a copy of the GNU General Public License along with
+this program; see the file COPYING.  If not, please write to the Free
+Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+=cut
+
+# $Id: docbook2man-spec.pl,v 1.1 2000/07/21 20:22:30 rosalia Exp $
+
+use SGMLS;			# Use the SGMLS package.
+use SGMLS::Output;		# Use stack-based output.
+use SGMLS::Refs;
+
+########################################################################
+# SGMLSPL script produced automatically by the script sgmlspl.pl
+#
+# Document Type: any, but processes only RefEntries
+# Edited by: me :)
+########################################################################
+
+$write_manpages = 0;
+$blank_xrefs = 0;
+
+sgml('start', sub { 
+	push_output('nul');
+	$raw_cdata = 1;			# Makes it a bit faster.
+	
+	# Links file
+	open(LINKSFILE, ">manpage.links");
+
+	$Refs = new SGMLS::Refs("manpage.refs");
+});
+sgml('end', sub {
+	close(LINKSFILE);
+	if($blank_xrefs) {
+		print STDERR "Warning: output contains unresolved XRefs\n";
+	}
+});
+
+
+
+
+########################################################################
+#
+# Output helpers 
+#
+########################################################################
+
+# Our own version of sgml() and output() to allow simple string output
+# to play well with roff's stupid whitespace rules. 
+
+sub man_sgml
+{
+	if(ref($_[1]) eq 'CODE') {
+		return &sgml;
+	}
+	
+	my $s = $_[1];
+
+	$s =~ s/\\/\\\\/g;
+	$s =~ s/'/\\'/g;
+
+	# \n at the beginning means start at beginning of line
+	if($s =~ s/^\n//) {
+		$sub = 'sub { output "\n" unless $newline_last++; ';
+		if($s eq '') { 
+			sgml($_[0], eval('sub { output "\n" unless $newline_last++; }'));
+		} elsif($s =~ /\n$/) {
+			sgml($_[0], eval("sub { output \"\\n\" unless \$newline_last++; output '$s'; }"));
+		} else {
+			sgml($_[0], eval("sub { output \"\\n\" unless \$newline_last; output '$s'; \$newline_last = 0; }"));
+		}
+	} else {
+		if($s =~ /\n$/) {
+			sgml($_[0], eval("sub { output '$s'; \$newline_last = 1; }"));
+		} else {
+			sgml($_[0], eval("sub { output '$s'; \$newline_last = 0; }"));
+		}
+	}
+}
+
+sub man_output
+{
+	$_ = shift;
+	if(s/^\n//) {
+		output "\n" unless $newline_last++;
+	}
+	return if $_ eq '';
+	
+	output $_;
+
+	if(@_) {
+		output @_;
+		$newline_last = (pop(@_) =~ /\n$/);
+	} else {
+		$newline_last = ($_ =~ /\n$/)
+	}
+}
+
+# Fold lines into one, quote some characters
+sub fold_string
+{
+	$_ = shift;
+	
+	s/\\/\\\\/g;
+	s/"/\\\&"/g;
+
+	# Change tabs to spaces
+	tr/\t\n/  /;
+
+	# Trim whitespace from beginning and end.
+	s/^ +//;
+	s/ +$//;
+
+	return $_;
+}
+	
+sub save_cdata()
+{
+	$raw_cdata++;
+	push_output('string');
+}
+
+sub bold_on()
+{
+	# If the last font is also bold, don't change anything.
+	# Basically this is to just get more readable man output.
+	if($fontstack[$#fontstack] ne 'bold') {
+		if(!$raw_cdata) {
+			output '\fB';
+			$newline_last = 0;
+		}
+	}
+	push(@fontstack, 'bold');
+}
+
+sub italic_on()
+{
+	# If the last font is also italic, don't change anything.
+	if($fontstack[$#fontstack] ne 'italic') {
+		if(!$raw_cdata) {
+			output '\fI';
+			$newline_last = 0;
+		}
+	}
+	push(@fontstack, 'italic');
+}
+
+sub font_off()
+{
+	my $thisfont = pop(@fontstack);
+	my $lastfont = $fontstack[$#fontstack];
+	
+	# Only output font change if it is different
+	if($thisfont ne $lastfont) {
+		if($raw_cdata)			{ return; }
+		elsif($lastfont eq 'bold') 	{ output '\fB'; }
+		elsif($lastfont eq 'italic')	{ output '\fI'; }
+		else				{ output '\fR'; }
+	
+		$newline_last = 0;
+	}
+}
+
+
+
+
+
+
+########################################################################
+#
+# Manpage management
+#
+########################################################################
+
+sgml('<REFENTRY>', sub { 
+	# This will be overwritten at end of REFMETA, when we know the name of the page.
+	pop_output();
+	
+	$write_manpages = 1;		# Currently writing manpage.
+	
+	$nocollapse_whitespace = 0;	# Current whitespace collapse counter.
+	$newline_last = 1;		# At beginning of line?
+		# Just a bit of warning, you will see this variable manipulated
+		# manually a lot.  It makes the code harder to follow but it
+		# saves you from having to worry about collapsing at the end of
+		# parse, stopping at verbatims, etc.
+	$raw_cdata = 0;                 # Instructs certain output functions to
+					# leave CDATA alone, so we can assign
+					# it to a string and process it, etc.
+	@fontstack = ();		# Fonts being activated.
+	
+	$manpage_title = '';		# Needed for indexing.
+	$manpage_sect = '';
+	@manpage_names = ();
+	
+	$manpage_misc = '';
+	
+	$list_nestlevel = 0;		# Indent certain nested content.
+});
+sgml('</REFENTRY>', sub {
+	if(!$newline_last) {
+		output "\n";
+	}
+	
+	$write_manpages = 0;
+	$raw_cdata = 1;
+	push_output('nul');
+});
+
+sgml('</REFMETA>', sub {
+	push_output('file', "$manpage_title.$manpage_sect");
+
+	output <<_END_BANNER;
+.\\" This manpage has been automatically generated by docbook2man 
+.\\" from a DocBook document.  This tool can be found at:
+.\\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
+.\\" Please send any bug reports, improvements, comments, patches, 
+.\\" etc. to Steve Cheng <steve\@ggi-project.org>.
+_END_BANNER
+
+	my $manpage_date = `date "+%d %B %Y"`;
+		
+	output '.TH "';
+	
+	# If the title is not mixed-case, convention says to
+	# uppercase the whole title.  (The canonical title is
+	# lowercase.)
+	if($manpage_title =~ /[A-Z]/) {
+		output fold_string($manpage_title);
+	} else {
+		output uc(fold_string($manpage_title));
+	}
+	
+	output  '" "', fold_string($manpage_sect), 
+		'" "', fold_string(`date "+%d %B %Y"`), 
+		'" "', $manpage_misc, 
+		'" "', $manpage_manual, 
+		"\"\n";
+
+	$newline_last = 1;
+
+	# References to this RefEntry.
+	my $id = $_[0]->parent->attribute('ID')->value;
+	if($id ne '') {
+		# The 'package name' part of the section should
+		# not be used when citing it.
+		my ($sectnum) = ($manpage_sect =~ /([0-9]*)/);
+		
+		if($_[0]->parent->attribute('XREFLABEL')->value eq '') {
+			$Refs->put("refentry:$id", "$manpage_title($sectnum)");
+		} else {
+			$Refs->put("refentry:$id",
+				$_[0]->parent->attribute('XREFLABEL')->value . 
+				"($sectnum)");
+		}
+	}
+});
+
+sgml('<REFENTRYTITLE>', sub { 
+	if($_[0]->in('REFMETA')) { 
+		save_cdata();
+	} else { 
+		# Manpage citations are in bold.
+		bold_on();
+	}
+});
+sgml('</REFENTRYTITLE>', sub { 
+	if($_[0]->in('REFMETA')) {
+		$raw_cdata--;
+		$manpage_title = pop_output();
+	}
+	else { font_off(); }
+});
+
+sgml('<MANVOLNUM>', sub { 
+	if($_[0]->in('REFMETA')) { 
+		save_cdata();	
+	} else {
+		# Manpage citations use ().
+		output '(';
+	}
+});
+sgml('</MANVOLNUM>', sub { 
+	if($_[0]->in('REFMETA')) {
+		$raw_cdata--;
+		$manpage_sect = pop_output();
+	}
+	else { output ')' }
+});
+
+sgml('<REFMISCINFO>', \&save_cdata);
+sgml('</REFMISCINFO>', sub { 
+	$raw_cdata--;
+	$manpage_misc = fold_string(pop_output());
+});
+
+
+# NAME section
+man_sgml('<REFNAMEDIV>', "\n.SH NAME\n");
+
+sgml('<REFNAME>', \&save_cdata);
+sgml('</REFNAME>', sub { 
+	$raw_cdata--;
+	push(@manpage_names, pop_output());
+});
+
+sgml('<REFPURPOSE>', \&save_cdata);
+sgml('</REFPURPOSE>', sub { 
+	$raw_cdata--;
+	my $manpage_purpose = fold_string(pop_output());
+	
+	for(my $i = 0; $i < $#manpage_names; $i++) {
+		output fold_string($manpage_names[$i]), ', ';
+	}
+
+	output fold_string($manpage_names[$#manpage_names]);
+	output " \\- $manpage_purpose\n";
+
+	$newline_last = 1;
+
+	foreach(@manpage_names) {
+		# Don't link to itself
+		if($_ ne $manpage_title) {
+			print LINKSFILE "$manpage_title.$manpage_sect	$_.$manpage_sect\n";
+		}
+	}
+});
+	
+man_sgml('<REFCLASS>', "\n.sp\n");
+
+#RefDescriptor
+
+
+
+
+
+########################################################################
+#
+# SYNOPSIS section and synopses
+#
+########################################################################
+
+man_sgml('<REFSYNOPSISDIV>', "\n.SH SYNOPSIS\n");
+man_sgml('</REFSYNOPSISDIV>', "\n");
+
+## FIXME! Must be made into block elements!!
+#sgml('<FUNCSYNOPSIS>', \&bold_on);
+#sgml('</FUNCSYNOPSIS>', \&font_off);
+#sgml('<CMDSYNOPSIS>', \&bold_on);
+#sgml('</CMDSYNOPSIS>', \&font_off);
+
+man_sgml('<FUNCSYNOPSIS>', sub {
+	man_output("\n.sp\n");
+	bold_on();
+});
+man_sgml('</FUNCSYNOPSIS>', sub {
+	font_off();
+	man_output("\n");
+});
+
+man_sgml('<CMDSYNOPSIS>', "\n\n");
+man_sgml('</CMDSYNOPSIS>', "\n\n");
+
+man_sgml('<FUNCPROTOTYPE>', "\n.sp\n");
+
+# Arguments to functions.  This is C convention.
+man_sgml('<PARAMDEF>', '(');
+man_sgml('</PARAMDEF>', ");\n");
+man_sgml('<VOID>', "(void);\n");
+
+
+
+sub arg_start
+{
+	# my $choice = $_[0]->attribute('CHOICE')->value;
+
+	# The content model for CmdSynopsis doesn't include #PCDATA,
+	# so we won't see any of the whitespace in the source file,
+	# so we have to add it after each component.
+	output ' ';
+
+	if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
+		output '[';
+	}
+	bold_on();
+}
+sub arg_end
+{
+	font_off();
+	if($_[0]->attribute('REP')->value =~ /^Repeat/i) {
+		italic_on();
+		output ' ...';
+		font_off();
+	}
+	if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
+		output ']';
+	}
+}
+
+sgml('<ARG>', \&arg_start);
+sgml('</ARG>', \&arg_end);
+sgml('<GROUP>', \&arg_start);
+sgml('</GROUP>', \&arg_end);
+
+sgml('<OPTION>', \&bold_on);
+sgml('</OPTION>', \&font_off);
+
+# FIXME: This is one _blank_ line.
+man_sgml('<SBR>', "\n\n");
+
+
+########################################################################
+#
+# General sections
+#
+########################################################################
+
+# The name of the section is handled by TITLE.  This just sets
+# up the roff markup.
+man_sgml('<REFSECT1>', "\n.SH ");
+man_sgml('<REFSECT2>', "\n.SS ");
+man_sgml('<REFSECT3>', "\n.SS ");
+
+
+########################################################################
+#
+# Titles, metadata.
+#
+########################################################################
+
+sgml('<TITLE>', sub {
+	if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) {
+		$write_manpages = 1;
+	}
+	save_cdata();
+});
+sgml('</TITLE>', sub { 
+	my $title = fold_string(pop_output());
+	$raw_cdata--;
+	
+	if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) {
+		# We use TITLE of enclosing Reference or Book as manual name
+		$manpage_manual = $title;
+		$write_manpages = 0;
+	}
+	elsif(exists $_[0]->parent->ext->{'title'}) {
+		# By far the easiest case.  Just fold the string as
+		# above, and then set the parent element's variable.
+		$_[0]->parent->ext->{'title'} = $title;
+	}
+	else {
+		# If the parent element's handlers are lazy, 
+		# output the folded string for them :)
+		# We assume they want uppercase and a newline.
+		output '"', uc($title), "\"\n";
+		$newline_last = 1;
+	}
+});
+
+sgml('<ATTRIBUTION>', sub { push_output('string') });
+sgml('</ATTRIBUTION>', sub { $_[0]->parent->ext->{'attribution'} = pop_output(); });
+
+
+# IGNORE.
+sgml('<DOCINFO>', sub { push_output('nul'); });
+sgml('</DOCINFO>', sub { pop_output(); });
+sgml('<REFSECT1INFO>', sub { push_output('nul'); });
+sgml('</REFSECT1INFO>', sub { pop_output(); });
+sgml('<REFSECT2INFO>', sub { push_output('nul'); });
+sgml('</REFSECT2INFO>', sub { pop_output(); });
+sgml('<REFSECT3INFO>', sub { push_output('nul'); });
+sgml('</REFSECT3INFO>', sub { pop_output(); });
+
+sgml('<INDEXTERM>', sub { push_output('nul'); });
+sgml('</INDEXTERM>', sub { pop_output(); });
+
+
+########################################################################
+#
+# Set bold on enclosed content 
+#
+########################################################################
+
+sgml('<APPLICATION>', \&bold_on);	sgml('</APPLICATION>', \&font_off);
+
+sgml('<CLASSNAME>', \&bold_on);		sgml('</CLASSNAME>', \&font_off);
+sgml('<STRUCTNANE>', \&bold_on);	sgml('</STRUCTNAME>', \&font_off);
+sgml('<STRUCTFIELD>', \&bold_on);	sgml('</STRUCTFIELD>', \&font_off);
+sgml('<SYMBOL>', \&bold_on);		sgml('</SYMBOL>', \&font_off);
+sgml('<TYPE>', \&bold_on);		sgml('</TYPE>', \&font_off);
+
+sgml('<ENVAR>', \&bold_on);	sgml('</ENVAR>', \&font_off);
+
+sgml('<FUNCTION>', \&bold_on);	sgml('</FUNCTION>', \&font_off);
+
+sgml('<EMPHASIS>', \&bold_on);	sgml('</EMPHASIS>', \&font_off);
+
+sgml('<ERRORNAME>', \&bold_on);	sgml('</ERRORNAME>', \&font_off);
+# ERRORTYPE
+
+sgml('<COMMAND>', \&bold_on);	sgml('</COMMAND>', \&font_off);
+
+sgml('<GUIBUTTON>', \&bold_on);	sgml('</GUIBUTTON>', \&font_off);
+sgml('<GUIICON>', \&bold_on);	sgml('</GUIICON>', \&font_off);
+# GUILABEL
+# GUIMENU
+# GUIMENUITEM
+# GUISUBMENU
+# MENUCHOICE
+# MOUSEBUTTON
+
+sgml('<ACCEL>', \&bold_on);	sgml('</ACCEL>', \&font_off);
+sgml('<KEYCAP>', \&bold_on);	sgml('</KEYCAP>', \&font_off);
+sgml('<KEYSYM>', \&bold_on);	sgml('</KEYSYM>', \&font_off);
+# KEYCODE
+# KEYCOMBO
+# SHORTCUT
+
+sgml('<USERINPUT>', \&bold_on);	sgml('</USERINPUT>', \&font_off);
+
+sgml('<INTERFACEDEFINITION>', \&bold_on);
+sgml('</INTERFACEDEFINITION>', \&font_off);
+
+# May need to look at the CLASS
+sgml('<SYSTEMITEM>', \&bold_on);
+sgml('</SYSTEMITEM>', \&font_off);
+
+
+
+
+
+########################################################################
+#
+# Set italic on enclosed content 
+#
+########################################################################
+
+sgml('<FIRSTTERM>', \&italic_on);	sgml('</FIRSTTERM>', \&font_off);
+
+sgml('<FILENAME>', \&italic_on);	sgml('</FILENAME>', \&font_off);
+sgml('<PARAMETER>', \&italic_on);	sgml('</PARAMETER>', \&font_off);
+sgml('<PROPERTY>', \&italic_on);	sgml('</PROPERTY>', \&font_off);
+
+sgml('<REPLACEABLE>', sub {
+	italic_on();
+	if($_[0]->in('TOKEN')) {
+		# When tokenizing, follow more 'intuitive' convention
+		output "<";
+	}
+});
+sgml('</REPLACEABLE>', sub {
+	if($_[0]->in('TOKEN')) {
+		output ">";
+	}
+	font_off();
+});
+
+sgml('<CITETITLE>', \&italic_on);	sgml('</CITETITLE>', \&font_off);
+sgml('<FOREIGNPHRASE>', \&italic_on);	sgml('</FOREIGNPHRASE>', \&font_off);
+
+sgml('<LINEANNOTATION>', \&italic_on);	sgml('</LINEANNOTATION>', \&font_off);
+
+
+
+
+
+
+########################################################################
+#
+# Other 'inline' elements 
+#
+########################################################################
+
+man_sgml('<EMAIL>', '<');
+man_sgml('</EMAIL>', '>');
+man_sgml('<OPTIONAL>', '[');
+man_sgml('</OPTIONAL>', ']');
+
+man_sgml('</TRADEMARK>', "\\u\\s-2TM\\s+2\\d");
+
+man_sgml('<COMMENT>', "[Comment: ");
+man_sgml('</COMMENT>', "]");
+
+man_sgml('<QUOTE>', "``");
+man_sgml('</QUOTE>', "''");
+
+#man_sgml('<LITERAL>', '"');
+#man_sgml('</LITERAL>', '"');
+
+# No special presentation:
+
+# AUTHOR
+# AUTHORINITIALS
+
+# ABBREV
+# ACTION
+# ACRONYM
+# ALT
+# CITATION
+# PHRASE
+# QUOTE
+# WORDASWORD
+
+# COMPUTEROUTPUT
+# MARKUP
+# PROMPT
+# RETURNVALUE
+# SGMLTAG
+# TOKEN
+
+# DATABASE
+# HARDWARE
+# INTERFACE
+# MEDIALABEL
+
+# There doesn't seem to be a good way to represent LITERAL in -man
+
+
+
+########################################################################
+#
+# Paragraph and paragraph-like elements 
+#
+########################################################################
+
+sub para_start {
+	output "\n" unless $newline_last++;
+
+	# In lists, etc., don't start paragraph with .PP since
+	# the indentation will be gone.
+
+	if($_[0]->parent->ext->{'nobreak'}==1) {
+		# Usually this is the FIRST element of
+		# a hanging tag, so we MUST not do a full
+		# paragraph break.
+		$_[0]->parent->ext->{'nobreak'} = 2;
+	} elsif($_[0]->parent->ext->{'nobreak'}==2) {
+		# Usually these are the NEXT elements of
+		# a hanging tag.  If we break using a blank
+		# line, we're okay.
+		output "\n";
+	} else {
+		# Normal case. (For indented blocks too, at least
+		# -man isn't so braindead in this area.)
+		output ".PP\n";
+	}
+}
+# Actually applies to a few other block elements as well
+sub para_end {
+	output "\n" unless $newline_last++; 
+}
+
+sgml('<PARA>', \&para_start);
+sgml('</PARA>', \&para_end);
+sgml('<SIMPARA>', \&para_start);
+sgml('</SIMPARA>', \&para_end);
+
+# Nothing special, except maybe FIXME set nobreak.
+sgml('<INFORMALEXAMPLE>', \&para_start);
+sgml('</INFORMALEXAMPLE>', \&para_end);
+
+
+
+
+
+########################################################################
+#
+# Blocks using SS sections
+#
+########################################################################
+
+# FIXME: We need to consider the effects of SS
+# in a hanging tag :(
+
+# Complete with the optional-title dilemma (again).
+sgml('<ABSTRACT>', sub {
+	$_[0]->ext->{'title'} = 'ABSTRACT';
+	output "\n" unless $newline_last++;
+	push_output('string');
+});
+sgml('</ABSTRACT>', sub {
+	my $content = pop_output();
+	
+	# As ABSTRACT is never on the same level as RefSect1,
+	# this leaves us with only .SS in terms of -man macros.
+	output ".SS \"", uc($_[0]->ext->{'title'}), "\"\n";
+
+	output $content;
+	output "\n" unless $newline_last++;
+});
+
+# Ah, I needed a break.  Example always has a title.
+man_sgml('<EXAMPLE>', "\n.SS ");
+sgml('</EXAMPLE>', \&para_end);
+
+# Same with sidebar.
+man_sgml('<SIDEBAR>', "\n.SS ");
+sgml('</SIDEBAR>', \&para_end);
+
+# NO title.
+man_sgml('<HIGHLIGHTS>', "\n.SS HIGHLIGHTS\n");
+sgml('</HIGHLIGHTS>', \&para_end);
+
+
+
+
+########################################################################
+#
+# Indented 'Block' elements 
+#
+########################################################################
+
+sub indent_block_start
+{
+	output "\n" unless $newline_last++;
+	output ".sp\n.RS\n";
+}
+sub indent_block_end
+{
+	output "\n" unless $newline_last++;
+	output ".RE\n";
+}
+
+# This element is almost like an admonition (below),
+# only the default title is blank :)
+
+sgml('<BLOCKQUOTE>', sub { 
+	$_[0]->ext->{'title'} = ''; 
+	output "\n" unless $newline_last++;
+	push_output('string');
+});
+sgml('</BLOCKQUOTE>', sub {
+	my $content = pop_output();
+
+	indent_block_start();
+	
+	if($_[0]->ext->{'title'}) {
+		output ".B \"", $_[0]->ext->{'title'}, ":\"\n";
+	}
+	
+	output $content;
+
+	if($_[0]->ext->{'attribution'}) {
+		output "\n" unless $newline_last++;
+		# One place where roff's space-sensitivity makes sense :)
+		output "\n                -- ";
+		output $_[0]->ext->{'attribution'} . "\n";
+	}
+	
+	indent_block_end();
+});
+
+# Set off admonitions from the rest of the text by indenting.
+# FIXME: Need to check if this works inside paragraphs, not enclosing them.
+sub admonition_end {
+	my $content = pop_output();
+
+	indent_block_start();
+	
+	# When the admonition is only one paragraph,
+	# it looks nicer if the title was inline.
+	my $num_para;
+	while ($content =~ /^\.PP/gm) { $num_para++ }
+	if($num_para==1) {
+		$content =~ s/^\.PP\n//;
+	}
+	
+	output ".B \"" . $_[0]->ext->{'title'} . ":\"\n";
+	output $content;
+	
+	indent_block_end();
+}
+
+sgml('<NOTE>', sub {
+	# We can't see right now whether or not there is a TITLE
+	# element, so we have to save the output now and add it back
+	# at the end of this admonition.
+	$_[0]->ext->{'title'} = 'Note';
+
+	# Although admonition_end's indent_block_start will do this,
+	# we need to synchronize the output _now_
+	output "\n" unless $newline_last++;
+
+	push_output('string');
+});
+sgml('</NOTE>', \&admonition_end);
+
+# Same as above.
+sgml('<WARNING>', sub { 
+	$_[0]->ext->{'title'} = 'Warning'; 
+	output "\n" unless $newline_last++;
+	push_output('string');
+});
+sgml('</WARNING>', \&admonition_end);
+
+sgml('<TIP>', sub {
+	$_[0]->ext->{'title'} = 'Tip';
+	output "\n" unless $newline_last++;
+	push_output('string');
+});
+sgml('</TIP>', \&admonition_end);
+sgml('<CAUTION>', sub {
+	$_[0]->ext->{'title'} = 'Caution';
+	output "\n" unless $newline_last++;
+	push_output('string');
+});
+sgml('</CAUTION>', \&admonition_end);
+
+sgml('<IMPORTANT>', sub {
+	$_[0]->ext->{'title'} = 'Important';
+	output "\n" unless $newline_last++;
+	push_output('string');
+});
+sgml('</IMPORTANT>', \&admonition_end);
+
+
+
+
+
+
+
+
+
+
+
+
+########################################################################
+#
+# Verbatim displays. 
+#
+########################################################################
+
+sub verbatim_start {
+	output "\n" unless $newline_last++;
+	
+	if($_[0]->parent->ext->{'nobreak'}==1) {
+		# Usually this is the FIRST element of
+		# a hanging tag, so we MUST not do a full
+		# paragraph break.
+		$_[0]->parent->ext->{'nobreak'} = 2;
+	} else {
+		output "\n";
+	}
+	
+	output(".nf\n") unless $nocollapse_whitespace++;
+}
+
+sub verbatim_end {
+	output "\n" unless $newline_last++;
+	output(".fi\n") unless --$nocollapse_whitespace;
+}
+
+sgml('<PROGRAMLISTING>', \&verbatim_start); 
+sgml('</PROGRAMLISTING>', \&verbatim_end);
+
+sgml('<SCREEN>', \&verbatim_start); 
+sgml('</SCREEN>', \&verbatim_end);
+
+sgml('<LITERALLAYOUT>', \&verbatim_start); 
+sgml('</LITERALLAYOUT>', \&verbatim_end);
+
+#sgml('<SYNOPSIS>', sub {
+#	if($_[0]->attribute('FORMAT')->value =~ /linespecific/i) {
+#		&verbatim_start;
+#	} else {
+#		roffcmd("");
+#	}
+#});
+#
+#sgml('</SYNOPSIS>', sub {
+#	if($_[0]->attribute('FORMAT')->value =~ /linespecific/i) {
+#		&verbatim_end;
+#	}
+#	else {
+#		roffcmd("");# not sure about this.
+#	}
+#});
+sgml('<SYNOPSIS>', \&verbatim_start);
+sgml('</SYNOPSIS>', \&verbatim_end);
+
+
+
+
+
+
+
+
+
+########################################################################
+#
+# Lists
+#
+########################################################################
+
+# Indent nested lists.
+sub indent_list_start {
+	if($list_nestlevel++) {
+		output "\n" unless $newline_last++;
+		output ".RS\n";
+	}
+}
+sub indent_list_end {
+	if(--$list_nestlevel) {
+		output "\n" unless $newline_last++;
+		output ".RE\n";
+	}
+}
+
+sgml('<VARIABLELIST>', \&indent_list_start);
+sgml('</VARIABLELIST>', \&indent_list_end);
+sgml('<ITEMIZEDLIST>', \&indent_list_start);
+sgml('</ITEMIZEDLIST>', \&indent_list_end);
+sgml('<ORDEREDLIST>', sub { 
+	indent_list_start();
+	$_[0]->ext->{'count'} = 1;
+});
+sgml('</ORDEREDLIST>', \&indent_list_end);
+		
+# Output content on one line, bolded.
+sgml('<TERM>', sub { 
+	output "\n" unless $newline_last++;
+	output ".TP\n";
+	bold_on();
+	push_output('string');
+});
+sgml('</TERM>', sub { 
+	my $term = pop_output();
+	$term =~ tr/\n/ /;
+	output $term;
+	font_off();
+	output "\n";
+	$newline_last = 1;
+});
+	
+sgml('<LISTITEM>', sub {
+	# A bulleted list.
+	if($_[0]->in('ITEMIZEDLIST')) {
+		output "\n" unless $newline_last++;
+		output ".TP 0.2i\n\\(bu\n";
+	}
+
+	# Need numbers.
+	# Assume Arabic numeration for now.
+	elsif($_[0]->in('ORDEREDLIST')) {
+		output "\n" unless $newline_last++;
+		output ".TP ", $_[0]->parent->ext->{'count'}++, ". \n";
+	}
+	
+	$_[0]->ext->{'nobreak'} = 1;
+});
+
+sgml('<SIMPLELIST>', sub {
+	$_[0]->ext->{'first_member'} = 1;
+});
+
+sgml('<MEMBER>', sub {
+	my $parent = $_[0]->parent;
+	
+	if($parent->attribute('TYPE')->value =~ /Inline/i) {
+		if($parent->ext->{'first_member'}) { 
+			# If this is the first member don't put any commas
+			$parent->ext->{'first_member'} = 0;
+		} else {
+			output ", ";
+		}
+	} elsif($parent->attribute('TYPE')->value =~ /Vert/i) {
+		output "\n" unless $newline_last++;
+		output "\n";
+	}
+});
+
+
+
+
+
+########################################################################
+#
+# Stuff we don't know how to handle (yet) 
+#
+########################################################################
+
+# Address blocks:
+
+# Credit stuff:
+# ACKNO
+# ADDRESS
+# AFFILIATION
+# ARTPAGENUMS
+# ATTRIBUTION
+# AUTHORBLURB
+# AUTHORGROUP
+# OTHERCREDIT
+# HONORIFIC
+
+# Areas:
+# AREA
+# AREASET
+# AREASPEC
+
+
+
+
+
+########################################################################
+#
+# Linkage, cross references
+#
+########################################################################
+
+# Print the URL
+sgml('</ULINK>', sub {
+#	output ' <URL:', $_[0]->attribute('URL')->value, '>';
+	$newline_last = 0;
+});
+
+# If cross reference target is a RefEntry, 
+# output CiteRefEntry-style references.
+sgml('<XREF>', sub {
+	my $id = $_[0]->attribute('LINKEND')->value;
+	my $manref = $Refs->get("refentry:$id");
+
+	if($manref) {
+		my ($title, $sect) = ($manref =~ /(.*)(\(.*\))/);
+		bold_on();
+		output $title;
+		font_off();
+		output $sect;
+	} else {
+		$blank_xrefs++ if $write_manpages;
+		output "[XRef to $id]";
+	}
+
+	$newline_last = 0;
+});
+
+# Anchor
+
+
+
+
+########################################################################
+#
+# Other handlers 
+#
+########################################################################
+
+man_sgml('|[lt    ]|', '<');
+man_sgml('|[gt    ]|', '>');
+man_sgml('|[amp   ]|', '&');
+
+#
+# Default handlers (uncomment these if needed).  Right now, these are set
+# up to gag on any unrecognised elements, sdata, processing-instructions,
+# or entities.
+#
+# sgml('start_element',sub { die "Unknown element: " . $_[0]->name; });
+# sgml('end_element','');
+
+# This is for weeding out and escaping certain characters.
+# This looks like it's inefficient since it's done on every line, but
+# in reality, SGMLSpm and sgmlspl parsing ESIS takes _much_ longer.
+
+sgml('cdata', sub
+{ 
+	if(!$write_manpages) { return; }
+	elsif($raw_cdata) { output $_[0]; return; }
+	
+	# Escape backslashes
+	$_[0] =~ s/\\/\\\\/g;
+
+	# In non-'pre'-type elements:
+	if(!$nocollapse_whitespace) {
+		# Change tabs to spaces
+		$_[0] =~ tr/\t/ /;
+
+		# Do not allow indents at beginning of line
+		# groff chokes on that.
+		if($newline_last) { 
+			$_[0] =~ s/^ +//;
+
+			# If the line is all blank, don't do anything.
+			if($_[0] eq '') { return; }
+			
+			$_[0] =~ s/^\./\\\&\./;
+
+			# Argh... roff doesn't like ' either...
+			$_[0] =~ s/^\'/\\\&\'/;
+		}
+	}
+
+	$newline_last = 0;
+
+	output $_[0];
+});
+
+
+# When in whitespace-collapsing mode, we disallow consecutive newlines.
+
+sgml('re', sub
+{
+	if($nocollapse_whitespace || !$newline_last) {
+		output "\n";
+	}
+
+	$newline_last = 1;
+});
+
+sgml('sdata',sub { die "Unknown SDATA: " . $_[0]; });
+sgml('pi',sub { die "Unknown processing instruction: " . $_[0]; });
+sgml('entity',sub { die "Unknown external entity: " . $_[0]->name; });
+sgml('start_subdoc',sub { die "Unknown subdoc entity: " . $_[0]->name; });
+sgml('end_subdoc','');
+sgml('conforming','');
+
+1;
+
diff --git a/iputils/doc/index.db b/iputils/doc/index.db
new file mode 100644
index 0000000..427c2e9
--- /dev/null
+++ b/iputils/doc/index.db
@@ -0,0 +1,28 @@
+<!DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[
+<!ENTITY snapshot SYSTEM "snapshot.db">
+<!ENTITY ping SYSTEM "ping.sgml">
+<!ENTITY rdisc SYSTEM "rdisc.sgml">
+<!ENTITY arping SYSTEM "arping.sgml">
+<!ENTITY clockdiff SYSTEM "clockdiff.sgml">
+<!ENTITY tracepath SYSTEM "tracepath.sgml">
+<!ENTITY traceroute6 SYSTEM "traceroute6.sgml">
+<!ENTITY rarpd SYSTEM "rarpd.sgml">
+<!ENTITY ninfod SYSTEM "ninfod.sgml">
+<!ENTITY tftpd SYSTEM "tftpd.sgml">
+<!ENTITY pg3 SYSTEM "pg3.sgml">
+]>
+<reference id="index">
+<title>System Manager's Manual: iputils</title>
+
+&ping;
+&arping;
+&clockdiff;
+&rarpd;
+&tracepath;
+&traceroute6;
+&tftpd;
+&ninfod;
+&rdisc;
+&pg3;
+
+</reference>
diff --git a/iputils/doc/index.out b/iputils/doc/index.out
new file mode 100644
index 0000000..fe8ef2e
--- /dev/null
+++ b/iputils/doc/index.out
@@ -0,0 +1,87 @@
+\BOOKMARK [1]{0.1.1}{ping}{}
+\BOOKMARK [2]{0.1.1.2}{Name}{0.1.1}
+\BOOKMARK [2]{0.1.2.2}{Synopsis}{0.1.1}
+\BOOKMARK [2]{0.1.3.2}{DESCRIPTION}{0.1.1}
+\BOOKMARK [2]{0.1.4.2}{OPTIONS}{0.1.1}
+\BOOKMARK [2]{0.1.5.2}{ICMP PACKET DETAILS}{0.1.1}
+\BOOKMARK [2]{0.1.6.2}{DUPLICATE AND DAMAGED PACKETS}{0.1.1}
+\BOOKMARK [2]{0.1.7.2}{TRYING DIFFERENT DATA PATTERNS}{0.1.1}
+\BOOKMARK [2]{0.1.8.2}{TTL DETAILS}{0.1.1}
+\BOOKMARK [2]{0.1.9.2}{BUGS}{0.1.1}
+\BOOKMARK [2]{0.1.10.2}{SEE ALSO}{0.1.1}
+\BOOKMARK [2]{0.1.11.2}{HISTORY}{0.1.1}
+\BOOKMARK [2]{0.1.12.2}{SECURITY}{0.1.1}
+\BOOKMARK [2]{0.1.13.2}{AVAILABILITY}{0.1.1}
+\BOOKMARK [1]{0.2.1}{arping}{}
+\BOOKMARK [2]{0.2.14.2}{Name}{0.2.1}
+\BOOKMARK [2]{0.2.15.2}{Synopsis}{0.2.1}
+\BOOKMARK [2]{0.2.16.2}{DESCRIPTION}{0.2.1}
+\BOOKMARK [2]{0.2.17.2}{OPTIONS}{0.2.1}
+\BOOKMARK [2]{0.2.18.2}{SEE ALSO}{0.2.1}
+\BOOKMARK [2]{0.2.19.2}{AUTHOR}{0.2.1}
+\BOOKMARK [2]{0.2.20.2}{SECURITY}{0.2.1}
+\BOOKMARK [2]{0.2.21.2}{AVAILABILITY}{0.2.1}
+\BOOKMARK [1]{0.3.1}{clockdiff}{}
+\BOOKMARK [2]{0.3.22.2}{Name}{0.3.1}
+\BOOKMARK [2]{0.3.23.2}{Synopsis}{0.3.1}
+\BOOKMARK [2]{0.3.24.2}{DESCRIPTION}{0.3.1}
+\BOOKMARK [2]{0.3.25.2}{OPTIONS}{0.3.1}
+\BOOKMARK [2]{0.3.26.2}{WARNINGS}{0.3.1}
+\BOOKMARK [2]{0.3.27.2}{SEE ALSO}{0.3.1}
+\BOOKMARK [2]{0.3.28.2}{REFERENCES}{0.3.1}
+\BOOKMARK [2]{0.3.29.2}{AUTHOR}{0.3.1}
+\BOOKMARK [2]{0.3.30.2}{SECURITY}{0.3.1}
+\BOOKMARK [2]{0.3.31.2}{AVAILABILITY}{0.3.1}
+\BOOKMARK [1]{0.4.1}{rarpd}{}
+\BOOKMARK [2]{0.4.32.2}{Name}{0.4.1}
+\BOOKMARK [2]{0.4.33.2}{Synopsis}{0.4.1}
+\BOOKMARK [2]{0.4.34.2}{DESCRIPTION}{0.4.1}
+\BOOKMARK [2]{0.4.35.2}{WARNING}{0.4.1}
+\BOOKMARK [2]{0.4.36.2}{OPTIONS}{0.4.1}
+\BOOKMARK [2]{0.4.37.2}{SEE ALSO}{0.4.1}
+\BOOKMARK [2]{0.4.38.2}{AUTHOR}{0.4.1}
+\BOOKMARK [2]{0.4.39.2}{SECURITY}{0.4.1}
+\BOOKMARK [2]{0.4.40.2}{AVAILABILITY}{0.4.1}
+\BOOKMARK [1]{0.5.1}{tracepath}{}
+\BOOKMARK [2]{0.5.41.2}{Name}{0.5.1}
+\BOOKMARK [2]{0.5.42.2}{Synopsis}{0.5.1}
+\BOOKMARK [2]{0.5.43.2}{DESCRIPTION}{0.5.1}
+\BOOKMARK [2]{0.5.44.2}{SEE ALSO}{0.5.1}
+\BOOKMARK [2]{0.5.45.2}{AUTHOR}{0.5.1}
+\BOOKMARK [2]{0.5.46.2}{SECURITY}{0.5.1}
+\BOOKMARK [2]{0.5.47.2}{AVAILABILITY}{0.5.1}
+\BOOKMARK [1]{0.6.1}{traceroute6}{}
+\BOOKMARK [2]{0.6.48.2}{Name}{0.6.1}
+\BOOKMARK [2]{0.6.49.2}{Synopsis}{0.6.1}
+\BOOKMARK [2]{0.6.50.2}{DESCRIPTION}{0.6.1}
+\BOOKMARK [2]{0.6.51.2}{SEE ALSO}{0.6.1}
+\BOOKMARK [2]{0.6.52.2}{HISTORY}{0.6.1}
+\BOOKMARK [2]{0.6.53.2}{SECURITY}{0.6.1}
+\BOOKMARK [2]{0.6.54.2}{AVAILABILITY}{0.6.1}
+\BOOKMARK [1]{0.7.1}{tftpd}{}
+\BOOKMARK [2]{0.7.55.2}{Name}{0.7.1}
+\BOOKMARK [2]{0.7.56.2}{Synopsis}{0.7.1}
+\BOOKMARK [2]{0.7.57.2}{DESCRIPTION}{0.7.1}
+\BOOKMARK [2]{0.7.58.2}{SECURITY}{0.7.1}
+\BOOKMARK [2]{0.7.59.2}{SEE ALSO}{0.7.1}
+\BOOKMARK [2]{0.7.60.2}{HISTORY}{0.7.1}
+\BOOKMARK [2]{0.7.61.2}{AVAILABILITY}{0.7.1}
+\BOOKMARK [1]{0.8.1}{rdisc}{}
+\BOOKMARK [2]{0.8.62.2}{Name}{0.8.1}
+\BOOKMARK [2]{0.8.63.2}{Synopsis}{0.8.1}
+\BOOKMARK [2]{0.8.64.2}{DESCRIPTION}{0.8.1}
+\BOOKMARK [2]{0.8.65.2}{OPTIONS}{0.8.1}
+\BOOKMARK [2]{0.8.66.2}{HISTORY}{0.8.1}
+\BOOKMARK [2]{0.8.67.2}{SEE ALSO}{0.8.1}
+\BOOKMARK [2]{0.8.68.2}{REFERENCES}{0.8.1}
+\BOOKMARK [2]{0.8.69.2}{SECURITY}{0.8.1}
+\BOOKMARK [2]{0.8.70.2}{AVAILABILITY}{0.8.1}
+\BOOKMARK [1]{0.9.1}{pg3}{}
+\BOOKMARK [2]{0.9.71.2}{Name}{0.9.1}
+\BOOKMARK [2]{0.9.72.2}{Synopsis}{0.9.1}
+\BOOKMARK [2]{0.9.73.2}{DESCRIPTION}{0.9.1}
+\BOOKMARK [2]{0.9.74.2}{COMMAND}{0.9.1}
+\BOOKMARK [2]{0.9.75.2}{WARNING}{0.9.1}
+\BOOKMARK [2]{0.9.76.2}{AUTHOR}{0.9.1}
+\BOOKMARK [2]{0.9.77.2}{SECURITY}{0.9.1}
+\BOOKMARK [2]{0.9.78.2}{AVAILABILITY}{0.9.1}
diff --git a/iputils/doc/iputils.db b/iputils/doc/iputils.db
new file mode 100644
index 0000000..f29dfad
--- /dev/null
+++ b/iputils/doc/iputils.db
@@ -0,0 +1,209 @@
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<article id="iputils">
+ <artheader>
+  <title>iputils: documentation directory</title>
+ </artheader>
+
+<sect1>
+<title>Index</title>
+
+<itemizedlist>
+ <listitem><para>
+  <ulink url="ping.html">ping, ping6</ulink>.
+ </para></listitem>
+ <listitem><para>
+  <ulink url="arping.html">arping</ulink>.
+ </para></listitem>
+ <listitem><para>
+  <ulink url="clockdiff.html">clockdiff</ulink>.
+ </para></listitem>
+ <listitem><para>
+  <ulink url="rarpd.html">rarpd</ulink>.
+ </para></listitem>
+ <listitem><para>
+  <ulink url="tracepath.html">tracepath, tracepath6</ulink>.
+ </para></listitem>
+ <listitem><para>
+  <ulink url="traceroute6.html">traceroute6</ulink>.
+ </para></listitem>
+ <listitem><para>
+  <ulink url="rdisc.html">rdisc</ulink>.
+ </para></listitem>
+ <listitem><para>
+  <ulink url="tftpd.html">tftpd</ulink>.
+ </para></listitem>
+ <listitem><para>
+  <ulink url="pg3.html">pg3, ipg, pgset</ulink>.
+ </para></listitem>
+</itemizedlist>
+</sect1>
+
+<sect1>
+<title>Historical notes</title>
+
+<para>
+This package appeared as a desperate attempt to bring some life
+to state of basic networking applets: <command/ping/, <command/traceroute/
+etc. Though it was known that port of BSD <command/ping/ to Linux
+was basically broken, neither maintainers of well known (and superb)
+Linux net-tools package nor maintainers of Linux distributions
+worried about fixing well known bugs, which were reported in linux-kernel
+and linux-net mail lists for ages, were identified and nevertheless
+not repaired. So, one day 1001th resuming of the subject happened
+to be the last straw to break camel's back, I just parsed my hard disks
+and collected a set of utilities, which shared the following properties:
+</para>
+
+<itemizedlist>
+ <listitem><para>
+Small
+ </para></listitem>
+ <listitem><para>
+Useful despite of this
+ </para></listitem>
+ <listitem><para>
+I never seen it was made right
+ </para></listitem>
+ <listitem><para>
+Not quite trivial
+ </para></listitem>
+ <listitem><para>
+Demonstrating some important feature of Linux 
+ </para></listitem>
+ <listitem><para>
+The last but not the least, I use it more or less regularly
+ </para></listitem>
+</itemizedlist>
+
+<para>
+This utility set was not supposed to be a reference set or something like
+that. Most of them were cloned from some originals:
+<informaltable>
+ <tgroup cols=2><tbody>
+ <row>
+  <entry>ping</entry>
+  <entry>cloned of an ancient NetTools-B-xx</entry>
+ </row>
+ <row>
+  <entry>ping6</entry>
+  <entry>cloned of a very old Pedro's utility set</entry>
+ </row>
+ <row>
+  <entry>traceroute6</entry>
+  <entry>cloned of NRL Sep 96 distribution</entry>
+ </row>
+ <row>
+  <entry>rdisc</entry>
+  <entry>cloned of SUN in.rdisc</entry>
+ </row>
+ <row>
+  <entry>clockdiff</entry>
+  <entry>broken out of some BSD timed</entry>
+ </row>
+ <row>
+  <entry>tftpd</entry>
+  <entry>it is clone of some ancient NetKit package</entry>
+ </row>
+ </tbody></tgroup>
+</informaltable>
+</para>
+
+<para>
+Also I added some utilities written from scratch, namely
+<command/tracepath/, <command/arping/ and later <command/rarpd/
+(the last one does not satisfy all the criteria, I used it two or three
+times).
+</para>
+
+<para>
+Hesitated a bit I overcame temptation to add <command/traceroute/.
+The variant released by LBNL to that time was mostly sane and bugs
+in it were mostly not specific to Linux, but main reason was that
+the latest version of LBNL <command/traceroute/ was not 
+<emphasis/small/, it consisted of several files,
+used a wicked (and failing with Linux :-)) autoconfiguration etc.
+So, instead I assembled to iputils a simplistic <command/tracepath/ utility
+and IPv6 version of traceroute, and published my 
+<ulink url="ftp://ftp.inr.ac.ru/ip-routing/lbl-tools"> patches</ulink>.
+to LBNL <command/traceroute/ separately.<footnote><para>This was mistake.
+Due to this <command/traceroute/ was in a sad state until recently.
+Good news, redhat-7.2 seems to add these patches to their traceroute
+rpm eventually. So, I think I will refrain of suicide for awhile.
+</para></footnote>
+</para>
+
+</sect1>
+
+<sect1>
+<title>Installation notes</title>
+<para>
+<userinput/make/ to compile utilities. <userinput/make html/ to prepare
+html documentation, <userinput/make man/ if you prefer man pages.
+Nothing fancy, provided you have DocBook package installed.
+</para>
+
+<para>
+<userinput/make install/ installs <emphasis/only/ HTML documentation
+to <filename>/usr/doc/iputils</filename>. It even does not try
+to install binaries and man pages. If you read historical
+notes above, the reason should be evident. Most of utilities
+intersect with utilities distributed in another packages, and
+making such target rewriting existing installation would be a crime
+from my side. The decision what variant of <command/ping/ is preferred,
+how to resolve the conflicts etc. is left to you or to person who
+assembled an rpm. I vote for variant from <command/iputils/ of course.
+</para>
+
+<para>
+Anyway, select utilities which you like and install them to the places
+which you prefer together with their man pages.
+</para>
+
+
+<para>
+It is possible that compilation will fail, if you use some
+funny Linux distribution mangling header files in some unexpected ways
+(expected ones are the ways of redhat of course :-)).
+I validate iputils against <ulink url="http://www.asplinux.ru">asplinux</ulink>
+distribution, which is inevitably followed by validity with respect
+to <ulink url="http://www.redhat.com">redhat</ulink>.
+If your distribution is one of widely known ones, suse or debian,
+it also will compile provided snapshot is elder than month or so and
+someone reported all the problems, if they took place at all.
+</para>
+
+<para>
+<emphasis>
+Anyway, please, do not abuse me complaining about some compilation problems
+in any distribution different of asplinux or redhat.
+If you have a fix, please, send it to
+<ulink url="mailto:kuznet@ms2.inr.ac.ru">me</ulink>,
+I will check that it does not break distributions mentioned above
+and apply it. But I am not going to undertake any investigations,
+bare reports are deemed to be routed to <filename>/dev/null</filename>.
+</emphasis>
+</para>
+
+</sect1>
+
+<sect1><title>Availability</title>
+
+<para>
+The collection of documents is part of <filename/iputils/ package
+and the latest versions are  available in source form at
+<ulink url="http://www.skbuff.net/iputils/iputils-current.tar.bz2">
+http://www.skbuff.net/iputils/iputils-current.tar.bz2</ulink>.
+</para>
+</sect1>
+
+
+<sect1>
+<title>Copying</title>
+<para>
+Different files are copyrighted by different persons and organizations
+and distributed under different licenses. For details look into corresponding
+source files.
+</para>
+</sect1>
+
+</article>
diff --git a/iputils/doc/ninfod.sgml b/iputils/doc/ninfod.sgml
new file mode 100644
index 0000000..1154a75
--- /dev/null
+++ b/iputils/doc/ninfod.sgml
@@ -0,0 +1,120 @@
+<refentry id="ninfod">
+
+<refmeta>
+<refentrytitle>ninfod</refentrytitle>
+<manvolnum>8</manvolnum>
+<refmiscinfo>iputils-&snapshot;</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>ninfod</refname>
+<refpurpose>Respond to IPv6 Node Information Queries</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>ninfod</command>
+<arg choice="opt"><option>-dhv</option></arg>
+<arg choice="opt">-p <replaceable/pidfile/</arg>
+<arg choice="opt">-u <replaceable/user/</arg>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+<para>
+Responds to <ulink url="http://tools.ietf.org/rfc/rfc4620.txt">IPv6 Node Information Queries (RFC4620)</ulink> from clients.
+Queries can be sent by various implementations of <command/ping6/ command.
+</para>
+</refsect1>
+
+<refsect1><title>OPTIONS</title>
+
+<variablelist>
+
+ <varlistentry>
+  <term><option/-a/</term>
+  <listitem><para>
+Debug mode.  Do not go background.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-h/</term>
+  <listitem><para>
+Show help.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-v/</term>
+  <listitem><para>
+Verbose mode.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>-u <replaceable/user/</option></term>
+  <listitem><para>
+Run as another user.
+<replaceable/user/ can either be username or user ID.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>-p <replaceable/pidfile/</option></term>
+  <listitem><para>
+File for process-id storage.
+<replaceable/user/ is required to be able to create the file.
+  </para></listitem>
+ </varlistentry>
+</variablelist>
+</refsect1>
+
+<refsect1><title>SEE ALSO</title>
+<para>
+<link linkend="ping">
+<citerefentry><refentrytitle/ping/<manvolnum/8/</citerefentry></link>.
+</para>
+</refsect1>
+
+<refsect1><title>AUTHOR</title>
+<para>
+<command/ninfod/ was written by USAGI/WIDE Project.
+</para>
+</refsect1>
+
+<refsect1><title>COPYING</title>
+<para>
+<literallayout>
+Copyright (C) 2012 YOSHIFUJI Hideaki.
+Copyright (C) 2002 USAGI/WIDE Project.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the project nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+</literallayout>
+</para>
+</refsect1>
+
+</refentry>
diff --git a/iputils/doc/pg3.sgml b/iputils/doc/pg3.sgml
new file mode 100644
index 0000000..04c80fe
--- /dev/null
+++ b/iputils/doc/pg3.sgml
@@ -0,0 +1,175 @@
+<refentry id="pg3">
+
+<refmeta>
+<refentrytitle>pg3</refentrytitle>
+<manvolnum>8</manvolnum>
+<refmiscinfo>iputils-&snapshot;</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+<refname>pg3, ipg, pgset</refname>
+<refpurpose>send stream of UDP packets</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>source ipg</command>
+</cmdsynopsis>
+<cmdsynopsis>
+<command>pg</command>
+</cmdsynopsis>
+<cmdsynopsis>
+<command>pgset</command>
+<arg choice="req"><replaceable/COMMAND/</arg>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+<para>
+<command/ipg/ is not a program, it is script which should be sourced
+to <command/bash/. When sourced it loads module <filename/pg3/ and
+exports a few of functions accessible from parent shell. These macros
+are <command/pg/ to start packet injection and to get the results of run;
+and <command/pgset/ to setup packet generator.
+</para>
+
+<para>
+<command/pgset/ can send the following commands to module <filename/pg3/:
+</para>
+</refsect1>
+
+<refsect1><title>COMMAND</title>
+
+<variablelist>
+
+ <varlistentry>
+  <term><option>odev <replaceable/DEVICE/</option></term>
+  <listitem><para>
+Name of Ethernet device to test. See
+<link linkend="pg3.warning">warning</link> below.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>pkt_size <replaceable/BYTES/</option></term>
+  <listitem><para>
+Size of packet to generate. The size includes all the headers: UDP, IP,
+MAC, but does not account for overhead internal to medium, i.e. FCS
+and various paddings.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>frags <replaceable/NUMBER/</option></term>
+  <listitem><para>
+Each packet will contain <replaceable/NUMBER/ of fragments.
+Maximal amount for linux-2.4 is 6. Far not all the devices support
+fragmented buffers.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>count <replaceable/NUMBER/</option></term>
+  <listitem><para>
+Send stream of <replaceable/NUMBER/ of packets and stop after this.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>ipg <replaceable/TIME/</option></term>
+  <listitem><para>
+Introduce artificial delay between packets of <replaceable/TIME/
+microseconds.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>dst <replaceable/IP_ADDRESS/</option></term>
+  <listitem><para>
+Select IP destination where the stream is sent to.
+Beware, never set this address at random. <command/pg3/ is not a toy,
+it creates really tough stream. Default value is 0.0.0.0.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>dst <replaceable/MAC_ADDRESS/</option></term>
+  <listitem><para>
+Select MAC destination where the stream is sent to.
+Default value is 00:00:00:00:00:00 in hope that this will not be received
+by any node on LAN.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>stop</option></term>
+  <listitem><para>
+Abort packet injection.
+  </para></listitem>
+ </varlistentry>
+
+</variablelist>
+</refsect1>
+
+<refsect1 id="pg3.warning"><title>WARNING</title>
+<para>
+When output device is set to some random device different
+of hardware Ethernet device, <command/pg3/ will crash kernel.
+</para>
+<para>
+Do not use it on VLAN, ethertap, VTUN and other devices,
+which emulate Ethernet not being real Ethernet in fact.
+</para>
+</refsect1>
+
+<refsect1><title>AUTHOR</title>
+<para>
+<command/pg3/ was written by <ulink url="mailto:robert.olsson@its.uu.se">
+Robert Olsson &lt;robert.olsson@its.uu.se&gt;</ulink>.
+</para>
+</refsect1>
+
+<refsect1><title>SECURITY</title>
+<para>
+This can be used only by superuser.
+</para>
+<para>
+This tool creates floods of packets which is unlikely to be handled
+even by high-end machines. For example, it saturates gigabit link with
+60 byte packets when used with Intel's e1000. In face of such stream
+switches, routers and end hosts may deadlock, crash, explode.
+Use only in test lab environment.
+</para>
+</refsect1>
+
+<refsect1><title>AVAILABILITY</title>
+<para>
+<command/pg3/ is part of <filename/iputils/ package
+and the latest versions are  available in source form at
+<ulink url="http://www.skbuff.net/iputils/iputils-current.tar.bz2">
+http://www.skbuff.net/iputils/iputils-current.tar.bz2</ulink>.
+</para>
+</refsect1>
+
+<![IGNORE[
+<refsect1><title>COPYING</title>
+<para>
+<literallayout>
+This documentation is free software; you can redistribute
+it and/or modify it under the terms of the GNU General Public
+License Version 2.
+
+This program is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied
+warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU General Public License for more details.
+ 
+For more details see the file COPYING in the source
+distribution of Linux kernel of version 2.4.
+</literallayout>
+</para>
+</refsect1>
+]]>
+
+</refentry>
diff --git a/iputils/doc/ping.sgml b/iputils/doc/ping.sgml
new file mode 100644
index 0000000..eec92a2
--- /dev/null
+++ b/iputils/doc/ping.sgml
@@ -0,0 +1,689 @@
+<refentry id="ping">
+
+<refmeta>
+<refentrytitle>ping</refentrytitle>
+<manvolnum>8</manvolnum>
+<refmiscinfo>iputils-&snapshot;</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>ping, ping6</refname>
+<refpurpose>send ICMP ECHO_REQUEST to network hosts</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>ping</command>
+<arg choice="opt"><option>-aAbBdDfhLnOqrRUvV</option></arg>
+<arg choice="opt">-c <replaceable/count/</arg>
+<arg choice="opt">-F <replaceable/flowlabel/</arg>
+<arg choice="opt">-i <replaceable/interval/</arg>
+<arg choice="opt">-I <replaceable/interface/</arg>
+<arg choice="opt">-l <replaceable/preload/</arg>
+<arg choice="opt">-m <replaceable/mark/</arg>
+<arg choice="opt">-M <replaceable/pmtudisc_option/</arg>
+<arg choice="opt">-N <replaceable/nodeinfo_option/</arg>
+<arg choice="opt">-w <replaceable/deadline/</arg>
+<arg choice="opt">-W <replaceable/timeout/</arg>
+<arg choice="opt">-p <replaceable/pattern/</arg>
+<arg choice="opt">-Q <replaceable/tos/</arg>
+<arg choice="opt">-s <replaceable/packetsize/</arg>
+<arg choice="opt">-S <replaceable/sndbuf/</arg>
+<arg choice="opt">-t <replaceable/ttl/</arg>
+<arg choice="opt">-T <replaceable/timestamp option/</arg>
+<arg choice="opt" rep="repeat"><replaceable/hop/</arg>
+<arg choice="req"><replaceable/destination/</arg>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+<para>
+<command/ping/ uses the ICMP protocol's mandatory ECHO_REQUEST
+datagram to elicit an ICMP ECHO_RESPONSE from a host or gateway.
+ECHO_REQUEST datagrams (``pings'') have an IP and ICMP
+header, followed by a <structname/struct timeval/ and then an arbitrary
+number of ``pad'' bytes used to fill out the packet.
+</para>
+<para>
+<command/ping6/ is IPv6 version of <command/ping/, and can also send Node Information Queries (RFC4620).
+Intermediate <replaceable/hop/s may not be allowed, because IPv6 source routing was deprecated (RFC5095).
+</para>
+</refsect1>
+
+<refsect1><title>OPTIONS</title>
+
+<variablelist>
+ <varlistentry>
+  <term><option/-a/</term>
+  <listitem><para>
+Audible ping.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-A/</term>
+  <listitem><para>
+Adaptive ping. Interpacket interval adapts to round-trip time, so that
+effectively not more than one (or more, if preload is set) unanswered probe
+is present in the network. Minimal interval is 200msec for not super-user.
+On networks with low rtt this mode is essentially equivalent to flood mode.  
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-b/</term>
+  <listitem><para>
+Allow pinging a broadcast address.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-B/</term>
+  <listitem><para>
+Do not allow <command/ping/ to change source address of probes.
+The address is bound to one selected when <command/ping/ starts.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option><anchor id="ping.count">-c <replaceable/count/</option></term>
+  <listitem><para>
+Stop after sending <replaceable/count/ ECHO_REQUEST
+packets. With 
+<link linkend="ping.deadline"><replaceable/deadline/</link>
+option, <command/ping/ waits for
+<replaceable/count/ ECHO_REPLY packets, until the timeout expires.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-d/</term>
+  <listitem><para>
+Set the <constant/SO_DEBUG/ option on the socket being used.
+Essentially, this socket option is not used by Linux kernel. 
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-D/</term>
+  <listitem><para>
+Print timestamp (unix time + microseconds as in gettimeofday) before
+each line.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-f/</term>
+  <listitem><para>
+Flood ping. For every ECHO_REQUEST sent a period ``.'' is printed,
+while for ever ECHO_REPLY received a backspace is printed.
+This provides a rapid display of how many packets are being dropped.
+If interval is not given, it sets interval to zero and
+outputs packets as fast as they come back or one hundred times per second,
+whichever is more.
+Only the super-user may use this option with zero interval.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option>-F <replaceable/flow label/</option></term>
+  <listitem><para>
+<command/ping6/ only.
+Allocate and set 20 bit flow label (in hex) on echo request packets.
+If value is zero, kernel allocates random flow label.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-h/</term>
+  <listitem><para>
+Show help.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option>-i <replaceable/interval/</option></term>
+  <listitem><para>
+Wait <replaceable/interval/ seconds between sending each packet.
+The default is to wait for one second between each packet normally,
+or not to wait in flood mode. Only super-user may set interval
+to values less 0.2 seconds.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option>-I <replaceable/interface/</option></term>
+  <listitem><para>
+<replaceable/interface/ is either an address, or an interface name.
+If <replaceable/interface/ is an address, it sets source address
+to specified interface address.
+If <replaceable/interface/ in an interface name, it sets
+source interface to specified interface.
+For <command/ping6/, when doing ping to a link-local scope
+address, link specification (by the '%'-notation in
+<replaceable/destination/, or by this option) is required.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option>-l <replaceable/preload/</option></term>
+  <listitem><para>
+If <replaceable/preload/ is specified,
+<command/ping/ sends that many packets not waiting for reply.
+Only the super-user may select preload more than 3.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-L/</term>
+  <listitem><para>
+Suppress loopback of multicast packets.  This flag only applies if the ping
+destination is a multicast address.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option>-m <replaceable/mark/</option></term>
+  <listitem><para>
+use <replaceable/mark/ to tag the packets going out. This is useful
+for variety of reasons within the kernel such as using policy
+routing to select specific outbound processing.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option>-M <replaceable/pmtudisc_opt/</option></term>
+  <listitem><para>
+Select Path MTU Discovery strategy.
+<replaceable/pmtudisc_option/ may be either <replaceable/do/
+(prohibit fragmentation, even local one), 
+<replaceable/want/ (do PMTU discovery, fragment locally when packet size
+is large), or <replaceable/dont/ (do not set DF flag).
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option>-N <replaceable/nodeinfo_option/</option></term>
+  <listitem><para>
+<command/ping6/ only.
+Send ICMPv6 Node Information Queries (RFC4620), instead of Echo Request.
+   <variablelist>
+    <varlistentry>
+     <term><option>help</option></term>
+     <listitem><para>Show help for NI support.</para></listitem>
+    </varlistentry>
+   </variablelist>
+   <variablelist>
+    <varlistentry>
+     <term><option>name</option></term>
+     <listitem><para>Queries for Node Names.</para></listitem>
+    </varlistentry>
+   </variablelist>
+   <variablelist>
+    <varlistentry>
+     <term><option>ipv6</option></term>
+     <listitem><para>Queries for IPv6 Addresses. There are several IPv6 specific flags.
+      <variablelist>
+       <varlistentry>
+        <term><option>ipv6-global</option></term>
+        <listitem><para>Request IPv6 global-scope addresses.</para></listitem> 
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+        <term><option>ipv6-sitelocal</option></term>
+        <listitem><para>Request IPv6 site-local addresses.</para></listitem> 
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+        <term><option>ipv6-linklocal</option></term>
+        <listitem><para>Request IPv6 link-local addresses.</para></listitem> 
+       </varlistentry>
+      </variablelist>
+      <variablelist>
+       <varlistentry>
+        <term><option>ipv6-all</option></term>
+        <listitem><para>Request IPv6 addresses on other interfaces.</para></listitem> 
+       </varlistentry>
+      </variablelist>
+     </para></listitem>
+    </varlistentry>
+   </variablelist>
+   <variablelist>
+    <varlistentry>
+     <term><option>ipv4</option></term>
+     <listitem><para>Queries for IPv4 Addresses.  There is one IPv4 specific flag.
+      <variablelist>
+       <varlistentry>
+        <term><option>ipv4-all</option></term>
+        <listitem><para>Request IPv4 addresses on other interfaces.</para></listitem>
+       </varlistentry>
+      </variablelist>
+     </para></listitem>
+    </varlistentry>
+   </variablelist>
+   <variablelist>
+    <varlistentry>
+     <term><option>subject-ipv6=<replaceable/ipv6addr/</option></term>
+     <listitem><para>IPv6 subject address.</para></listitem>
+    </varlistentry>
+   </variablelist>
+   <variablelist>
+    <varlistentry>
+     <term><option>subject-ipv4=<replaceable/ipv4addr/</option></term>
+     <listitem><para>IPv4 subject address.</para></listitem>
+    </varlistentry>
+   </variablelist>
+   <variablelist>
+    <varlistentry>
+     <term><option>subject-name=<replaceable/nodename/</option></term>
+     <listitem><para>Subject name.  If it contains more than one dot,
+	fully-qualified domain name is assumed.</para></listitem>
+    </varlistentry>
+   </variablelist>
+   <variablelist>
+    <varlistentry>
+     <term><option>subject-fqdn=<replaceable/nodename/</option></term>
+     <listitem><para>Subject name.  Fully-qualified domain name is
+	always assumed.</para></listitem>
+    </varlistentry>
+   </variablelist>
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-n/</term>
+  <listitem><para>
+Numeric output only.
+No attempt will be made to lookup symbolic names for host addresses.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-O/</term>
+  <listitem><para>
+Report outstanding ICMP ECHO reply before sending next packet.
+This is useful together with the timestamp <option>-D</option> to
+log output to a diagnostic file and search for missing answers.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option>-p <replaceable/pattern/</option></term>
+  <listitem><para>
+You may specify up to 16 ``pad'' bytes to fill out the packet you send.
+This is useful for diagnosing data-dependent problems in a network.
+For example, <option>-p ff</option> will cause the sent packet
+to be filled with all ones.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-q/</term>
+  <listitem><para>
+Quiet output.
+Nothing is displayed except the summary lines at startup time and
+when finished.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option>-Q <replaceable/tos/</option></term>
+  <listitem><para>
+	Set Quality of Service -related bits in ICMP datagrams.
+	<replaceable/tos/ can be decimal (<command/ping/ only) or hex number.
+	</para>
+	<para>
+	In RFC2474, these fields are interpreted as 8-bit Differentiated
+	Services (DS), consisting of: bits 0-1 (2 lowest bits) of separate
+	data, and bits 2-7 (highest 6 bits) of Differentiated Services
+	Codepoint (DSCP).  In RFC2481 and RFC3168, bits 0-1 are used for ECN.
+	</para>
+	<para>
+	Historically (RFC1349, obsoleted by RFC2474), these were interpreted
+	as: bit 0 (lowest bit) for reserved (currently being redefined as
+	congestion control), 1-4 for Type of Service and bits 5-7
+	(highest bits) for Precedence.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-r/</term>
+  <listitem><para>
+Bypass the normal routing tables and send directly to a host on an attached
+interface.
+If the host is not on a directly-attached network, an error is returned.
+This option can be used to ping a local host through an interface
+that has no route through it provided the option <option/-I/ is also
+used.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-R/</term>
+  <listitem><para>
+<command/ping/ only.
+Record route.
+Includes the RECORD_ROUTE option in the ECHO_REQUEST
+packet and displays the route buffer on returned packets.
+Note that the IP header is only large enough for nine such routes.
+Many hosts ignore or discard this option.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option>-s <replaceable/packetsize/</option></term>
+  <listitem><para>
+Specifies the number of data bytes to be sent.  
+The default is 56, which translates into 64 ICMP
+data bytes when combined with the 8 bytes of ICMP header data.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option>-S <replaceable/sndbuf/</option></term>
+  <listitem><para>
+Set socket sndbuf. If not specified, it is selected to buffer
+not more than one packet.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option>-t <replaceable/ttl/</option></term>
+  <listitem><para>
+<command/ping/ only.
+Set the IP Time to Live.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option>-T <replaceable/timestamp option/</option></term>
+  <listitem><para>
+Set special IP timestamp options.
+<replaceable/timestamp option/ may be either 
+<replaceable/tsonly/ (only timestamps), 
+<replaceable/tsandaddr/ (timestamps and addresses) or 
+<replaceable/tsprespec host1 [host2 [host3 [host4]]]/
+(timestamp prespecified hops).
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-U/</term>
+  <listitem><para>
+Print full user-to-user latency (the old behaviour). Normally
+<command/ping/
+prints network round trip time, which can be different
+f.e. due to DNS failures. 
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-v/</term>
+  <listitem><para>
+Verbose output.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-V/</term>
+  <listitem><para>
+Show version and exit.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option><anchor id="ping.deadline">-w <replaceable/deadline/</option></term>
+  <listitem><para>
+Specify a timeout, in seconds, before
+<command/ping/
+exits regardless of how many
+packets have been sent or received. In this case
+<command/ping/
+does not stop after
+<link linkend="ping.count"><replaceable/count/</link>
+packet are sent, it waits either for
+<link linkend="ping.deadline"><replaceable/deadline/</link>
+expire or until
+<link linkend="ping.count"><replaceable/count/</link>
+probes are answered or for some error notification from network.   
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option>-W <replaceable/timeout/</option></term>
+  <listitem><para>
+Time to wait for a response, in seconds. The option affects only timeout
+in absence of any responses, otherwise <command/ping/ waits for two RTTs.
+  </para></listitem>
+ </varlistentry>
+</variablelist>
+
+<para>
+When using <command/ping/ for fault isolation, it should first be run
+on the local host, to verify that the local network interface is up
+and running. Then, hosts and gateways further and further away should be
+``pinged''. Round-trip times and packet loss statistics are computed.
+If duplicate packets are received, they are not included in the packet
+loss calculation, although the round trip time of these packets is used
+in calculating the minimum/average/maximum round-trip time numbers.
+When the specified number of packets have been sent (and received) or
+if the program is terminated with a
+<constant/SIGINT/, a brief summary is displayed. Shorter current statistics
+can be obtained without termination of process with signal
+<constant/SIGQUIT/.
+</para>
+
+<para>
+If <command/ping/ does not receive any reply packets at all it will
+exit with code 1. If a packet 
+<link linkend="ping.count"><replaceable/count/</link>
+and
+<link linkend="ping.deadline"><replaceable/deadline/</link>
+are both specified, and fewer than
+<link linkend="ping.count"><replaceable/count/</link>
+packets are received by the time the
+<link linkend="ping.deadline"><replaceable/deadline/</link>
+has arrived, it will also exit with code 1. 
+On other error it exits with code 2. Otherwise it exits with code 0. This
+makes it possible to use the exit code to see if a host is alive or
+not.
+</para>
+
+
+<para>
+This program is intended for use in network testing, measurement and
+management.
+Because of the load it can impose on the network, it is unwise to use
+<command/ping/ during normal operations or from automated scripts.
+</para>
+
+</refsect1>
+
+
+<refsect1><title>ICMP PACKET DETAILS</title>
+
+<para>
+An IP header without options is 20 bytes.
+An ICMP ECHO_REQUEST packet contains an additional 8 bytes worth
+of ICMP header followed by an arbitrary amount of data.
+When a <replaceable/packetsize/ is given, this indicated the size of this
+extra piece of data (the default is 56). Thus the amount of data received
+inside of an IP packet of type ICMP ECHO_REPLY will always be 8 bytes
+more than the requested data space (the ICMP header).
+</para>
+
+<para>
+If the data space is at least of size of <structname/struct timeval/
+<command/ping/ uses the beginning bytes of this space to include
+a timestamp which it uses in the computation of round trip times.
+If the data space is shorter, no round trip times are given.
+</para>
+
+</refsect1>
+
+<refsect1><title>DUPLICATE AND DAMAGED PACKETS</title>
+
+<para>
+<command/ping/ will report duplicate and damaged packets.
+Duplicate packets should never occur, and seem to be caused by
+inappropriate link-level retransmissions.
+Duplicates may occur in many situations and are rarely (if ever) a
+good sign, although the presence of low levels of duplicates may not
+always be cause for alarm.
+</para>
+
+<para>
+Damaged packets are obviously serious cause for alarm and often
+indicate broken hardware somewhere in the
+<command/ping/ packet's path (in the network or in the hosts).
+</para>
+
+</refsect1>
+
+<refsect1><title>TRYING DIFFERENT DATA PATTERNS</title>
+
+<para>
+The (inter)network layer should never treat packets differently depending
+on the data contained in the data portion.
+Unfortunately, data-dependent problems have been known to sneak into
+networks and remain undetected for long periods of time.
+In many cases the particular pattern that will have problems is something
+that doesn't have sufficient ``transitions'', such as all ones or all
+zeros, or a pattern right at the edge, such as almost all zeros.
+It isn't necessarily enough to specify a data pattern of all zeros (for
+example) on the command line because the pattern that is of interest is
+at the data link level, and the relationship between what you type and
+what the controllers transmit can be complicated.
+</para>
+
+<para>
+This means that if you have a data-dependent problem you will probably
+have to do a lot of testing to find it.
+If you are lucky, you may manage to find a file that either can't be sent
+across your network or that takes much longer to transfer than other
+similar length files.
+You can then examine this file for repeated patterns that you can test
+using the <option/-p/ option of <command/ping/.
+</para>
+
+</refsect1>
+
+<refsect1><title>TTL DETAILS</title>
+
+<para>
+The TTL value of an IP packet represents the maximum number of IP routers
+that the packet can go through before being thrown away.
+In current practice you can expect each router in the Internet to decrement
+the TTL field by exactly one.
+</para>
+
+<para>
+The TCP/IP specification states that the TTL field for TCP
+packets should be set to 60, but many systems use smaller values
+(4.3 BSD uses 30, 4.2 used 15).
+</para>
+
+<para>
+The maximum possible value of this field is 255, and most Unix systems set
+the TTL field of ICMP ECHO_REQUEST packets to 255.
+This is why you will find you can ``ping'' some hosts, but not reach them
+with
+<citerefentry><refentrytitle/telnet/<manvolnum/1/</citerefentry>
+or
+<citerefentry><refentrytitle/ftp/<manvolnum/1/</citerefentry>.
+</para>
+
+<para>
+In normal operation ping prints the TTL value from the packet it receives.
+When a remote system receives a ping packet, it can do one of three things
+with the TTL field in its response:
+</para>
+
+<itemizedlist>
+ <listitem><para>
+Not change it; this is what Berkeley Unix systems did before the
+4.3BSD Tahoe release. In this case the TTL value in the received packet
+will be 255 minus the number of routers in the round-trip path.
+ </para></listitem>
+ <listitem><para>
+Set it to 255; this is what current Berkeley Unix systems do.
+In this case the TTL value in the received packet will be 255 minus the
+number of routers in the path <emphasis/from/
+the remote system <emphasis/to/ the <command/ping/ing host.
+ </para></listitem>
+ <listitem><para>
+Set it to some other value. Some machines use the same value for
+ICMP packets that they use for TCP packets, for example either 30 or 60.
+Others may use completely wild values.
+ </para></listitem>
+</itemizedlist>
+
+</refsect1>
+
+<refsect1><title>BUGS</title>
+
+<itemizedlist>
+ <listitem><para>
+Many Hosts and Gateways ignore the RECORD_ROUTE option.
+ </para></listitem>
+ <listitem><para>
+The maximum IP header length is too small for options like
+RECORD_ROUTE to be completely useful.
+There's not much that can be done about this, however.
+ </para></listitem>
+ <listitem><para>
+Flood pinging is not recommended in general, and flood pinging the
+broadcast address should only be done under very controlled conditions.
+ </para></listitem>
+</itemizedlist>
+
+</refsect1>
+
+<refsect1><title>SEE ALSO</title>
+<para>
+<citerefentry><refentrytitle/netstat/<manvolnum/1/</citerefentry>,
+<citerefentry><refentrytitle/ifconfig/<manvolnum/8/</citerefentry>.
+</para>
+</refsect1>
+
+<refsect1><title>HISTORY</title>
+<para>
+The <command/ping/ command appeared in 4.3BSD.
+</para>
+<para>
+The version described here is its descendant specific to Linux.
+</para>
+</refsect1>
+
+<refsect1><title>SECURITY</title>
+<para>
+<command/ping/ requires <constant/CAP_NET_RAW/ capability
+to be executed. It may be used as set-uid root.
+</para>
+</refsect1>
+
+<refsect1><title>AVAILABILITY</title>
+<para>
+<command/ping/ is part of <filename/iputils/ package
+and the latest versions are  available in source form at
+<ulink url="http://www.skbuff.net/iputils/iputils-current.tar.bz2">
+http://www.skbuff.net/iputils/iputils-current.tar.bz2</ulink>.
+</para>
+</refsect1>
+
+<![IGNORE[
+<refsect1><title>COPYING</title>
+<para>
+<literallayout>
+Copyright (c) 1989 The Regents of the University of California.
+All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Mike Muuss.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+	This product includes software developed by the University of
+	California, Berkeley and its contributors.
+4. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+</literallayout>
+</para>
+</refsect1>
+]]>
+
+
+</refentry>
+
diff --git a/iputils/doc/rarpd.sgml b/iputils/doc/rarpd.sgml
new file mode 100644
index 0000000..9f86ef0
--- /dev/null
+++ b/iputils/doc/rarpd.sgml
@@ -0,0 +1,170 @@
+<refentry id="rarpd">
+
+<refmeta>
+<refentrytitle>rarpd</refentrytitle>
+<manvolnum>8</manvolnum>
+<refmiscinfo>iputils-&snapshot;</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>rarpd</refname>
+<refpurpose>answer RARP REQUESTs</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>arping</command>
+<arg choice="opt"><option>-aAvde</option></arg>
+<arg choice="opt">-b <replaceable/bootdir/</arg>
+<arg choice="opt"><replaceable/interface/</arg>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+<para>
+Listens
+<ulink url="http://tools.ietf.org/rfc/rfc903.txt">RARP</ulink>
+requests from clients. Provided MAC address of client
+is found in <filename>/etc/ethers</filename> database and
+obtained host name is resolvable to an IP address appropriate
+for attached network, <command/rarpd/ answers to client with RARPD
+reply carrying an IP address.
+</para>
+<para>
+To allow multiple boot servers on the network <command/rarpd/
+optionally checks for presence Sun-like bootable image in TFTP directory.
+It should have form <userinput/Hexadecimal_IP.ARCH/, f.e. to load
+sparc 193.233.7.98 <filename/C1E90762.SUN4M/ is linked to
+an image appropriate for SUM4M in directory <filename>/etc/tftpboot</filename>.
+</para>
+</refsect1>
+
+<refsect1><title>WARNING</title>
+<para>
+This facility is deeply obsoleted by
+<ulink url="http://tools.ietf.org/rfc/rfc951.txt">BOOTP</ulink>
+and later
+<ulink url="http://tools.ietf.org/rfc/rfc2131.txt">DHCP</ulink> protocols.
+However, some clients really still need this to boot.
+</para>
+</refsect1>
+
+
+<refsect1><title>OPTIONS</title>
+
+<variablelist>
+
+ <varlistentry>
+  <term><option/-a/</term>
+  <listitem><para>
+Listen on all the interfaces. Currently it is an internal
+option, its function is overridden with <replaceable/interface/
+argument. It should not be used.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-A/</term>
+  <listitem><para>
+Listen not only RARP but also ARP messages, some rare clients
+use ARP by some unknown reason.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-v/</term>
+  <listitem><para>
+Be verbose.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-d/</term>
+  <listitem><para>
+Debug mode. Do not go to background.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-e/</term>
+  <listitem><para>
+Do not check for presence of a boot image, reply if MAC address
+resolves to a valid IP address using <filename>/etc/ethers</filename>
+database and DNS. 
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>-b <replaceable/bootdir/</option></term>
+  <listitem><para>
+TFTP boot directory. Default is <filename>/etc/tftpboot</filename>
+  </para></listitem>
+ </varlistentry>
+</variablelist>
+</refsect1>
+
+<refsect1><title>SEE ALSO</title>
+<para>
+<link linkend="arping">
+<citerefentry><refentrytitle/arping/<manvolnum/8/</citerefentry></link>,
+<link linkend="tftpd">
+<citerefentry><refentrytitle/tftpd/<manvolnum/8/</citerefentry></link>.
+</para>
+</refsect1>
+
+<refsect1><title>AUTHOR</title>
+<para>
+<command/rarpd/ was written by
+<ulink url="mailto:kuznet@ms2.inr.ac.ru">Alexey Kuznetsov
+&lt;kuznet@ms2.inr.ac.ru&gt;</ulink>.
+It is now maintained by
+<ulink url="mailto:yoshfuji@skbuff.net">YOSHIFUJI Hideaki
+&lt;yoshfuji@skbuff.net&gt;</ulink>.
+</para>
+</refsect1>
+
+<refsect1><title>SECURITY</title>
+<para>
+<command/rarpd/ requires <constant/CAP_NET_RAW/ capability
+to listen and send RARP and ARP packets. It also needs <constant/CAP_NET_ADMIN/
+to give to kernel hint for ARP resolution; this is not strictly required,
+but some (most of, to be more exact) clients are so badly broken that
+are not able to answer ARP before they are finally booted. This is
+not wonderful taking into account that clients using RARPD in 2002
+are all unsupported relic creatures of 90's and even earlier.
+</para>
+</refsect1>
+
+<refsect1><title>AVAILABILITY</title>
+<para>
+<command/rarpd/ is part of <filename/iputils/ package
+and the latest versions are  available in source form at
+<ulink url="http://www.skbuff.net/iputils/iputils-current.tar.bz2">
+http://www.skbuff.net/iputils/iputils-current.tar.bz2</ulink>.
+</para>
+</refsect1>
+
+<![IGNORE[
+<refsect1><title>COPYING</title>
+<para>
+<literallayout>
+This documentation is free software; you can redistribute
+it and/or modify it under the terms of the GNU General Public
+License Version 2.
+
+This program is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied
+warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU General Public License for more details.
+ 
+For more details see the file COPYING in the source
+distribution of Linux kernel of version 2.4.
+</literallayout>
+</para>
+</refsect1>
+]]>
+
+
+
+
+</refentry>
diff --git a/iputils/doc/rdisc.sgml b/iputils/doc/rdisc.sgml
new file mode 100644
index 0000000..f991cb9
--- /dev/null
+++ b/iputils/doc/rdisc.sgml
@@ -0,0 +1,246 @@
+<refentry id="rdisc">
+
+<refmeta>
+<refentrytitle>rdisc</refentrytitle>
+<manvolnum>8</manvolnum>
+<refmiscinfo>iputils-&snapshot;</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>rdisc</refname>
+<refpurpose>network router discovery daemon</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>rdisc</command>
+<arg choice="opt"><option>-abdfrstvV</option></arg>
+<arg choice="opt">-p <replaceable/preference/</arg>
+<arg choice="opt">-T <replaceable/max_interval/</arg>
+<arg choice="opt"><replaceable/send_address/</arg>
+<arg choice="opt"><replaceable/receive_address/</arg>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+<para>
+<command/rdisc/ implements client side of the ICMP router discover protocol.
+<command/rdisc/ is invoked at boot time to populate the network
+routing tables with default routes. 
+</para>
+
+<para>
+<command/rdisc/ listens on the ALL_HOSTS (224.0.0.1) multicast address
+(or <replaceable/receive_address/ provided it is given) 
+for ROUTER_ADVERTISE messages from routers. The received
+messages are handled by first ignoring those listed router addresses
+with which the host does not share a network. Among the remaining addresses
+the ones with the highest preference are selected as default routers
+and a default route is entered in the kernel routing table
+for each one of them.
+</para>
+
+<para>
+Optionally, <command/rdisc/ can avoid waiting for routers to announce 
+themselves by sending out a few ROUTER_SOLICITATION messages
+to the ALL_ROUTERS (224.0.0.2) multicast address 
+(or <replaceable/send_address/ provided it is given) 
+when it is started.
+</para>
+
+<para>
+A timer is associated with each router address and the address will
+no longer be considered for inclusion in the the routing tables if the 
+timer expires before a new 
+<emphasis/advertise/ message is received from the router.
+The address will also be excluded from consideration if the host receives an 
+<emphasis/advertise/
+message with the preference being maximally negative.
+</para>
+
+<para>
+Server side of router discovery protocol is supported by Cisco IOS
+and by any more or less complete UNIX routing daemon, f.e <command/gated/.
+Or, <command/rdisc/ can act as responder, if compiled with -DRDISC_SERVER.
+</para>
+
+</refsect1>
+
+<refsect1><title>OPTIONS</title>
+
+<variablelist>
+ <varlistentry>
+  <term><option/-a/</term>
+  <listitem><para>
+Accept all routers independently of the preference they have in their 
+<emphasis/advertise/ messages.
+Normally <command/rdisc/ only accepts (and enters in the kernel routing
+tables) the router or routers with the highest preference.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-b/</term>
+  <listitem><para>
+Opposite to <option/-a/, i.e. install only router with the best
+preference value. It is default behaviour.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-d/</term>
+  <listitem><para>
+Send debugging messages to syslog.
+  </para></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><option/-f/</term>
+  <listitem><para>
+Run <command/rdisc/ forever even if no routers are found.
+Normally <command/rdisc/ gives up if it has not received any 
+<emphasis/advertise/ message after after soliciting three times,
+in which case it exits with a non-zero exit code.
+If <option/-f/ is not specified in the first form then 
+<option/-s/ must be specified.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-r/</term>
+  <listitem><para>
+Responder mode, available only if compiled with -DRDISC_SERVER.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-s/</term>
+  <listitem><para>
+Send three <emphasis/solicitation/ messages initially to quickly discover
+the routers when the system is booted.
+When <option/-s/ is specified <command/rdisc/
+exits with a non-zero exit code if it can not find any routers.
+This can be overridden with the <option/-f/ option.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>-p <replaceable/preference/</option></term>
+  <listitem><para>
+Set preference in advertisement.
+Available only with -r option.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option>-T <replaceable/max_interval/</option></term>
+  <listitem><para>
+Set maximum advertisement interval in seconds.  Default is 600 secs.
+Available only with -r option.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-t/</term>
+  <listitem><para>
+Test mode. Do not go to background.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-v/</term>
+  <listitem><para>
+Be verbose i.e. send lots of debugging messages to syslog.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-V/</term>
+  <listitem><para>
+Print version and exit.
+  </para></listitem>
+ </varlistentry>
+</variablelist>
+</refsect1>
+
+<refsect1><title>HISTORY</title>
+<para>
+This program was developed by Sun Microsystems (see copyright
+notice in source file). It was ported to Linux by
+<ulink url="mailto:kuznet@ms2.inr.ac.ru">Alexey Kuznetsov
+&lt;kuznet@ms2.inr.ac.ru&gt;</ulink>.
+It is now maintained by
+<ulink url="mailto:yoshfuji@skbuff.net">YOSHIFUJI Hideaki
+&lt;yoshfuji@skbuff.net&gt;</ulink>.
+</para>
+</refsect1>
+
+
+<refsect1><title>SEE ALSO</title>
+<para>
+<citerefentry><refentrytitle/icmp/<manvolnum/7/</citerefentry>,
+<citerefentry><refentrytitle/inet/<manvolnum/7/</citerefentry>,
+<link linkend="ping">
+<citerefentry><refentrytitle/ping/<manvolnum/8/</citerefentry></link>.
+</para>
+</refsect1>
+
+<refsect1><title>REFERENCES</title>
+<para>
+Deering, S.E.,ed "ICMP Router Discovery Messages",
+<ulink url="http://tools.ietf.org/rfc/rfc1256.txt">
+RFC1256</ulink>, Network Information Center, SRI International,
+Menlo Park, Calif., September 1991.
+</para>
+</refsect1>
+
+<refsect1><title>SECURITY</title>
+<para>
+<command/rdisc/ requires <constant/CAP_NET_RAW/ to listen
+and send ICMP messages and capability <constant/CAP_NET_ADMIN/
+to update routing tables. 
+</para>
+</refsect1>
+
+<refsect1><title>AVAILABILITY</title>
+<para>
+<command/rdisc/ is part of <filename/iputils/ package
+and the latest versions are  available in source form at
+<ulink url="http://www.skbuff.net/iputils/iputils-current.tar.bz2">
+http://www.skbuff.net/iputils/iputils-current.tar.bz2</ulink>.
+</para>
+</refsect1>
+
+<![IGNORE[
+<refsect1><title>COPYING</title>
+<para>
+<literallayout>
+Rdisc (this program) was developed by Sun Microsystems, Inc. and is 
+provided for unrestricted use provided that this legend is included on 
+all tape media and as a part of the software program in whole or part.  
+Users may copy or modify Rdisc without charge, and they may freely 
+distribute it.
+
+RDISC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+
+Rdisc is provided with no support and without any obligation on the
+part of Sun Microsystems, Inc. to assist in its use, correction,
+modification or enhancement.
+
+SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY RDISC
+OR ANY PART THEREOF.
+
+In no event will Sun Microsystems, Inc. be liable for any lost revenue
+or profits or other special, indirect and consequential damages, even if
+Sun has been advised of the possibility of such damages.
+
+Sun Microsystems, Inc.
+2550 Garcia Avenue
+Mountain View, California  94043
+</literallayout>
+</para>
+</refsect1>
+]]>
+
+
+</refentry>
diff --git a/iputils/doc/snapshot.db b/iputils/doc/snapshot.db
new file mode 100644
index 0000000..6dd54a5
--- /dev/null
+++ b/iputils/doc/snapshot.db
@@ -0,0 +1 @@
+121221
diff --git a/iputils/doc/tftpd.sgml b/iputils/doc/tftpd.sgml
new file mode 100644
index 0000000..fe7fd7c
--- /dev/null
+++ b/iputils/doc/tftpd.sgml
@@ -0,0 +1,151 @@
+<refentry id="tftpd">
+
+<refmeta>
+<refentrytitle>tftpd</refentrytitle>
+<manvolnum>8</manvolnum>
+<refmiscinfo>iputils-&snapshot;</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>tftpd</refname>
+<refpurpose>Trivial File Transfer Protocol server</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>tftpd</command>
+<arg choice="req"><replaceable/directory/</arg>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+<para>
+<command/tftpd/ is a server which supports the DARPA
+Trivial File Transfer Protocol
+(<ulink url="http://tools.ietf.org/rfc/rfc1350.txt">RFC1350</ulink>).
+The TFTP server is started
+by <citerefentry><refentrytitle/inetd/<manvolnum/8/</citerefentry>.
+</para>
+
+<para>
+<replaceable/directory/ is required argument; if it is not given
+<command/tftpd/ aborts. This path is prepended to any file name requested
+via TFTP protocol, effectively chrooting <command/tftpd/ to this directory.
+File names are validated not to escape out of this directory, however
+administrator may configure such escape using symbolic links.
+</para>
+
+<para>
+It is in difference of variants of <command/tftpd/ usually distributed
+with unix-like systems, which take a list of directories and match
+file names to start from one of given prefixes or to some random
+default, when no arguments were given. There are two reasons not to
+behave in this way: first, it is inconvenient, clients are not expected
+to know something about layout of filesystem on server host.
+And second, TFTP protocol is not a tool for browsing of server's filesystem,
+it is just an agent allowing to boot dumb clients. 
+</para>
+
+<para>
+In the case when <command/tftpd/ is used together with
+<link linkend="rarpd">
+<citerefentry><refentrytitle/rarpd/<manvolnum/8/</citerefentry></link>,
+tftp directories in these services should coincide and it is expected
+that each client booted via TFTP has boot image corresponding
+its IP address with an architecture suffix following Sun Microsystems
+conventions. See 
+<link linkend="rarpd">
+<citerefentry><refentrytitle/rarpd/<manvolnum/8/</citerefentry></link>
+for more details.
+</para>
+</refsect1>
+
+<refsect1><title>SECURITY</title>
+<para>
+TFTP protocol does not provide any authentication.
+Due to this capital flaw <command/tftpd/ is not able to restrict
+access to files and will allow only publically readable
+files to be accessed. Files may be written only if they already
+exist and are publically writable.
+</para>
+
+<para>
+Impact is evident, directory exported via TFTP <emphasis/must not/
+contain sensitive information of any kind, everyone is allowed
+to read it as soon as a client is allowed. Boot images do not contain
+such information as rule, however you should think twice before
+publishing f.e. Cisco IOS config files via TFTP, they contain
+<emphasis/unencrypted/ passwords and may contain some information
+about the network, which you were not going to make public.
+</para>
+
+<para>
+The <command/tftpd/ server should be executed by <command/inetd/
+with dropped root privileges, namely with a user ID giving minimal
+access to files published in tftp directory. If it is executed
+as superuser occasionally, <command/tftpd/ drops its UID and GID
+to 65534, which is most likely not the thing which you expect.
+However, this is not very essential; remember, only files accessible
+for everyone can be read or written via TFTP.
+</para>
+
+</refsect1>
+
+
+<refsect1><title>SEE ALSO</title>
+<para>
+<link linkend="rarpd">
+<citerefentry><refentrytitle/rarpd/<manvolnum/8/</citerefentry></link>,
+<citerefentry><refentrytitle/tftp/<manvolnum/1/</citerefentry>,
+<citerefentry><refentrytitle/inetd/<manvolnum/8/</citerefentry>.
+</para>
+</refsect1>
+
+<refsect1><title>HISTORY</title>
+<para>
+The <command/tftpd/ command appeared in 4.2BSD. The source in iputils
+is cleaned up both syntactically (ANSIized) and semantically (UDP socket IO).
+</para>
+<para>
+It is distributed with iputils mostly as good demo of an interesting feature
+(<constant/MSG_CONFIRM/) allowing to boot long images by dumb clients
+not answering ARP requests until they are finally booted.
+However, this is full functional and can be used in production.
+</para>
+</refsect1>
+
+
+<refsect1><title>AVAILABILITY</title>
+<para>
+<command/tftpd/ is part of <filename/iputils/ package
+and the latest versions are  available in source form at
+<ulink url="http://www.skbuff.net/iputils/iputils-current.tar.bz2">
+http://www.skbuff.net/iputils/iputils-current.tar.bz2</ulink>.
+</para>
+</refsect1>
+
+
+<![IGNORE[
+<refsect1><title>COPYING</title>
+<para>
+<literallayout>
+This documentation is free software; you can redistribute
+it and/or modify it under the terms of the GNU General Public
+License Version 2.
+
+This program is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied
+warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU General Public License for more details.
+ 
+For more details see the file COPYING in the source
+distribution of Linux kernel of version 2.4.
+</literallayout>
+</literallayout>
+</para>
+</refsect1>
+]]>
+
+
+
+</refentry>
diff --git a/iputils/doc/tracepath.sgml b/iputils/doc/tracepath.sgml
new file mode 100644
index 0000000..ed91887
--- /dev/null
+++ b/iputils/doc/tracepath.sgml
@@ -0,0 +1,201 @@
+<refentry id="tracepath">
+
+<refmeta>
+<refentrytitle>tracepath</refentrytitle>
+<manvolnum>8</manvolnum>
+<refmiscinfo>iputils-&snapshot;</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>tracepath, tracepath6</refname>
+<refpurpose>
+traces path to a network host discovering MTU along this path</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>tracepath</command>
+<arg choice="opt">-n</arg>
+<arg choice="opt">-b</arg>
+<arg choice="opt">-l <replaceable/pktlen/</arg>
+<arg choice="opt">-m <replaceable/max_hops/</arg>
+<arg choice="opt">-p <replaceable/port/</arg>
+<arg choice="req"><replaceable/destination/</arg>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+<para>
+It traces path to <replaceable/destination/ discovering MTU along this path.
+It uses UDP port <replaceable/port/ or some random port.
+It is similar to <command/traceroute/, only does not require superuser
+privileges and has no fancy options.
+</para>
+
+<para>
+<command/tracepath6/ is good replacement for <command/traceroute6/
+and classic example of application of Linux error queues.
+The situation with IPv4 is worse, because commercial
+IP routers do not return enough information in ICMP error messages.
+Probably, it will change, when they will be updated.
+For now it uses Van Jacobson's trick, sweeping a range
+of UDP ports to maintain trace history.
+</para>
+</refsect1>
+
+<refsect1><title>OPTIONS</title>
+<variablelist>
+
+ <varlistentry>
+  <term><option/-n/</term>
+  <listitem><para>
+Print primarily IP addresses numerically.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-b/</term>
+  <listitem><para>
+Print both of host names and IP addresses.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-l/</term>
+  <listitem><para>
+Sets the initial packet length to <replaceable/pktlen/ instead of
+65535 for <command/tracepath/ or 128000 for <command/tracepath6/.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-m</term>
+  <listitem><para>
+Set maximum hops (or maximum TTLs) to <replaceable/max_hops/
+instead of 30.
+  </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term><option/-p/</term>
+  <listitem><para>
+Sets the initial destination port to use.
+  </para></listitem>
+ </varlistentry>
+</variablelist>
+</refsect1>
+
+<refsect1><title>OUTPUT</title>
+<para>
+<literallayout>
+root@mops:~ # tracepath6 3ffe:2400:0:109::2
+ 1?: [LOCALHOST]                              pmtu 1500
+ 1:  dust.inr.ac.ru                   0.411ms
+ 2:  dust.inr.ac.ru        asymm  1   0.390ms pmtu 1480
+ 2:  3ffe:2400:0:109::2               463.514ms reached
+     Resume: pmtu 1480 hops 2 back 2
+</literallayout>
+</para>
+
+<para>
+The first column shows <literal/TTL/ of the probe, followed by colon.
+Usually value of <literal/TTL/ is obtained from reply from network,
+but sometimes reply does not contain necessary information and
+we have to guess it. In this case the number is followed by ?.
+</para>
+
+<para>
+The second column shows the network hop, which replied to the probe.
+It is either address of router or word <literal/[LOCALHOST]/, if
+the probe was not sent to the network.
+</para>
+
+<para>
+The rest of line shows miscellaneous information about path to
+the correspinding network hop. As rule it contains value of RTT.
+Additionally, it can show Path MTU, when it changes.
+If the path is asymmetric
+or the probe finishes before it reach prescribed hop, difference
+between number of hops in forward and backward direction is shown
+following keyword <literal/async/. This information is not reliable.
+F.e. the third line shows asymmetry of 1, it is because the first probe
+with TTL of 2 was rejected at the first hop due to Path MTU Discovery.
+</para>
+
+<para>
+The last line summarizes information about all the path to the destination,
+it shows detected Path MTU, amount of hops to the destination and our
+guess about amount of hops from the destination to us, which can be
+different when the path is asymmetric.
+</para>
+
+</refsect1>
+
+
+
+
+<refsect1><title>SEE ALSO</title>
+<para>
+<citerefentry><refentrytitle/traceroute/<manvolnum/8/</citerefentry>,
+<link linkend="traceroute6">
+<citerefentry><refentrytitle/traceroute6/<manvolnum/8/</citerefentry></link>,
+<link linkend="ping">
+<citerefentry><refentrytitle/ping/<manvolnum/8/</citerefentry></link>.
+</para>
+</refsect1>
+
+<refsect1><title>AUTHOR</title>
+<para>
+<command/tracepath/ was written by
+<ulink url="mailto:kuznet@ms2.inr.ac.ru">Alexey Kuznetsov
+&lt;kuznet@ms2.inr.ac.ru&gt;</ulink>.
+</para>
+</refsect1>
+
+<refsect1><title>SECURITY</title>
+<para>
+No security issues.
+</para>
+<para>
+This lapidary deserves to be elaborated.
+<command/tracepath/ is not a privileged program, unlike
+<command/traceroute/, <command/ping/ and other beasts of this kind.
+<command/tracepath/ may be executed by everyone who has some access
+to network, enough to send UDP datagrams to investigated destination
+using given port.
+</para>
+</refsect1>
+
+<refsect1><title>AVAILABILITY</title>
+<para>
+<command/tracepath/ is part of <filename/iputils/ package
+and the latest versions are  available in source form at
+<ulink url="http://www.skbuff.net/iputils/iputils-current.tar.bz2">
+http://www.skbuff.net/iputils/iputils-current.tar.bz2</ulink>.
+</para>
+</refsect1>
+
+<![IGNORE[
+<refsect1><title>COPYING</title>
+<para>
+<literallayout>
+This documentation is free software; you can redistribute
+it and/or modify it under the terms of the GNU General Public
+License Version 2.
+
+This program is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied
+warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU General Public License for more details.
+ 
+For more details see the file COPYING in the source
+distribution of Linux kernel of version 2.4.
+</literallayout>
+</para>
+</refsect1>
+]]>
+
+
+
+
+</refentry>
diff --git a/iputils/doc/traceroute6.sgml b/iputils/doc/traceroute6.sgml
new file mode 100644
index 0000000..e47dd13
--- /dev/null
+++ b/iputils/doc/traceroute6.sgml
@@ -0,0 +1,97 @@
+<refentry id="traceroute6">
+
+<refmeta>
+<refentrytitle>traceroute6</refentrytitle>
+<manvolnum>8</manvolnum>
+<refmiscinfo>iputils-&snapshot;</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>traceroute6</refname>
+<refpurpose>traces path to a network host</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>traceroute6</command>
+<arg choice="opt"><option>-dnrvV</option></arg>
+<arg choice="opt">-i <replaceable/interface/</arg>
+<arg choice="opt">-m <replaceable/max_ttl/</arg>
+<arg choice="opt">-p <replaceable/port/</arg>
+<arg choice="opt">-q <replaceable/max_probes/</arg>
+<arg choice="opt">-s <replaceable/source/</arg>
+<arg choice="opt">-w <replaceable/wait time/</arg>
+<arg choice="req"><replaceable/destination/</arg>
+<arg choice="opt"><replaceable/size/</arg>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+<para>
+Description can be found in 
+<citerefentry><refentrytitle/traceroute/<manvolnum/8/</citerefentry>,
+all the references to IP replaced to IPv6. It is needless to copy
+the description from there.
+</para>
+</refsect1>
+
+<refsect1><title>SEE ALSO</title>
+<para>
+<citerefentry><refentrytitle/traceroute/<manvolnum/8/</citerefentry>,
+<citerefentry><refentrytitle/tracepath/<manvolnum/8/</citerefentry>,
+<citerefentry><refentrytitle/ping/<manvolnum/8/</citerefentry>.
+</para>
+</refsect1>
+
+<refsect1><title>HISTORY</title>
+<para>
+This program has long history. Author of <command/traceroute/
+is Van Jacobson and it first appeared in 1988. This clone is
+based on a port of <command/traceroute/ to IPv6 published
+in NRL IPv6 distribution in 1996. In turn, it was ported
+to Linux by Pedro Roque. After this it was kept in sync by    
+<ulink url="mailto:kuznet@ms2.inr.ac.ru">Alexey Kuznetsov
+&lt;kuznet@ms2.inr.ac.ru&gt;</ulink>. And eventually entered
+<command/iputils/ package.
+</para>
+</refsect1>
+
+<refsect1><title>SECURITY</title>
+<para>
+<command/tracepath6/ requires <constant/CAP_NET_RAW/ capability
+to be executed. It is safe to be used as set-uid root.
+</para>
+</refsect1>
+
+<refsect1><title>AVAILABILITY</title>
+<para>
+<command/traceroute6/ is part of <filename/iputils/ package
+and the latest versions are  available in source form at
+<ulink url="http://www.skbuff.net/iputils/iputils-current.tar.bz2">
+http://www.skbuff.net/iputils/iputils-current.tar.bz2</ulink>.
+</para>
+</refsect1>
+
+<![IGNORE[
+<refsect1><title>COPYING</title>
+<para>
+<literallayout>
+This documentation is free software; you can redistribute
+it and/or modify it under the terms of the GNU General Public
+License Version 2.
+
+This program is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied
+warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU General Public License for more details.
+ 
+For more details see the file COPYING in the source
+distribution of Linux kernel of version 2.4.
+</literallayout>
+</para>
+</refsect1>
+]]>
+
+
+
+</refentry>
diff --git a/iputils/in6_flowlabel.h b/iputils/in6_flowlabel.h
new file mode 100644
index 0000000..9a27397
--- /dev/null
+++ b/iputils/in6_flowlabel.h
@@ -0,0 +1,4 @@
+/* The in6_flowlabel.h file in the iputils distribution exists to provide
+ * kernel flowlabel API definitions that are not in the userspace headers
+ * because they are linux-specific. It's not needed on Android because Android
+ * exposes the kernel definitions to userspace directly . */
diff --git a/iputils/ipg b/iputils/ipg
new file mode 100755
index 0000000..9332013
--- /dev/null
+++ b/iputils/ipg
@@ -0,0 +1,34 @@
+#! /bin/bash
+
+if [ -e /proc/modules ] ; then
+	modprobe pg3 >& /dev/null
+	modprobe pktgen >& /dev/null
+fi
+
+for PGDEV in /proc/net/pg /proc/net/pktgen/pg0 / ; do
+	[ -e ${PGDEV} ] && break
+done
+if [ "${PGDEV}" = "/" ] ; then
+	echo "Could not locate pg in /proc/net" 1>&2
+	exit 1
+fi
+
+function pgset() {
+    local result
+
+    echo $1 > ${PGDEV}
+
+    result=`cat ${PGDEV} | fgrep "Result: OK:"`
+    if [ "$result" = "" ]; then
+         cat ${PGDEV} | fgrep Result:
+    fi
+}
+
+function pg() {
+    echo inject > ${PGDEV}
+    cat ${PGDEV}
+}
+
+pgset "odev eth0"
+pgset "dst 0.0.0.0"
+
diff --git a/iputils/iputils.spec b/iputils/iputils.spec
new file mode 100644
index 0000000..9123a40
--- /dev/null
+++ b/iputils/iputils.spec
@@ -0,0 +1,93 @@
+#
+# This spec file is for _testing_.
+#
+
+%define ssdate 20121221
+Summary: The ping program for checking to see if network hosts are alive.
+Name: iputils
+Version: s%{ssdate}
+Release: 1local
+License: GPLv2+
+Group: System Environment/Daemons
+Source0: iputils-s%{ssdate}.tar.bz2
+Prefix: %{_prefix}
+BuildRoot: %{_tmppath}/%{name}-root
+#BuildPrereq: docbook-dtd31-sgml, perl
+Requires: kernel >= 2.4.7
+
+%description
+The iputils package contains ping, a basic networking tool.  The ping
+command sends a series of ICMP protocol ECHO_REQUEST packets to a
+specified network host and can tell you if that machine is alive and
+receiving network traffic.
+
+%prep
+%setup -q %{name}
+
+%build
+make
+make ninfod
+make man
+make html
+
+%install
+rm -fr ${RPM_BUILD_ROOT}
+mkdir -p ${RPM_BUILD_ROOT}%{_sbindir}
+mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
+mkdir -p $RPM_BUILD_ROOT/%{_unitdir}
+
+install -c clockdiff            ${RPM_BUILD_ROOT}%{_sbindir}/
+install -cp arping              ${RPM_BUILD_ROOT}%{_sbindir}/
+install -cp ping                ${RPM_BUILD_ROOT}%{_bindir}/
+install -cp rdisc               ${RPM_BUILD_ROOT}%{_sbindir}/
+install -cp ping6               ${RPM_BUILD_ROOT}%{_bindir}/
+install -cp tracepath           ${RPM_BUILD_ROOT}%{_bindir}/
+install -cp tracepath6          ${RPM_BUILD_ROOT}%{_bindir}/
+install -cp ninfod/ninfod       ${RPM_BUILD_ROOT}%{_sbindir}/
+
+mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
+ln -sf ../bin/ping6 ${RPM_BUILD_ROOT}%{_sbindir}
+ln -sf ../bin/tracepath ${RPM_BUILD_ROOT}%{_sbindir}
+ln -sf ../bin/tracepath6 ${RPM_BUILD_ROOT}%{_sbindir}
+
+mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man8
+install -cp doc/clockdiff.8     ${RPM_BUILD_ROOT}%{_mandir}/man8/
+install -cp doc/arping.8        ${RPM_BUILD_ROOT}%{_mandir}/man8/
+install -cp doc/ping.8          ${RPM_BUILD_ROOT}%{_mandir}/man8/
+install -cp doc/rdisc.8         ${RPM_BUILD_ROOT}%{_mandir}/man8/
+install -cp doc/tracepath.8     ${RPM_BUILD_ROOT}%{_mandir}/man8/
+install -cp doc/ninfod.8        ${RPM_BUILD_ROOT}%{_mandir}/man8/
+ln -s ping.8.gz ${RPM_BUILD_ROOT}%{_mandir}/man8/ping6.8.gz
+ln -s tracepath.8.gz ${RPM_BUILD_ROOT}%{_mandir}/man8/tracepath6.8.gz
+
+iconv -f ISO88591 -t UTF8 RELNOTES -o RELNOTES.tmp
+touch -r RELNOTES RELNOTES.tmp
+mv -f RELNOTES.tmp RELNOTES
+
+%clean
+rm -rf ${RPM_BUILD_ROOT}
+
+%files
+%doc RELNOTES
+%attr(0755,root,root) %caps(cap_net_raw=ep) %{_sbindir}/clockdiff
+#%attr(4755,root,root) %{_sbindir}/clockdiff
+%attr(0755,root,root) %caps(cap_net_raw=ep) %{_sbindir}/arping
+#%attr(4755,root,root) %{_sbindir}/arping
+%attr(0755,root,root) %caps(cap_net_raw=ep cap_net_admin=ep) %{_bindir}/ping
+#%attr(4755,root,root) %{_bindir}/ping
+%attr(0755,root,root) %caps(cap_net_raw=ep cap_net_admin=ep) %{_bindir}/ping6
+#%attr(4755,root,root) %{_bindir}/ping6
+%{_sbindir}/rdisc
+%{_bindir}/tracepath
+%{_bindir}/tracepath6
+%{_sbindir}/ping6
+%{_sbindir}/tracepath
+%{_sbindir}/tracepath6
+%{_sbindir}/ninfod
+%attr(644,root,root) %{_mandir}/man8/*
+
+%changelog
+* Fri Nov 30 2012 YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+  Partically sync with current Fedora's specfile.
+* Sat Feb 23 2001 Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+  Taken iputils rpm from ASPLinux-7.2 as pattern.
diff --git a/iputils/ninfod/COPYING b/iputils/ninfod/COPYING
new file mode 100644
index 0000000..30df58e
--- /dev/null
+++ b/iputils/ninfod/COPYING
@@ -0,0 +1,26 @@
+Copyright (C) 2002 USAGI/WIDE Project.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the project nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/iputils/ninfod/Makefile.in b/iputils/ninfod/Makefile.in
new file mode 100644
index 0000000..ebd7838
--- /dev/null
+++ b/iputils/ninfod/Makefile.in
@@ -0,0 +1,88 @@
+# $USAGI: Makefile.in,v 1.6 2003-01-15 06:41:23 mk Exp $
+#
+# Copyright (C)2002 USAGI/WIDE Project.
+# Copyright (C)2000-2001 Hideaki YOSHIFUJI and USAGI Project.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the project nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+# $Id: Makefile.in,v 1.2 2000/06/10 05:45:14 yoshfuji Exp yoshfuji $
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datarootdir = @datarootdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+
+INSTALL = @INSTALL@
+
+CC = @CC@
+CFLAGS=@CFLAGS@ -D_GNU_SOURCE
+DEFS=@DEFS@
+LIBS=@LIBS@
+LDFLAGS=@LDFLAGS@
+INSTALL = @INSTALL@
+
+# ----------------
+all: ninfod
+clean:
+	-rm -f *.o ninfod
+distclean: clean
+	-rm -f *~ *.bak #*
+	-rm -fr autom4te.cache
+	-rm -f Makefile config.h config.cache config.status config.log
+	-rm -f ninfod.sh
+install: all
+	@INSTALL_DIR@ @sbindir@
+	@INSTALL@ ninfod -o root @sbindir@
+	@INSTALL@ ninfod.sh -o root -m 755 @sysconfdir@/init.d/ninfod
+
+# ----------------
+ninfod: ninfod_addrs.o ni_ifaddrs.o ninfod_name.o ninfod_core.o ninfod.o
+	$(CC) $(LDFLAGS) $^ $(LIBS) -o $@
+%.o: %.c
+	$(CC) $(CFLAGS) -c $(DEFS) -o $@ $<
+
+# ----------------
+ni_ifaddrs.o: config.h ni_ifaddrs.h
+ninfod.o: config.h ninfod.h
+ninfod_addrs.c: config.h ninfod.h ni_ifaddrs.h
+ninfod_core.c: config.h ninfod.h
+ninfod_name.c: config.h ninfod.h
+
diff --git a/iputils/ninfod/config.h.in b/iputils/ninfod/config.h.in
new file mode 100644
index 0000000..b1709dd
--- /dev/null
+++ b/iputils/ninfod/config.h.in
@@ -0,0 +1,139 @@
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Enable debugging */
+#undef ENABLE_DEBUG
+
+/* Enable ttl support for qtypes (deprecated) */
+#undef ENABLE_SUPTYPES
+
+/* Enable threads */
+#undef ENABLE_THREADS
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the <gnutls/openssl.h> header file. */
+#undef HAVE_GNUTLS_OPENSSL_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `cap' library (-lcap). */
+#undef HAVE_LIBCAP
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#undef HAVE_LIBPTHREAD
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the <linux/rtnetlink.h> header file. */
+#undef HAVE_LINUX_RTNETLINK_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `nanosleep' function. */
+#undef HAVE_NANOSLEEP
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/icmp6.h> header file. */
+#undef HAVE_NETINET_ICMP6_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/ip6.h> header file. */
+#undef HAVE_NETINET_IP6_H
+
+/* Define to 1 if you have the <openssl/md5.h> header file. */
+#undef HAVE_OPENSSL_MD5_H
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#undef HAVE_PTHREAD_H
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#undef HAVE_PWD_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have struct icmp6_nodeinfo */
+#undef HAVE_STRUCT_ICMP6_NODEINFO
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/capability.h> header file. */
+#undef HAVE_SYS_CAPABILITY_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#undef HAVE_SYS_UIO_H
+
+/* Define to 1 if you have the <sys/utsname.h> header file. */
+#undef HAVE_SYS_UTSNAME_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
diff --git a/iputils/ninfod/configure b/iputils/ninfod/configure
new file mode 100755
index 0000000..763e416
--- /dev/null
+++ b/iputils/ninfod/configure
@@ -0,0 +1,5519 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.68.
+#
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+#
+# Copyright (C)2002 USAGI/WIDE Project.  All Rights Reserved.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  # We cannot yet assume a decent shell, so we have to provide a
+	# neutralization value for shells without unset; and this also
+	# works around shells that cannot unset nonexistent variables.
+	# Preserve -v and -x to the replacement shell.
+	BASH_ENV=/dev/null
+	ENV=/dev/null
+	(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+	export CONFIG_SHELL
+	case $- in # ((((
+	  *v*x* | *x*v* ) as_opts=-vx ;;
+	  *v* ) as_opts=-v ;;
+	  *x* ) as_opts=-x ;;
+	  * ) as_opts= ;;
+	esac
+	exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in #(
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="ninfod.c"
+ac_default_prefix=/usr/local/v6
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+EGREP
+GREP
+CPP
+INSTALL_DIR
+INSTALL_LIB
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_debug
+enable_threads
+enable_suptypes
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used" >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/PACKAGE]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-debug          Enable debugging
+  --disable-threads       Disable threads (and random delay)
+  --enable-suptypes       Enable suptypes qtype (deprecated)
+  --enable-ttl            Enable ttl support for qtypes (deprecated)
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.68
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+
+Copyright (C)2002 USAGI/WIDE Project.  All Rights Reserved.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=no"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+	 return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+	    return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_type
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.68.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    rm -rf conftest.one conftest.two conftest.dir
+	    echo one > conftest.one
+	    echo two > conftest.two
+	    mkdir conftest.dir
+	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+	      test -s conftest.one && test -s conftest.two &&
+	      test -s conftest.dir/conftest.one &&
+	      test -s conftest.dir/conftest.two
+	    then
+	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	      break 3
+	    fi
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+INSTALL_LIB="\${INSTALL_DATA}"
+
+INSTALL_DIR="\${INSTALL} -d"
+
+
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then :
+  enableval=$enable_debug;
+fi
+
+if test x"$enableval" != x"no"; then
+
+$as_echo "#define ENABLE_DEBUG 1" >>confdefs.h
+
+fi
+
+# Check whether --enable-threads was given.
+if test "${enable_threads+set}" = set; then :
+  enableval=$enable_threads;
+else
+  enable_threads=no
+fi
+
+if test x"$enableval" != x"no"; then
+
+$as_echo "#define ENABLE_THREADS 1" >>confdefs.h
+
+fi
+
+# Check whether --enable-suptypes was given.
+if test "${enable_suptypes+set}" = set; then :
+  enableval=$enable_suptypes;
+fi
+
+if test x"$enableval" != x"no"; then
+
+$as_echo "#define ENABLE_SUPTYPES 1" >>confdefs.h
+
+fi
+
+# Check whether --enable-suptypes was given.
+if test "${enable_suptypes+set}" = set; then :
+  enableval=$enable_suptypes;
+fi
+
+if test x"$enableval" != x"no"; then
+
+$as_echo "#define ENABLE_SUPTYPES 1" >>confdefs.h
+
+fi
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5
+$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; }
+if ${ac_cv_header_time+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_time=yes
+else
+  ac_cv_header_time=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5
+$as_echo "$ac_cv_header_time" >&6; }
+if test $ac_cv_header_time = yes; then
+
+$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in limits.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default"
+if test "x$ac_cv_header_limits_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIMITS_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in gnutls/openssl.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "gnutls/openssl.h" "ac_cv_header_gnutls_openssl_h" "$ac_includes_default"
+if test "x$ac_cv_header_gnutls_openssl_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_GNUTLS_OPENSSL_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in openssl/md5.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "openssl/md5.h" "ac_cv_header_openssl_md5_h" "$ac_includes_default"
+if test "x$ac_cv_header_openssl_md5_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_OPENSSL_MD5_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in sys/uio.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "sys/uio.h" "ac_cv_header_sys_uio_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_uio_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_UIO_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in sys/utsname.h arpa/inet.h netdb.h syslog.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in sys/capability.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "sys/capability.h" "ac_cv_header_sys_capability_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_capability_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_CAPABILITY_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in pwd.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "pwd.h" "ac_cv_header_pwd_h" "$ac_includes_default"
+if test "x$ac_cv_header_pwd_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_PWD_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in netinet/in.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" "$ac_includes_default"
+if test "x$ac_cv_header_netinet_in_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_NETINET_IN_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in netinet/ip6.h netinet/icmp6.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in linux/rtnetlink.h
+do :
+  ac_fn_c_check_header_compile "$LINENO" "linux/rtnetlink.h" "ac_cv_header_linux_rtnetlink_h" "
+#include <asm/types.h>
+#include <sys/socket.h>
+
+"
+if test "x$ac_cv_header_linux_rtnetlink_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LINUX_RTNETLINK_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in pthread.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default"
+if test "x$ac_cv_header_pthread_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_PTHREAD_H 1
+_ACEOF
+
+fi
+
+done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if ${ac_cv_c_bigendian+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_bigendian=unknown
+    # See if we're dealing with a universal compiler.
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifndef __APPLE_CC__
+	       not a universal capable compiler
+	     #endif
+	     typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+	# Check for potential -arch flags.  It is not universal unless
+	# there are at least two -arch flags with different values.
+	ac_arch=
+	ac_prev=
+	for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+	 if test -n "$ac_prev"; then
+	   case $ac_word in
+	     i?86 | x86_64 | ppc | ppc64)
+	       if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+		 ac_arch=$ac_word
+	       else
+		 ac_cv_c_bigendian=universal
+		 break
+	       fi
+	       ;;
+	   esac
+	   ac_prev=
+	 elif test "x$ac_word" = "x-arch"; then
+	   ac_prev=arch
+	 fi
+       done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if sys/param.h defines the BYTE_ORDER macro.
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+	     #include <sys/param.h>
+
+int
+main ()
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+		     && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+		     && LITTLE_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+		#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to _BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # Compile a test program.
+      if test "$cross_compiling" = yes; then :
+  # Try to guess by grepping values from an object file.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+short int ascii_mm[] =
+		  { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+		short int ascii_ii[] =
+		  { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+		int use_ascii (int i) {
+		  return ascii_mm[i] + ascii_ii[i];
+		}
+		short int ebcdic_ii[] =
+		  { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+		short int ebcdic_mm[] =
+		  { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+		int use_ebcdic (int i) {
+		  return ebcdic_mm[i] + ebcdic_ii[i];
+		}
+		extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+	      ac_cv_c_bigendian=yes
+	    fi
+	    if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+	      if test "$ac_cv_c_bigendian" = unknown; then
+		ac_cv_c_bigendian=no
+	      else
+		# finding both strings is unlikely to happen, but who knows?
+		ac_cv_c_bigendian=unknown
+	      fi
+	    fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+	     /* Are we little or big endian?  From Harbison&Steele.  */
+	     union
+	     {
+	       long int l;
+	       char c[sizeof (long int)];
+	     } u;
+	     u.l = 1;
+	     return u.c[sizeof (long int) - 1] == 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_c_bigendian=no
+else
+  ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+    fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+   yes)
+     $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+;; #(
+   no)
+      ;; #(
+   universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+     ;; #(
+   *)
+     as_fn_error $? "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if ${ac_cv_c_const+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+  /* Ultrix mips cc rejects this.  */
+  typedef int charset[2];
+  const charset cs;
+  /* SunOS 4.1.1 cc rejects this.  */
+  char const *const *pcpcc;
+  char **ppc;
+  /* NEC SVR4.0.2 mips cc rejects this.  */
+  struct point {int x, y;};
+  static struct point const zero = {0,0};
+  /* AIX XL C 1.02.0.0 rejects this.
+     It does not let you subtract one const X* pointer from another in
+     an arm of an if-expression whose if-part is not a constant
+     expression */
+  const char *g = "string";
+  pcpcc = &g + (g ? g-g : 0);
+  /* HPUX 7.0 cc rejects these. */
+  ++pcpcc;
+  ppc = (char**) pcpcc;
+  pcpcc = (char const *const *) ppc;
+  { /* SCO 3.2v4 cc rejects this.  */
+    char *t;
+    char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+    *t++ = 0;
+    if (s) return 0;
+  }
+  { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+    int x[] = {25, 17};
+    const int *foo = &x[0];
+    ++foo;
+  }
+  { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+    typedef const int *iptr;
+    iptr p = 0;
+    ++p;
+  }
+  { /* AIX XL C 1.02.0.0 rejects this saying
+       "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+    struct s { int j; const int *ap[3]; };
+    struct s *b; b->j = 5;
+  }
+  { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+    const int foo = 10;
+    if (!foo) return 0;
+  }
+  return !cs[0] && !zero.x;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_const=yes
+else
+  ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+$as_echo "#define const /**/" >>confdefs.h
+
+fi
+
+ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct icmp6_nodeinfo" >&5
+$as_echo_n "checking for struct icmp6_nodeinfo... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+
+int
+main ()
+{
+
+struct icmp6_nodeinfo nodeinfo;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_STRUCT_ICMP6_NODEINFO 1" >>confdefs.h
+
+
+else
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+for ac_func in nanosleep
+do :
+  ac_fn_c_check_func "$LINENO" "nanosleep" "ac_cv_func_nanosleep"
+if test "x$ac_cv_func_nanosleep" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_NANOSLEEP 1
+_ACEOF
+
+fi
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
+$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
+if ${ac_cv_lib_pthread_pthread_create+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_create ();
+int
+main ()
+{
+return pthread_create ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_pthread_create=yes
+else
+  ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for cap_init in -lcap" >&5
+$as_echo_n "checking for cap_init in -lcap... " >&6; }
+if ${ac_cv_lib_cap_cap_init+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcap  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cap_init ();
+int
+main ()
+{
+return cap_init ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_cap_cap_init=yes
+else
+  ac_cv_lib_cap_cap_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cap_cap_init" >&5
+$as_echo "$ac_cv_lib_cap_cap_init" >&6; }
+if test "x$ac_cv_lib_cap_cap_init" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCAP 1
+_ACEOF
+
+  LIBS="-lcap $LIBS"
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for MD5_Init in -lgnutls-openssl" >&5
+$as_echo_n "checking for MD5_Init in -lgnutls-openssl... " >&6; }
+if ${ac_cv_lib_gnutls_openssl_MD5_Init+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgnutls-openssl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char MD5_Init ();
+int
+main ()
+{
+return MD5_Init ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_gnutls_openssl_MD5_Init=yes
+else
+  ac_cv_lib_gnutls_openssl_MD5_Init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnutls_openssl_MD5_Init" >&5
+$as_echo "$ac_cv_lib_gnutls_openssl_MD5_Init" >&6; }
+if test "x$ac_cv_lib_gnutls_openssl_MD5_Init" = xyes; then :
+  $as_echo "#define HAVE_MD5_INIT 1" >>confdefs.h
+
+	LIBS="-lgnutls-openssl $LIBS"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MD5_Init in -lcrypto" >&5
+$as_echo_n "checking for MD5_Init in -lcrypto... " >&6; }
+if ${ac_cv_lib_crypto_MD5_Init+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char MD5_Init ();
+int
+main ()
+{
+return MD5_Init ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_crypto_MD5_Init=yes
+else
+  ac_cv_lib_crypto_MD5_Init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_MD5_Init" >&5
+$as_echo "$ac_cv_lib_crypto_MD5_Init" >&6; }
+if test "x$ac_cv_lib_crypto_MD5_Init" = xyes; then :
+  $as_echo "#define HAVE_MD5_INIT 1" >>confdefs.h
+
+		LIBS="-lcrypto $LIBS"
+fi
+
+
+fi
+
+
+
+ac_config_files="$ac_config_files Makefile ninfod.sh"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+	cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+	  mv -f confcache "$cache_file"$$ &&
+	  mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+	  mv -f confcache "$cache_file" ;;
+	esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in #(
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.68.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.68,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "ninfod.sh") CONFIG_FILES="$CONFIG_FILES ninfod.sh" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_tt"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    "
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+    } >"$ac_tmp/config.h" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$ac_tmp/config.h" "$ac_file" \
+	|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error $? "could not create -" "$LINENO" 5
+  fi
+ ;;
+
+
+  esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/iputils/ninfod/configure.in b/iputils/ninfod/configure.in
new file mode 100644
index 0000000..2e3275e
--- /dev/null
+++ b/iputils/ninfod/configure.in
@@ -0,0 +1,141 @@
+dnl $USAGI: configure.in,v 1.12 2003-07-16 09:49:01 yoshfuji Exp $
+
+dnl Copyright (C) 2002 USAGI/WIDE Project.
+dnl All rights reserved.
+dnl 
+dnl Redistribution and use in source and binary forms, with or without
+dnl modification, are permitted provided that the following conditions
+dnl are met:
+dnl 1. Redistributions of source code must retain the above copyright
+dnl    notice, this list of conditions and the following disclaimer.
+dnl 2. Redistributions in binary form must reproduce the above copyright
+dnl    notice, this list of conditions and the following disclaimer in the
+dnl    documentation and/or other materials provided with the distribution.
+dnl 3. Neither the name of the project nor the names of its contributors
+dnl    may be used to endorse or promote products derived from this software
+dnl    without specific prior written permission.
+dnl 
+dnl THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+dnl ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+dnl IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+dnl ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+dnl FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+dnl DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+dnl OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+dnl HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+dnl LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+dnl OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+dnl SUCH DAMAGE.
+
+AC_PREREQ(2.53)
+AC_INIT(ninfod.c)
+AC_CONFIG_HEADER(config.h)
+AC_PREFIX_DEFAULT(/usr/local/v6)
+
+AC_COPYRIGHT([Copyright (C)2002 USAGI/WIDE Project.  All Rights Reserved.])
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+INSTALL_LIB="\${INSTALL_DATA}"
+AC_SUBST(INSTALL_LIB)
+INSTALL_DIR="\${INSTALL} -d"
+AC_SUBST(INSTALL_DIR)
+
+dnl Checks for Enable/With
+AC_ARG_ENABLE(debug,
+[  --enable-debug          Enable debugging])
+if test x"$enableval" != x"no"; then
+  AC_DEFINE(ENABLE_DEBUG, 1, 
+	    [Enable debugging])
+fi
+
+AC_ARG_ENABLE(threads,
+[  --disable-threads       Disable threads (and random delay)],,enable_threads=no)
+if test x"$enableval" != x"no"; then
+  AC_DEFINE(ENABLE_THREADS, 1,
+            [Enable threads])
+fi
+
+AC_ARG_ENABLE(suptypes,
+[  --enable-suptypes       Enable suptypes qtype (deprecated)])
+if test x"$enableval" != x"no"; then
+  AC_DEFINE(ENABLE_SUPTYPES, 1,
+	    [Enable suptypes (deprecated)])
+fi
+
+AC_ARG_ENABLE(suptypes,
+[  --enable-ttl            Enable ttl support for qtypes (deprecated)])
+if test x"$enableval" != x"no"; then
+  AC_DEFINE(ENABLE_SUPTYPES, 1,
+	    [Enable ttl support for qtypes (deprecated)])
+fi
+
+dnl Checks for libraries.
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_HEADER_TIME
+AC_CHECK_HEADERS(limits.h)
+AC_CHECK_HEADERS(gnutls/openssl.h)
+AC_CHECK_HEADERS(openssl/md5.h)
+AC_CHECK_HEADERS(sys/uio.h)
+AC_CHECK_HEADERS(sys/utsname.h arpa/inet.h netdb.h syslog.h)
+AC_CHECK_HEADERS(sys/capability.h)
+AC_CHECK_HEADERS(pwd.h)
+AC_CHECK_HEADERS(netinet/in.h)
+AC_CHECK_HEADERS(netinet/ip6.h netinet/icmp6.h,,,[
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+])
+AC_CHECK_HEADERS(linux/rtnetlink.h,,,[
+#include <asm/types.h>
+#include <sys/socket.h>
+])
+AC_CHECK_HEADERS(pthread.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_BIGENDIAN
+AC_C_CONST
+AC_TYPE_SIZE_T
+
+AC_MSG_CHECKING([for struct icmp6_nodeinfo])
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+],[
+struct icmp6_nodeinfo nodeinfo;
+],[
+	AC_MSG_RESULT([yes])
+	AC_DEFINE([HAVE_STRUCT_ICMP6_NODEINFO], 1,
+		  [Define to 1 if you have struct icmp6_nodeinfo])
+],[
+	AC_MSG_RESULT([no])
+])
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(nanosleep)
+AC_CHECK_LIB(pthread, pthread_create)
+AC_CHECK_LIB(cap, cap_init)
+
+AC_CHECK_LIB(gnutls-openssl, MD5_Init,
+	AC_DEFINE(HAVE_MD5_INIT)
+	LIBS="-lgnutls-openssl $LIBS",
+	AC_CHECK_LIB(crypto, MD5_Init,
+		AC_DEFINE(HAVE_MD5_INIT)
+		LIBS="-lcrypto $LIBS",
+	)
+)
+dnl AC_CHECK_LIB(crypto, MD5Init,
+dnl	AC_DEFINE(HAVE_MD5INIT)
+dnl	LIBS="-lcrypto $LIBS",
+dnl)
+
+dnl AC_SUBST(DEFS)
+
+AC_OUTPUT(Makefile ninfod.sh)
diff --git a/iputils/ninfod/icmp6_nodeinfo.h b/iputils/ninfod/icmp6_nodeinfo.h
new file mode 100644
index 0000000..5c6e741
--- /dev/null
+++ b/iputils/ninfod/icmp6_nodeinfo.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ICMP6_NODEINFO_H
+#define ICMP6_NODEINFO_H
+
+struct icmp6_nodeinfo {
+	struct icmp6_hdr	icmp6_ni_hdr;
+	uint8_t			icmp6_ni_nonce[8];
+	/* could be followed by reply data */
+};
+
+#define ni_type		icmp6_ni_hdr.icmp6_type
+#define ni_code		icmp6_ni_hdr.icmp6_code
+#define ni_cksum	icmp6_ni_hdr.icmp6_cksum
+#define ni_qtype	icmp6_ni_hdr.icmp6_data16[0]
+#define ni_flags	icmp6_ni_hdr.icmp6_data16[1]
+#define ni_nonce	icmp6_ni_nonce
+
+/* ICMP6 types */
+#define ICMP6_NI_QUERY			139
+#define ICMP6_NI_REPLY			140
+
+/* ICMP6 codes for NI Query */
+#define ICMP6_NI_SUBJ_IPV6		0	/* Query Subject is an ipv6 address */
+#define ICMP6_NI_SUBJ_FQDN		1	/* Query Subject is a Domain name */
+#define ICMP6_NI_SUBJ_IPV4		2	/* Query Subject is an ipv4 address */
+
+/* ICMP6 codes for NI Reply */
+#define ICMP6_NI_SUCCESS		0	/* NI successful reply */
+#define ICMP6_NI_REFUSED		1	/* NI request is refused */
+#define ICMP6_NI_UNKNOWN		2	/* unknown Qtype */
+
+/* NI Codes */
+#define NI_QTYPE_NOOP			0	/* NOOP  */
+#define NI_QTYPE_SUPTYPES		1	/* Supported Qtypes */
+#define NI_QTYPE_DNSNAME		2	/* DNS Name */
+#define NI_QTYPE_NODEADDR		3	/* Node Addresses */
+#define NI_QTYPE_IPV4ADDR		4	/* IPv4 Addresses */
+
+/* NI Flags */
+#if WORDS_BIGENDIAN
+#define NI_SUPTYPE_FLAG_COMPRESS	0x1
+#define NI_FQDN_FLAG_VALIDTTL		0x1
+#else
+#define NI_SUPTYPE_FLAG_COMPRESS	0x0100
+#define NI_FQDN_FLAG_VALIDTTL		0x0100
+#endif
+
+#if WORDS_BIGENDIAN
+#define NI_NODEADDR_FLAG_TRUNCATE	0x1
+#define NI_NODEADDR_FLAG_ALL		0x2
+#define NI_NODEADDR_FLAG_COMPAT		0x4
+#define NI_NODEADDR_FLAG_LINKLOCAL	0x8
+#define NI_NODEADDR_FLAG_SITELOCAL	0x10
+#define NI_NODEADDR_FLAG_GLOBAL		0x20
+#else
+#define NI_NODEADDR_FLAG_TRUNCATE	0x0100
+#define NI_NODEADDR_FLAG_ALL		0x0200
+#define NI_NODEADDR_FLAG_COMPAT		0x0400
+#define NI_NODEADDR_FLAG_LINKLOCAL	0x0800
+#define NI_NODEADDR_FLAG_SITELOCAL	0x1000
+#define NI_NODEADDR_FLAG_GLOBAL		0x2000
+#endif
+
+#define NI_IPV4ADDR_FLAG_TRUNCATE	NI_NODEADDR_FLAG_TRUNCATE
+#define NI_IPV4ADDR_FLAG_ALL		NI_NODEADDR_FLAG_ALL
+
+#endif
+
diff --git a/iputils/ninfod/install-sh b/iputils/ninfod/install-sh
new file mode 100755
index 0000000..e9de238
--- /dev/null
+++ b/iputils/ninfod/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+		chmodcmd=""
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/iputils/ninfod/ni_ifaddrs.c b/iputils/ninfod/ni_ifaddrs.c
new file mode 100644
index 0000000..4ee2838
--- /dev/null
+++ b/iputils/ninfod/ni_ifaddrs.c
@@ -0,0 +1,543 @@
+/* $USAGI: ni_ifaddrs.c,v 1.8 2007-10-11 06:25:21 yoshfuji Exp $ */
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* reformatted by indent -kr -i8 -l 1000 */
+/* USAGI: ifaddrs.c,v 1.18 2002/03/06 01:50:46 yoshfuji Exp */
+
+/**************************************************************************
+ * ifaddrs.c
+ * Copyright (C)2000 Hideaki YOSHIFUJI, All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <time.h>
+#include <malloc.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netpacket/packet.h>
+#include <net/ethernet.h>	/* the L2 protocols */
+#include <sys/uio.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include "ni_ifaddrs.h"
+#include <netinet/in.h>
+
+#ifdef _USAGI_LIBINET6
+#include "libc-compat.h"
+#endif
+
+//#define IFA_LOCAL	IFA_LOCAL
+
+static const char *RCSID __attribute__ ((unused)) = "$USAGI: ni_ifaddrs.c,v 1.8 2007-10-11 06:25:21 yoshfuji Exp $ based on USAGI: ifaddrs.c,v 1.18 2002/03/06 01:50:46 yoshfuji Exp";
+
+/* ====================================================================== */
+struct nlmsg_list {
+	struct nlmsg_list *nlm_next;
+	struct nlmsghdr *nlh;
+	int size;
+	time_t seq;
+};
+
+#ifndef IFA_LOCAL
+struct rtmaddr_ifamap {
+	void *address;
+	void *local;
+	void *broadcast;
+	int address_len;
+	int local_len;
+	int broadcast_len;
+};
+#endif
+
+/* ====================================================================== */
+static int nl_sendreq(int sd, int request, int flags, int *seq)
+{
+	char reqbuf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
+	struct sockaddr_nl nladdr;
+	struct nlmsghdr *req_hdr;
+	struct rtgenmsg *req_msg;
+	time_t t = time(NULL);
+
+	if (seq)
+		*seq = t;
+	memset(&reqbuf, 0, sizeof(reqbuf));
+	req_hdr = (struct nlmsghdr *) reqbuf;
+	req_msg = (struct rtgenmsg *) NLMSG_DATA(req_hdr);
+	req_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*req_msg));
+	req_hdr->nlmsg_type = request;
+	req_hdr->nlmsg_flags = flags | NLM_F_REQUEST;
+	req_hdr->nlmsg_pid = 0;
+	req_hdr->nlmsg_seq = t;
+	req_msg->rtgen_family = AF_UNSPEC;
+	memset(&nladdr, 0, sizeof(nladdr));
+	nladdr.nl_family = AF_NETLINK;
+	return (sendto(sd, (void *) req_hdr, req_hdr->nlmsg_len, 0, (struct sockaddr *) &nladdr, sizeof(nladdr)));
+}
+
+static int nl_recvmsg(int sd, int request, int seq, void *buf, size_t buflen, int *flags)
+{
+	struct msghdr msg;
+	struct iovec iov = { buf, buflen };
+	struct sockaddr_nl nladdr;
+	int read_len;
+
+	for (;;) {
+		msg.msg_name = (void *) &nladdr;
+		msg.msg_namelen = sizeof(nladdr);
+		msg.msg_iov = &iov;
+		msg.msg_iovlen = 1;
+		msg.msg_control = NULL;
+		msg.msg_controllen = 0;
+		msg.msg_flags = 0;
+		read_len = recvmsg(sd, &msg, 0);
+		if ((read_len < 0 && errno == EINTR)
+		    || (msg.msg_flags & MSG_TRUNC))
+			continue;
+		if (flags)
+			*flags = msg.msg_flags;
+		break;
+	}
+	return read_len;
+}
+
+static int nl_getmsg(int sd, int request, int seq, struct nlmsghdr **nlhp, int *done)
+{
+	struct nlmsghdr *nh;
+	size_t bufsize = 65536, lastbufsize = 0;
+	void *buff = NULL;
+	int result = 0, read_size;
+	int msg_flags;
+	pid_t pid = getpid();
+	for (;;) {
+		void *newbuff = realloc(buff, bufsize);
+		if (newbuff == NULL || bufsize < lastbufsize) {
+			free(newbuff);
+			result = -1;
+			break;
+		}
+		buff = newbuff;
+		result = read_size = nl_recvmsg(sd, request, seq, buff, bufsize, &msg_flags);
+		if (read_size < 0 || (msg_flags & MSG_TRUNC)) {
+			lastbufsize = bufsize;
+			bufsize *= 2;
+			continue;
+		}
+		if (read_size == 0)
+			break;
+		nh = (struct nlmsghdr *) buff;
+		for (nh = (struct nlmsghdr *) buff; NLMSG_OK(nh, read_size); nh = (struct nlmsghdr *) NLMSG_NEXT(nh, read_size)) {
+			if (nh->nlmsg_pid != pid || nh->nlmsg_seq != seq)
+				continue;
+			if (nh->nlmsg_type == NLMSG_DONE) {
+				(*done)++;
+				break;	/* ok */
+			}
+			if (nh->nlmsg_type == NLMSG_ERROR) {
+				struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA(nh);
+				result = -1;
+				if (nh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
+					errno = EIO;
+				else
+					errno = -nlerr->error;
+				break;
+			}
+		}
+		break;
+	}
+	if (result < 0)
+		if (buff) {
+			int saved_errno = errno;
+			free(buff);
+			buff = NULL;
+			errno = saved_errno;
+		}
+	*nlhp = (struct nlmsghdr *) buff;
+	return result;
+}
+
+static int nl_getlist(int sd, int seq, int request, struct nlmsg_list **nlm_list, struct nlmsg_list **nlm_end)
+{
+	struct nlmsghdr *nlh = NULL;
+	int status;
+	int done = 0;
+
+	status = nl_sendreq(sd, request, NLM_F_ROOT | NLM_F_MATCH, &seq);
+	if (status < 0)
+		return status;
+	if (seq == 0)
+		seq = (int) time(NULL);
+	while (!done) {
+		status = nl_getmsg(sd, request, seq, &nlh, &done);
+		if (status < 0)
+			return status;
+		if (nlh) {
+			struct nlmsg_list *nlm_next = (struct nlmsg_list *) malloc(sizeof(struct nlmsg_list));
+			if (nlm_next == NULL) {
+				int saved_errno = errno;
+				free(nlh);
+				errno = saved_errno;
+				status = -1;
+			} else {
+				nlm_next->nlm_next = NULL;
+				nlm_next->nlh = (struct nlmsghdr *) nlh;
+				nlm_next->size = status;
+				nlm_next->seq = seq;
+				if (*nlm_list == NULL) {
+					*nlm_list = nlm_next;
+					*nlm_end = nlm_next;
+				} else {
+					(*nlm_end)->nlm_next = nlm_next;
+					*nlm_end = nlm_next;
+				}
+			}
+		}
+	}
+	return status >= 0 ? seq : status;
+}
+
+/* ---------------------------------------------------------------------- */
+static void free_nlmsglist(struct nlmsg_list *nlm0)
+{
+	struct nlmsg_list *nlm, *nlm_next;
+	int saved_errno;
+	if (!nlm0)
+		return;
+	saved_errno = errno;
+	nlm = nlm0;
+	while(nlm) {
+		if(nlm->nlh)
+			free(nlm->nlh);
+		nlm_next = nlm->nlm_next;
+		free(nlm);
+		nlm = nlm_next;
+	}
+	errno = saved_errno;
+}
+
+static void free_data(void *data)
+{
+	int saved_errno = errno;
+	if (data != NULL)
+		free(data);
+	errno = saved_errno;
+}
+
+/* ---------------------------------------------------------------------- */
+static void nl_close(int sd)
+{
+	int saved_errno = errno;
+	if (sd >= 0)
+		close(sd);
+	errno = saved_errno;
+}
+
+/* ---------------------------------------------------------------------- */
+static int nl_open(void)
+{
+	struct sockaddr_nl nladdr;
+	int sd;
+
+	sd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (sd < 0)
+		return -1;
+	memset(&nladdr, 0, sizeof(nladdr));
+	nladdr.nl_family = AF_NETLINK;
+	if (bind(sd, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
+		nl_close(sd);
+		return -1;
+	}
+	return sd;
+}
+
+/* ====================================================================== */
+int ni_ifaddrs(struct ni_ifaddrs **ifap, sa_family_t family)
+{
+	int sd;
+	struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm;
+	/* - - - - - - - - - - - - - - - */
+	int icnt;
+	size_t dlen, xlen;
+	uint32_t max_ifindex = 0;
+
+	pid_t pid = getpid();
+	int seq = 0;
+	int result;
+	int build;		/* 0 or 1 */
+
+/* ---------------------------------- */
+	/* initialize */
+	icnt = dlen = xlen = 0;
+	nlmsg_list = nlmsg_end = NULL;
+
+	if (ifap)
+		*ifap = NULL;
+
+/* ---------------------------------- */
+	/* open socket and bind */
+	sd = nl_open();
+	if (sd < 0)
+		return -1;
+
+/* ---------------------------------- */
+	/* gather info */
+	if ((seq = nl_getlist(sd, seq + 1, RTM_GETADDR, &nlmsg_list, &nlmsg_end)) < 0) {
+		free_nlmsglist(nlmsg_list);
+		nl_close(sd);
+		return -1;
+	}
+
+/* ---------------------------------- */
+	/* Estimate size of result buffer and fill it */
+	for (build = 0; build <= 1; build++) {
+		struct ni_ifaddrs *ifl = NULL, *ifa = NULL;
+		struct nlmsghdr *nlh, *nlh0;
+		void *data = NULL, *xdata = NULL;
+		uint16_t *ifflist = NULL;
+#ifndef IFA_LOCAL
+		struct rtmaddr_ifamap ifamap;
+#endif
+
+		if (build) {
+			ifa = data = calloc(1, NLMSG_ALIGN(sizeof(struct ni_ifaddrs[icnt]))
+					    + dlen + xlen);
+			if (ifap != NULL)
+				*ifap = ifa;
+			else {
+				free_data(data);
+				result = 0;
+				break;
+			}
+			if (data == NULL) {
+				free_data(data);
+				result = -1;
+				break;
+			}
+			ifl = NULL;
+			data += NLMSG_ALIGN(sizeof(struct ni_ifaddrs)) * icnt;
+			xdata = data + dlen;
+			ifflist = xdata + xlen;
+		}
+
+		for (nlm = nlmsg_list; nlm; nlm = nlm->nlm_next) {
+			int nlmlen = nlm->size;
+			if (!(nlh0 = nlm->nlh))
+				continue;
+			for (nlh = nlh0; NLMSG_OK(nlh, nlmlen); nlh = NLMSG_NEXT(nlh, nlmlen)) {
+				struct ifaddrmsg *ifam = NULL;
+				struct rtattr *rta;
+
+				size_t nlm_struct_size = 0;
+				sa_family_t nlm_family = 0;
+				uint32_t nlm_scope = 0, nlm_index = 0;
+				unsigned int nlm_flags;
+				size_t rtasize;
+
+#ifndef IFA_LOCAL
+				memset(&ifamap, 0, sizeof(ifamap));
+#endif
+
+				/* check if the message is what we want */
+				if (nlh->nlmsg_pid != pid || nlh->nlmsg_seq != nlm->seq)
+					continue;
+				if (nlh->nlmsg_type == NLMSG_DONE) {
+					break;	/* ok */
+				}
+				switch (nlh->nlmsg_type) {
+				case RTM_NEWADDR:
+					ifam = (struct ifaddrmsg *) NLMSG_DATA(nlh);
+					nlm_struct_size = sizeof(*ifam);
+					nlm_family = ifam->ifa_family;
+					nlm_scope = ifam->ifa_scope;
+					nlm_index = ifam->ifa_index;
+					nlm_flags = ifam->ifa_flags;
+					if (family && nlm_family != family)
+						continue;
+					if (build) {
+						ifa->ifa_ifindex = nlm_index;
+						ifa->ifa_flags = nlm_flags;
+					}
+					break;
+				default:
+					continue;
+				}
+
+				if (!build) {
+					if (max_ifindex < nlm_index)
+						max_ifindex = nlm_index;
+				} else {
+					if (ifl != NULL)
+						ifl->ifa_next = ifa;
+				}
+
+				rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size);
+				for (rta = (struct rtattr *) (((char *) NLMSG_DATA(nlh)) + 
+									NLMSG_ALIGN(nlm_struct_size)); 
+				     RTA_OK(rta, rtasize); 
+				     rta = RTA_NEXT(rta, rtasize)) {
+					void *rtadata = RTA_DATA(rta);
+					size_t rtapayload = RTA_PAYLOAD(rta);
+
+					switch (nlh->nlmsg_type) {
+					case RTM_NEWADDR:
+						if (nlm_family == AF_PACKET)
+							break;
+						switch (rta->rta_type) {
+#ifndef IFA_LOCAL
+						case IFA_ADDRESS:
+							ifamap.address = rtadata;
+							ifamap.address_len = rtapayload;
+							break;
+						case IFA_LOCAL:
+							ifamap.local = rtadata;
+							ifamap.local_len = rtapayload;
+							break;
+						case IFA_BROADCAST:
+							ifamap.broadcast = rtadata;
+							ifamap.broadcast_len = rtapayload;
+							break;
+						case IFA_LABEL:
+							break;
+						case IFA_UNSPEC:
+							break;
+#else
+						case IFA_LOCAL:
+							if (!build)
+								dlen += NLMSG_ALIGN(rtapayload);
+							else {
+								memcpy(data, rtadata, rtapayload);
+								ifa->ifa_addr = data;
+								data += NLMSG_ALIGN(rtapayload);
+							}
+							break;
+#endif
+						case IFA_CACHEINFO:
+							if (!build)
+								xlen += NLMSG_ALIGN(rtapayload);
+							else {
+								memcpy(xdata, rtadata, rtapayload);
+								ifa->ifa_cacheinfo = xdata;
+								xdata += NLMSG_ALIGN(rtapayload);
+							}
+							break;
+						}
+					}
+				}
+#ifndef IFA_LOCAL
+				if (nlh->nlmsg_type == RTM_NEWADDR && nlm_family != AF_PACKET) {
+					if (!ifamap.local) {
+						ifamap.local = ifamap.address;
+						ifamap.local_len = ifamap.address_len;
+					}
+					if (!ifamap.address) {
+						ifamap.address = ifamap.local;
+						ifamap.address_len = ifamap.local_len;
+					}
+					if (ifamap.address_len != ifamap.local_len || 
+					    (ifamap.address != NULL && 
+					     memcmp(ifamap.address, ifamap.local, ifamap.address_len))) {
+						/* p2p; address is peer and local is ours */
+						ifamap.broadcast = ifamap.address;
+						ifamap.broadcast_len = ifamap.address_len;
+						ifamap.address = ifamap.local;
+						ifamap.address_len = ifamap.local_len;
+					}
+					if (ifamap.address) {
+						if (!build)
+							dlen += NLMSG_ALIGN(ifamap.address_len);
+						else {
+							ifa->ifa_addr = (struct sockaddr *) data;
+							memcpy(ifa->ifa_addr, ifamap.address, ifamap.address_len);
+							data += NLMSG_ALIGN(ifamap.address_len);
+						}
+					}
+				}
+#endif
+				if (!build) {
+					icnt++;
+				} else {
+					ifl = ifa++;
+				}
+			}
+		}
+		if (!build) {
+			if (icnt == 0 && (dlen + xlen == 0)) {
+				if (ifap != NULL)
+					*ifap = NULL;
+				break;	/* cannot found any addresses */
+			}
+		}
+	}
+
+/* ---------------------------------- */
+	/* Finalize */
+	free_nlmsglist(nlmsg_list);
+	nl_close(sd);
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+void ni_freeifaddrs(struct ni_ifaddrs *ifa)
+{
+	free(ifa);
+}
+
diff --git a/iputils/ninfod/ni_ifaddrs.h b/iputils/ninfod/ni_ifaddrs.h
new file mode 100644
index 0000000..e164a8b
--- /dev/null
+++ b/iputils/ninfod/ni_ifaddrs.h
@@ -0,0 +1,45 @@
+/* $USAGI: ni_ifaddrs.h,v 1.1 2002-12-03 17:48:53 yoshfuji Exp $ */
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef NODEINFO_IFADDRS_H
+#define NODEINFO_IFADDRS_H
+
+struct ni_ifaddrs {
+	struct ni_ifaddrs  	*ifa_next;
+	unsigned int		ifa_ifindex;
+	unsigned short		ifa_flags;
+	void			*ifa_addr;
+	struct ifa_cacheinfo	*ifa_cacheinfo;
+};
+
+int ni_ifaddrs(struct ni_ifaddrs **ifap, sa_family_t family);
+void ni_freeifaddrs(struct ni_ifaddrs *ifa);
+
+#endif
+
diff --git a/iputils/ninfod/ninfod.c b/iputils/ninfod/ninfod.c
new file mode 100644
index 0000000..5ff6993
--- /dev/null
+++ b/iputils/ninfod/ninfod.c
@@ -0,0 +1,775 @@
+/* $USAGI: ninfod.c,v 1.34 2003-01-15 06:41:23 mk Exp $ */
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Author:
+ * 	YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if STDC_HEADERS
+# include <stdio.h>
+# include <stdlib.h>
+# include <stddef.h>
+# include <stdarg.h>
+#else
+# if HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# ifdef HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#if HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#include <sys/socket.h>
+
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#if HAVE_NETINET_ICMP6_H
+# include <netinet/icmp6.h>
+#endif
+#ifndef HAVE_STRUCT_ICMP6_NODEINFO
+# include "icmp6_nodeinfo.h"
+#endif
+
+#if HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#include <errno.h>
+
+#include <signal.h>
+
+#if HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+#if HAVE_PWD_H
+# include <pwd.h>
+#endif
+
+#if HAVE_SYS_CAPABILITY_H
+# include <sys/prctl.h>
+# include <sys/capability.h>
+#endif
+
+#include "ninfod.h"
+
+#ifndef offsetof
+# define offsetof(aggregate,member)	((size_t)&((aggregate *)0)->member)
+#endif
+
+/* --------- */
+/* ID */
+static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod.c,v 1.34 2003-01-15 06:41:23 mk Exp $";
+
+/* Variables */
+int sock;
+int daemonized;
+
+char *appname;
+static int opt_d = 0;	/* debug */
+static int opt_h = 0;	/* help */
+static char *opt_p = NINFOD_PIDFILE;	/* pidfile */
+static int got_signal = 0;	/* loop unless true */
+int opt_v = 0;		/* verbose */
+static uid_t opt_u;
+
+static int ipv6_pktinfo = IPV6_PKTINFO;
+
+/* --------- */
+#if ENABLE_DEBUG
+static const __inline__ char * log_level(int priority) {
+	switch(priority) {
+	case LOG_EMERG:		return "EMERG";
+	case LOG_ALERT:		return "ALERT";
+	case LOG_CRIT:		return "CRIT";
+	case LOG_ERR:		return "ERR";
+	case LOG_WARNING:	return "WARNING";
+	case LOG_NOTICE:	return "NOTICE";
+	case LOG_INFO:		return "INFO";
+	case LOG_DEBUG:		return "DEBUG";
+	default:		return "???";
+	}
+}
+
+void stderrlog(int pri, char *fmt, ...)
+{
+	va_list ap;
+	char ebuf[512];
+	char *buf;
+	size_t buflen;
+
+	va_start(ap, fmt);
+
+	for (buf = ebuf, buflen = sizeof(ebuf);
+	     buflen < SIZE_MAX / 2;
+	     free(buf != ebuf ? buf : NULL), buf = NULL, buflen *= 2) {
+		size_t rem;
+		size_t res;
+
+		buf = malloc(buflen);
+		if (!buf)
+			break;	/*XXX*/
+
+		rem = buflen;
+
+		res = snprintf(buf, rem, "[%s] ", log_level(pri));
+		if (res >= rem)
+			continue;
+		rem -= res;
+
+		res = vsnprintf(buf + res, rem, fmt, ap);
+
+		if (res >= rem)
+			continue;
+		break;
+	}
+
+	if (buf) {
+		fputs(buf, stderr);
+		free(buf != ebuf ? buf : NULL);
+	}
+
+	va_end(ap);
+}
+#endif
+
+/* --------- */
+static int __inline__ open_sock(void)
+{
+	return socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+}
+
+static int set_recvpktinfo(int sock)
+{
+	int on, ret;
+
+	on = 1;
+
+#if defined(IPV6_RECVPKTINFO)
+	ret = setsockopt(sock,
+			 IPPROTO_IPV6, IPV6_RECVPKTINFO,
+			 &on, sizeof(on));
+	if (!ret)
+		return 0;
+# if defined(IPV6_2292PKTINFO)
+	ret = setsockopt(sock,
+			 IPPROTO_IPV6, IPV6_2292PKTINFO,
+			 &on, sizeof(on));
+	if (!ret) {
+		ipv6_pktinfo = IPV6_2292PKTINFO;
+		return 0;
+	}
+
+	DEBUG(LOG_ERR, "setsockopt(IPV6_RECVPKTINFO/IPV6_2292PKTINFO): %s\n",
+	      strerror(errno));
+# else
+	DEBUG(LOG_ERR, "setsockopt(IPV6_RECVPKTINFO): %s\n",
+	      strerror(errno));
+# endif
+#else
+	ret = setsockopt(sock,
+			 IPPROTO_IPV6, IPV6_PKTINFO,
+			 &on, sizeof(on));
+	if (!ret)
+		return 0;
+
+	DEBUG(LOG_ERR, "setsockopt(IPV6_PKTINFO): %s\n",
+	      strerror(errno));
+#endif
+
+	return -1;
+}
+
+static int __inline__ init_sock(int sock)
+{
+	struct icmp6_filter filter;
+#if NEED_IPV6CHECKSUM
+	int i;
+
+	i = offsetof(struct icmp6_nodeinfo, ni_cksum);
+	if (setsockopt(sock,
+		       IPPROTO_IPV6, IPV6_CHECKSUM,
+		       &i, sizeof(i)) < 0) {
+		DEBUG(LOG_ERR, "setsockopt(IPV6_CHECKSUM): %s\n",
+		      strerror(errno));
+		return -1;
+	}
+#endif
+
+	ICMP6_FILTER_SETBLOCKALL(&filter);
+	ICMP6_FILTER_SETPASS(ICMP6_NI_QUERY, &filter);
+	if (setsockopt(sock,
+		       IPPROTO_ICMPV6, ICMP6_FILTER,
+		       &filter, sizeof(filter)) < 0) {
+		DEBUG(LOG_ERR, "setsockopt(ICMP6_FILTER): %s\n",
+		      strerror(errno));
+		return -1;
+	}
+
+	if (set_recvpktinfo(sock) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* --------- */
+int ni_recv(struct packetcontext *p)
+{
+	int sock = p->sock;
+	struct iovec iov[1];
+	struct msghdr msgh;
+	char recvcbuf[CMSG_SPACE(sizeof(p->pktinfo))];
+	struct cmsghdr *cmsg;
+	int cc;
+
+	DEBUG(LOG_DEBUG, "%s()\n", __func__);
+
+	memset(&iov, 0, sizeof(iov));
+	iov[0].iov_base = p->query;
+	iov[0].iov_len = sizeof(p->query);
+
+	memset(&msgh, 0, sizeof(msgh));
+	msgh.msg_name = (struct sockaddr *)&p->addr;
+	msgh.msg_namelen = sizeof(p->addr);
+	msgh.msg_iov = iov;
+	msgh.msg_iovlen = 1;
+	msgh.msg_control = recvcbuf;
+	msgh.msg_controllen = sizeof(recvcbuf);
+
+	if ((cc = recvmsg(sock, &msgh, 0)) < 0)
+		return -1;
+
+	p->querylen = cc;
+	p->addrlen = msgh.msg_namelen;
+
+	for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
+	     cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
+		if (cmsg->cmsg_level == IPPROTO_IPV6 &&
+		    (cmsg->cmsg_type == IPV6_PKTINFO
+#if defined(IPV6_2292PKTINFO)
+		     || cmsg->cmsg_type == IPV6_2292PKTINFO
+#endif
+		    )) {
+			memcpy(&p->pktinfo, CMSG_DATA(cmsg), sizeof(p->pktinfo));
+			break;
+		}
+	}
+
+	return 0;
+}
+
+int ni_send(struct packetcontext *p)
+{
+	int sock = p->sock;
+	struct iovec iov[2];
+	char cbuf[CMSG_SPACE(sizeof(p->pktinfo))];
+	struct msghdr msgh;
+	struct cmsghdr *cmsg;
+	int cc;
+
+	DEBUG(LOG_DEBUG, "%s()\n", __func__);
+
+	memset(&iov, 0, sizeof(iov));
+	iov[0].iov_base = &p->reply;
+	iov[0].iov_len = sizeof(p->reply);
+	iov[1].iov_base = p->replydata;
+	iov[1].iov_len = p->replydatalen;
+
+	memset(&msgh, 0, sizeof(msgh));
+	msgh.msg_name = (struct sockaddr *)&p->addr;
+	msgh.msg_namelen = p->addrlen;
+	msgh.msg_iov = iov;
+	msgh.msg_iovlen = p->replydata ? 2 : 1;
+
+	msgh.msg_control = cbuf;
+	msgh.msg_controllen = sizeof(cbuf);
+
+	cmsg = CMSG_FIRSTHDR(&msgh);
+	cmsg->cmsg_level = IPPROTO_IPV6;
+	cmsg->cmsg_type = ipv6_pktinfo;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(p->pktinfo));
+	memcpy(CMSG_DATA(cmsg), &p->pktinfo, sizeof(p->pktinfo));
+
+	msgh.msg_controllen = cmsg->cmsg_len;
+
+	if (p->delay) {
+#if HAVE_NANOSLEEP
+		struct timespec ts, rts;
+		int err = 0;
+
+		rts.tv_sec  = p->delay / 1000000;
+		rts.tv_nsec = (long)(p->delay % 1000000) * 1000;
+
+		do {
+			ts = rts;
+			err = nanosleep(&ts, &rts);
+		} while(err < 0);
+#else
+		usleep(p->delay);	/*XXX: signal*/
+#endif
+	}
+
+	cc = sendmsg(sock, &msgh, 0);
+	if (cc < 0)
+		DEBUG(LOG_DEBUG, "sendmsg(): %s\n", strerror(errno));
+
+	ni_free(p->replydata);
+	ni_free(p);
+
+	return cc;
+}
+
+/* --------- */
+static void sig_handler(int sig)
+{
+	if (!got_signal)
+		DEBUG(LOG_INFO, "singnal(%d) received, quitting.\n", sig);
+	got_signal = 1;
+}
+
+static void setup_sighandlers(void)
+{
+	struct sigaction act;
+	sigset_t smask;
+	sigemptyset(&smask);
+	sigaddset(&smask, SIGHUP);
+	sigaddset(&smask, SIGINT);
+	sigaddset(&smask, SIGQUIT);
+	sigaddset(&smask, SIGTERM);
+
+	memset(&act, 0, sizeof(act));
+	act.sa_handler = sig_handler;
+	act.sa_mask = smask;
+
+	sigaction(SIGHUP, &act, NULL);
+	sigaction(SIGINT, &act, NULL);
+	sigaction(SIGQUIT, &act, NULL);
+	sigaction(SIGTERM, &act, NULL);
+}
+
+static void set_logfile(void)
+{
+	setbuf(stderr, NULL);
+#if ENABLE_DEBUG
+	openlog(NINFOD, 0, LOG_USER);
+#endif
+}
+
+static void cleanup_pidfile(void)
+{
+	int err;
+
+	if (daemonized && opt_p) {
+		err = unlink(opt_p);
+		DEBUG(LOG_ERR, "failed to unlink file '%s' : %s\n",
+				opt_p, strerror(errno));
+	}
+}
+
+static FILE *fopen_excl(const char *file)
+{
+#ifndef __linux__
+	int fd;
+	FILE *fp;
+
+	fd = open(file, O_CREAT | O_RDWR | O_EXCL,
+		  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+	if (fd < 0)
+		return NULL;
+
+	return fdopen(file, "w+");
+#else
+	return fopen(file, "w+x");
+#endif
+}
+
+static void do_daemonize(void)
+{
+	FILE *fp = NULL;
+	pid_t pid;
+
+	if (opt_p) {
+		if (!access(opt_p, R_OK)) {
+			if ((fp = fopen(opt_p, "r"))) {
+				if (fscanf(fp, "%d", &pid) != 1) {
+					DEBUG(LOG_ERR, "pid file '%s' exists, but read failed.\n",
+					      opt_p);
+				} else {
+					DEBUG(LOG_ERR, "pid file '%s' exists : %d\n",
+					      opt_p, pid);
+				}
+				fclose(fp);
+				exit(1);
+			}
+		}
+
+		fp = fopen_excl(opt_p);
+		if (!fp) {
+			DEBUG(LOG_ERR, "failed to open file '%s': %s\n",
+			      opt_p, strerror(errno));
+			exit(1);
+		}
+	}
+
+	if (daemon(0, 0) < 0) {
+		DEBUG(LOG_ERR, "failed to daemon(): %s\n", strerror(errno));
+		unlink(opt_p);
+		exit(1);
+	}
+	daemonized = 1;
+
+	if (fp) {
+		fprintf(fp, "%d\n", getpid());
+		fclose(fp);
+	}
+}
+
+/* --------- */
+#ifdef HAVE_LIBCAP
+static const cap_value_t cap_net_raw = CAP_NET_RAW;
+static const cap_value_t cap_setuid =  CAP_SETUID; 
+static cap_flag_value_t cap_ok;
+#else
+static uid_t euid;
+#endif
+
+static void limit_capabilities(void)
+{
+#ifdef HAVE_LIBCAP
+	cap_t cap_p, cap_cur_p;
+
+	cap_p = cap_init();
+	if (!cap_p) {
+		DEBUG(LOG_ERR, "cap_init: %s\n", strerror(errno));
+		exit(-1);
+	}
+
+	cap_cur_p = cap_get_proc();
+	if (!cap_cur_p) {
+		DEBUG(LOG_ERR, "cap_get_proc: %s\n", strerror(errno));
+		exit(-1);
+        }
+
+	/* net_raw + setuid / net_raw */
+	cap_get_flag(cap_cur_p, CAP_NET_RAW, CAP_PERMITTED, &cap_ok);
+	if (cap_ok != CAP_CLEAR) {
+		cap_set_flag(cap_p, CAP_PERMITTED, 1, &cap_net_raw, CAP_SET);
+		cap_set_flag(cap_p, CAP_EFFECTIVE, 1, &cap_net_raw, CAP_SET);
+	}
+
+	cap_get_flag(cap_cur_p, CAP_SETUID, CAP_PERMITTED, &cap_ok);
+	if (cap_ok != CAP_CLEAR)
+		cap_set_flag(cap_p, CAP_PERMITTED, 1, &cap_setuid, CAP_SET);
+
+	if (cap_set_proc(cap_p) < 0) {
+		DEBUG(LOG_ERR, "cap_set_proc: %s\n", strerror(errno));
+		if (errno != EPERM)
+			exit(-1);
+	}
+
+	if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+		DEBUG(LOG_ERR, "prctl: %s\n", strerror(errno));
+		exit(-1);
+	}
+
+	cap_free(cap_cur_p);
+	cap_free(cap_p);
+#else
+	euid = geteuid();
+#endif
+}
+
+static void drop_capabilities(void)
+{
+#ifdef HAVE_LIBCAP
+	cap_t cap_p;
+
+	cap_p = cap_init();
+	if (!cap_p) {
+		DEBUG(LOG_ERR, "cap_init: %s\n", strerror(errno));
+		exit(-1);
+	}
+
+	/* setuid / setuid */
+	if (cap_ok != CAP_CLEAR) {
+		cap_set_flag(cap_p, CAP_PERMITTED, 1, &cap_setuid, CAP_SET);
+		cap_set_flag(cap_p, CAP_EFFECTIVE, 1, &cap_setuid, CAP_SET);
+
+		if (cap_set_proc(cap_p) < 0) {
+			DEBUG(LOG_ERR, "cap_set_proc: %s\n", strerror(errno));
+			exit(-1);
+		}
+	}
+
+	if (seteuid(opt_u ? opt_u : getuid()) < 0) {
+		DEBUG(LOG_ERR, "setuid: %s\n", strerror(errno));
+		exit(-1);
+	}
+
+	if (prctl(PR_SET_KEEPCAPS, 0) < 0) {
+		DEBUG(LOG_ERR, "prctl: %s\n", strerror(errno));
+		exit(-1);
+	}
+
+	cap_clear(cap_p);
+	if (cap_set_proc(cap_p) < 0) {
+		DEBUG(LOG_ERR, "cap_set_proc: %s\n", strerror(errno));
+		exit(-1);
+	}
+
+	cap_free(cap_p);
+#else
+	if (setuid(getuid()) < 0) {
+		DEBUG(LOG_ERR, "setuid: %s\n", strerror(errno));
+		exit(-1);
+	}
+#endif
+}
+
+/* --------- */
+static void parse_args(int argc, char **argv)
+{
+	int c;
+	unsigned long val;
+	char *ep;
+
+	/* parse options */
+	while ((c = getopt(argc, argv, "dhvp:u:")) != -1) {
+		switch(c) {
+		case 'd':	/* debug */
+			opt_d = 1;
+			break;
+		case 'v':	/* verbose */
+			opt_v = 1;
+			break;
+		case 'p':
+			opt_p = optarg;
+			break;
+		case 'u':
+			val = strtoul(optarg, &ep, 10);
+			if (!optarg || *ep) {
+				struct passwd *pw = getpwnam(optarg);
+				if (!pw) {
+					DEBUG(LOG_ERR, "No such user: %s", optarg);
+					exit(1);
+				}
+				opt_u = pw->pw_uid;
+			} else
+				opt_u = val;
+			break;
+		case 'h':	/* help */
+		default:
+			opt_h = 1;
+			break;
+		}
+	}
+
+	argc -= optind;
+#if 0
+	argv += optind;
+#endif
+
+	if (argc)
+		opt_h = 1;
+}
+
+static void print_copying(void) {
+	fprintf(stderr,
+		"Node Information Daemon\n"
+		"Copyright (C)2002 USAGI/WIDE Project.  All Rights Reserved.\n"
+		"\n"
+	);
+}
+
+static void print_usage(void) {
+	fprintf(stderr, 
+		"Usage: %s [-d] [-p pidfile] [-u user] [-h] [-v]\n\n",
+		appname
+	);
+}
+
+/* --------- */
+int main (int argc, char **argv)
+{
+	int sock_errno = 0;
+	int ret;
+
+	appname = argv[0];
+	set_logfile();
+
+	limit_capabilities();
+
+	sock = open_sock();
+	if (sock < 0)
+		sock_errno = errno;
+
+	parse_args(argc, argv);
+
+	drop_capabilities();
+
+	if (opt_h || opt_v)
+		print_copying();
+	if (opt_h) {
+		print_usage();
+		exit(1);
+	}
+
+	if (sock_errno) {
+		DEBUG(LOG_ERR, "socket: %s\n", strerror(sock_errno));
+		exit(1);
+	}
+
+	/* initialize */
+	if (init_sock(sock) < 0)
+		exit(1);
+
+	setup_sighandlers();
+	if (!opt_d)
+		do_daemonize();
+
+	init_core(1);
+
+	/* main loop */
+	while (!got_signal) {
+		struct packetcontext *p;
+		struct icmp6_hdr *icmph;
+#if ENABLE_DEBUG
+		char saddrbuf[NI_MAXHOST];
+		int gni;
+#endif 
+
+		init_core(0);
+
+		p = ni_malloc(sizeof(*p));
+		if (!p) {
+			DEBUG(LOG_WARNING, "%s(): failed to allocate packet context; sleep 1 sec.\n",
+			      __func__);
+			sleep(1);
+			continue;
+		}
+
+		while (!got_signal) {
+			memset(p, 0, sizeof(*p));
+			p->sock = sock;
+
+			if (ni_recv(p) < 0) {
+				if (got_signal)
+					break;
+				if (errno == EAGAIN || errno == EINTR)
+					continue;
+				/* XXX: syslog */
+				continue;
+			}
+			break;
+		}
+
+#if ENABLE_DEBUG
+		gni = getnameinfo((struct sockaddr *)&p->addr,
+				  p->addrlen,
+				  saddrbuf, sizeof(saddrbuf),
+				  NULL, 0,
+				  NI_NUMERICHOST);
+		if (gni)
+			sprintf(saddrbuf, "???");
+#endif
+		init_core(0);
+
+		if (p->querylen < sizeof(struct icmp6_hdr)) {
+			ni_free(p);
+			DEBUG(LOG_WARNING, "Too short icmp message from %s\n", saddrbuf);
+			continue;
+		}
+
+		icmph = (struct icmp6_hdr *)p->query;
+
+		DEBUG(LOG_DEBUG,
+		      "type=%d, code=%d, cksum=0x%04x\n",
+		      icmph->icmp6_type, icmph->icmp6_code,
+		      ntohs(icmph->icmp6_cksum));
+
+		if (icmph->icmp6_type != ICMP6_NI_QUERY) {
+			DEBUG(LOG_WARNING,
+			      "Strange icmp type %d from %s\n", 
+			      icmph->icmp6_type, saddrbuf);
+			ni_free(p);
+			continue;
+		}
+
+		pr_nodeinfo(p);	/* this frees p */
+	}
+
+	cleanup_pidfile();
+
+	exit(0);
+}
+
diff --git a/iputils/ninfod/ninfod.h b/iputils/ninfod/ninfod.h
new file mode 100644
index 0000000..feda4fa
--- /dev/null
+++ b/iputils/ninfod/ninfod.h
@@ -0,0 +1,136 @@
+/* $USAGI: ninfod.h,v 1.20 2002-12-19 15:51:16 yoshfuji Exp $ */
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Author:
+ * 	YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ */
+
+/* definitions */
+#define NINFOD			"ninfod"
+#define NINFOD_PIDFILE		"/var/run/ninfod.pid"
+
+#define	MAX_ANYCAST_DELAY_TIME	1000000.0	/* 1 sec */
+
+#define MAX_DNSLABEL_SIZE	63
+#define MAX_DNSNAME_SIZE	255
+#define MAX_QUERY_SIZE		(sizeof(struct icmp6_nodeinfo)+MAX_DNSNAME_SIZE+2)
+#define MAX_REPLY_SIZE		1280-sizeof(struct ip6_hdr)
+
+#define MAX_SUPTYPES		32
+
+#define CHECKANDFILL_ARGS	struct packetcontext *p,\
+				char *subject, size_t subjlen,	\
+				unsigned int flags,		\
+				unsigned int *subj_if,		\
+				int reply
+#define INIT_ARGS		\
+				int forced
+
+struct packetcontext {
+	/* socket */
+	int sock;
+
+	/* query info */
+	struct sockaddr_storage addr;
+	socklen_t addrlen;
+	struct in6_pktinfo pktinfo;
+	char query[MAX_QUERY_SIZE];
+	int querylen;
+
+	/* reply info */
+	struct icmp6_nodeinfo reply;	/* common */
+	char *replydata;		/* data */
+	int replydatalen;
+
+	unsigned int delay;		/* (random) delay */
+};
+
+/* variables */
+extern int opt_v;		/* ninfod.c */
+extern int daemonized;		/* ninfod.c */
+extern int sock;		/* ninfod.c */
+extern int initialized;		/* ninfod_core.c */
+
+/* ninfod.c* */
+int ni_recv(struct packetcontext *p);
+int ni_send(struct packetcontext *p);
+
+/* ninfod_core.c */
+#if ENABLE_DEBUG
+void stderrlog(int priority, char *format, ...);
+# define DEBUG(pri, fmt, args...)	do {									\
+						int saved_errno = errno;					\
+						if (opt_v || pri != LOG_DEBUG) {				\
+							if (daemonized) {					\
+								syslog(pri, fmt, ## args);			\
+							} else {						\
+								stderrlog(pri, fmt, ## args);			\
+							}							\
+						}								\
+						errno = saved_errno;						\
+					} while(0)
+#else
+# define DEBUG(pri, fmt, args...)	do { ; } while(0)
+#endif
+
+#define ni_malloc(size)	({										\
+				size_t _size = (size);							\
+				void *p = malloc(_size);						\
+				DEBUG(LOG_DEBUG, "%s(): malloc(%zu) = %p\n", __func__, _size, p);	\
+				p;									\
+			})
+#define ni_free(p)	({										\
+				void *_p = (p);								\
+				int saved_errno = errno;						\
+				DEBUG(LOG_DEBUG, "%s(): free(%p)\n", __func__, _p);			\
+				free(_p);								\
+				errno = saved_errno;							\
+			})
+
+void init_core(int forced);
+int pr_nodeinfo(struct packetcontext *p);
+
+int pr_nodeinfo_unknown(CHECKANDFILL_ARGS);
+int pr_nodeinfo_refused(CHECKANDFILL_ARGS);
+int pr_nodeinfo_noop(CHECKANDFILL_ARGS);
+void init_nodeinfo_suptypes(INIT_ARGS);
+int pr_nodeinfo_suptypes(CHECKANDFILL_ARGS);
+
+/* ninfod_addrs.c */
+void init_nodeinfo_ipv6addr(INIT_ARGS);
+int pr_nodeinfo_ipv6addr(CHECKANDFILL_ARGS);
+void init_nodeinfo_ipv4addr(INIT_ARGS);
+int pr_nodeinfo_ipv4addr(CHECKANDFILL_ARGS);
+
+/* ninfod_name.c */
+int check_nigroup(const struct in6_addr *addr);
+void init_nodeinfo_nodename(INIT_ARGS);
+int pr_nodeinfo_nodename(CHECKANDFILL_ARGS);
+
diff --git a/iputils/ninfod/ninfod.sh.in b/iputils/ninfod/ninfod.sh.in
new file mode 100644
index 0000000..4c5e6b5
--- /dev/null
+++ b/iputils/ninfod/ninfod.sh.in
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+NINFOD=@prefix@/sbin/ninfod
+PID=/var/run/ninfod.pid
+
+if ! [ -x $NINFOD ]; then
+	exit 0
+fi
+
+case "$1" in
+    start)
+	echo -n "Starting node infomation daemon:"
+	echo -n " ninfod" ; 
+	$NINFOD 
+	echo "."
+	;;
+    stop)
+	echo -n "Stopping node infomation daemon:"
+	echo -n " ninfod" ; 
+	kill `cat $PID`
+	echo "."
+	;;
+    restart)
+	echo -n "Restarting node information daemon:"
+	echo -n " ninfod"
+	kill `cat $PID`
+	$NINFOD
+	echo "."
+	;;
+    *)
+	echo "Usage: /etc/init.d/ninfod {start|stop|restart}"
+	exit 1
+	;;
+esac
+
+exit 0
+
diff --git a/iputils/ninfod/ninfod_addrs.c b/iputils/ninfod/ninfod_addrs.c
new file mode 100644
index 0000000..448121f
--- /dev/null
+++ b/iputils/ninfod/ninfod_addrs.c
@@ -0,0 +1,469 @@
+/* $USAGI: ninfod_addrs.c,v 1.18 2003-07-16 09:49:01 yoshfuji Exp $ */
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Author:
+ * 	YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#if STDC_HEADERS
+# include <stdio.h>
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if TIME_WITH_SYS_TIME   
+# include <sys/time.h>  
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H     
+#  include <sys/time.h>
+# else                
+#  include <time.h>
+# endif                  
+#endif                   
+
+#if HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#include <sys/socket.h>
+#if HAVE_LINUX_RTNETLINK_H
+#include <asm/types.h>
+#include <linux/rtnetlink.h>
+#endif
+
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#if HAVE_NETINET_IP6_H
+# include <netinet/ip6.h>
+#endif
+
+#if HAVE_NETINET_ICMP6_H
+# include <netinet/icmp6.h>
+#endif
+#ifndef HAVE_STRUCT_ICMP6_NODEINFO
+# include "icmp6_nodeinfo.h"
+#endif
+
+#if HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#include <errno.h>
+
+#if HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+#include "ninfod.h"
+#include "ni_ifaddrs.h"
+
+#ifndef offsetof
+# define offsetof(aggregate,member)	((size_t)&((aggregate *)0)->member)
+#endif
+
+/* ---------- */
+/* ID */
+static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod_addrs.c,v 1.18 2003-07-16 09:49:01 yoshfuji Exp $";
+
+/* ---------- */
+/* ipv6 address */
+void init_nodeinfo_ipv6addr(INIT_ARGS)
+{
+	DEBUG(LOG_DEBUG, "%s()\n", __func__);
+	return;
+}
+
+int filter_ipv6addr(const struct in6_addr *ifaddr, unsigned int flags)
+{
+	if (IN6_IS_ADDR_UNSPECIFIED(ifaddr) ||
+	    IN6_IS_ADDR_LOOPBACK(ifaddr)) {
+		return 1;
+	} else if (IN6_IS_ADDR_V4COMPAT(ifaddr) ||
+		   IN6_IS_ADDR_V4MAPPED(ifaddr)) {
+		return !(flags & NI_NODEADDR_FLAG_COMPAT);
+	} else if (IN6_IS_ADDR_LINKLOCAL(ifaddr)) {
+		return !(flags & NI_NODEADDR_FLAG_LINKLOCAL);
+	} else if (IN6_IS_ADDR_SITELOCAL(ifaddr)) {
+		return !(flags & NI_NODEADDR_FLAG_SITELOCAL);
+	}
+	return !(flags & NI_NODEADDR_FLAG_GLOBAL);
+}
+
+int pr_nodeinfo_ipv6addr(CHECKANDFILL_ARGS)
+{
+	struct ni_ifaddrs *ifa0;
+	unsigned int ifindex = 0;
+
+	DEBUG(LOG_DEBUG, "%s()\n", __func__);
+
+	if (subject && subjlen != sizeof(struct in6_addr)) {
+		DEBUG(LOG_INFO,
+		      "%s(): invalid subject length %zu for IPv6 Address Subject\n",
+		      __func__, subjlen);
+		return 1;
+	}
+	if (ni_ifaddrs(&ifa0, AF_INET6))
+		return -1;	/* failed to get addresses */
+
+	/* pass 0: consider subject and determine subjected interface */
+	if (subject) {
+		struct ni_ifaddrs *ifa;
+
+		for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
+			if (!ifa->ifa_addr)
+				continue;
+			if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
+				continue;
+			if (!ifindex && 
+			    IN6_ARE_ADDR_EQUAL(&p->pktinfo.ipi6_addr,
+					       (struct in6_addr *)subject)) {
+				/*
+				 * if subject is equal to destination
+				 * address, receiving interface is
+				 * the candidate subject interface.
+				 */
+				ifindex = p->pktinfo.ipi6_ifindex;
+			}
+			if (!IN6_IS_ADDR_LOOPBACK((struct in6_addr *)subject) &&
+			    IN6_ARE_ADDR_EQUAL((struct in6_addr *)ifa->ifa_addr,
+					       (struct in6_addr *)subject)) {
+				/*
+				 * address is assigned on some interface.
+				 * if multiple interfaces have the same interface,
+				 *  1) prefer receiving interface
+				 *  2) use first found one
+				 */
+				if (!ifindex ||
+				    (p->pktinfo.ipi6_ifindex == ifindex))
+					ifindex = ifa->ifa_ifindex;
+			}
+		}
+		if (!ifindex) {
+			ni_freeifaddrs(ifa0);
+			return 1;	/* subject not found */
+		}
+		if (subj_if)
+			*subj_if = ifindex;
+	} else {
+		ifindex = subj_if ? *subj_if : 0;
+		if (ifindex == 0)
+			ifindex = p->pktinfo.ipi6_ifindex;
+		if (ifindex == 0) {
+			ni_freeifaddrs(ifa0);
+			return 1;	/* XXX */
+		}
+	}
+
+	if (reply) {
+		struct ni_ifaddrs *ifa;
+		unsigned int addrs0 = 0, paddrs0 = 0;
+		unsigned int addrs, paddrs = 0, daddrs = 0;
+
+		flags &= ~NI_NODEADDR_FLAG_TRUNCATE;	
+	
+		/* pass 1: count addresses and preferred addresses to be returned */
+		for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
+			if (!ifa->ifa_addr)
+				continue;
+			if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
+				continue;
+			if (!(flags & NI_NODEADDR_FLAG_ALL) &&
+			    ifa->ifa_ifindex != ifindex)
+				continue;
+			if (filter_ipv6addr((struct in6_addr *)ifa->ifa_addr, flags))
+				continue;
+
+			if (addrs0 + 1 >= ((MAX_REPLY_SIZE - sizeof(struct icmp6_nodeinfo)) / (sizeof(uint32_t) + sizeof(struct in6_addr)))) {
+				flags |= ~NI_NODEADDR_FLAG_TRUNCATE;
+				break;
+			}
+
+			addrs0++;
+			if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
+				paddrs0++;
+		}
+		
+		p->reply.ni_type = ICMP6_NI_REPLY;
+		p->reply.ni_code = ICMP6_NI_SUCCESS;
+		p->reply.ni_cksum = 0;
+		p->reply.ni_qtype = htons(NI_QTYPE_NODEADDR);
+		p->reply.ni_flags = flags&(NI_NODEADDR_FLAG_COMPAT|
+					   NI_NODEADDR_FLAG_LINKLOCAL|
+					   NI_NODEADDR_FLAG_SITELOCAL|
+					   NI_NODEADDR_FLAG_GLOBAL);
+
+		/* pass 2: store addresses */
+		p->replydatalen = (sizeof(uint32_t)+sizeof(struct in6_addr)) * addrs0;
+		p->replydata = p->replydatalen ? ni_malloc(p->replydatalen) : NULL;
+
+		if (p->replydatalen && !p->replydata) {
+			p->reply.ni_flags |= NI_NODEADDR_FLAG_TRUNCATE;
+			addrs0 = paddrs0 = 0;
+		}
+
+		for (ifa = ifa0, addrs = 0; 
+		     ifa && addrs < addrs0; 
+		     ifa = ifa->ifa_next) {
+			char *cp;
+			uint32_t ttl;
+
+			if (!ifa->ifa_addr)
+				continue;
+			if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
+				continue;
+			if (!(flags & NI_NODEADDR_FLAG_ALL) &&
+			    ((subj_if && *subj_if) ? (ifa->ifa_ifindex != *subj_if) :
+						     (ifa->ifa_ifindex != p->pktinfo.ipi6_ifindex)))
+				continue;
+			if (filter_ipv6addr((struct in6_addr *)ifa->ifa_addr, flags))
+				continue;
+
+#if ENABLE_TTL
+			if (ifa->ifa_cacheinfo) {
+				ttl = ifa->ifa_cacheinfo->ifa_valid > 0x7fffffff ? 
+				      htonl(0x7fffffff) : htonl(ifa->ifa_cacheinfo->ifa_valid);
+			} else {
+				ttl = (ifa->ifa_flags & IFA_F_PERMANENT) ? htonl(0x7fffffff) : 0;
+			}
+#else
+			ttl = 0;
+#endif
+
+			cp = p->replydata +
+			     (sizeof(uint32_t)+sizeof(struct in6_addr)) * (ifa->ifa_flags & IFA_F_DEPRECATED ? paddrs0+daddrs : paddrs);
+			memcpy(cp, &ttl, sizeof(ttl));
+			memcpy(cp + sizeof(ttl), ifa->ifa_addr, sizeof(struct in6_addr));
+
+			addrs++;
+			if (ifa->ifa_flags & IFA_F_DEPRECATED)
+				daddrs++;
+			else
+				paddrs++;
+		}
+	}
+
+	ni_freeifaddrs(ifa0);
+	return 0;
+}
+
+/* ipv4 address */
+void init_nodeinfo_ipv4addr(INIT_ARGS)
+{
+	DEBUG(LOG_DEBUG, "%s()\n", __func__);
+	return;
+}
+
+int filter_ipv4addr(const struct in_addr *ifaddr, unsigned int flags)
+{
+	return 0;
+}
+
+int pr_nodeinfo_ipv4addr(CHECKANDFILL_ARGS)
+{
+	struct ni_ifaddrs *ifa0;
+	unsigned int ifindex = 0;
+
+	DEBUG(LOG_DEBUG, "%s()\n", __func__);
+
+	if (subject && subjlen != sizeof(struct in_addr)) {
+		DEBUG(LOG_INFO,
+		      "%s(): invalid subject length %zu for IPv4 Address Subject\n",
+		      __func__, subjlen);
+		return 1;
+	}
+	if (ni_ifaddrs(&ifa0, AF_INET))
+		return -1;	/* failed to get addresses */
+
+	/* pass 0: consider subject and determine subjected interface */
+	if (subject) {
+		struct ni_ifaddrs *ifa;
+
+		for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
+			if (!ifa->ifa_addr)
+				continue;
+			if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
+				continue;
+			if ((((struct in_addr *)subject)->s_addr != htonl(INADDR_LOOPBACK)) &&
+			    memcmp((struct in_addr *)ifa->ifa_addr,
+				   (struct in_addr *)subject,
+				   sizeof(struct in_addr)) == 0) {
+				/*
+				 * address is assigned on some interface.
+				 * if multiple interfaces have the same interface,
+				 *  1) prefer receiving interface
+				 *  2) use first found one
+				 */
+				if (!ifindex ||
+				    (p->pktinfo.ipi6_ifindex == ifindex))
+					ifindex = ifa->ifa_ifindex;
+			}
+		}
+		if (!ifindex) {
+			ni_freeifaddrs(ifa0);
+			return 1;	/* subject not found */
+		}
+		if (subj_if)
+			*subj_if = ifindex;
+	} else {
+		ifindex = subj_if ? *subj_if : 0;
+		if (ifindex == 0)
+			ifindex = p->pktinfo.ipi6_ifindex;
+		if (ifindex == 0) {
+			ni_freeifaddrs(ifa0);
+			return 1;	/* XXX */
+		}
+	}
+
+	if (reply) {
+		struct ni_ifaddrs *ifa;
+		unsigned int addrs0 = 0, paddrs0 = 0;
+		unsigned int addrs, paddrs = 0, daddrs = 0;
+
+		flags &= ~NI_IPV4ADDR_FLAG_TRUNCATE;
+
+		/* pass 1: count addresses and preferred addresses to be returned */
+		for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
+			if (!ifa->ifa_addr)
+				continue;
+#if 1	/* not used in kernel */
+			if (ifa->ifa_flags & (IFA_F_TENTATIVE))
+				continue;
+#endif
+			if (!(flags & NI_NODEADDR_FLAG_ALL) &&
+			    ((subj_if && *subj_if) ? (ifa->ifa_ifindex != *subj_if) :
+						     (ifa->ifa_ifindex != p->pktinfo.ipi6_ifindex)))
+				continue;
+			if (filter_ipv4addr((struct in_addr *)ifa->ifa_addr, flags))
+				continue;
+
+			if (addrs0 + 1 >= ((MAX_REPLY_SIZE - sizeof(struct icmp6_nodeinfo)) / (sizeof(uint32_t) + sizeof(struct in_addr)))) {
+				flags |= NI_IPV4ADDR_FLAG_TRUNCATE;
+				break;
+			}
+
+			addrs0++;
+			if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
+				paddrs0++;
+		}
+
+		p->reply.ni_type = ICMP6_NI_REPLY;
+		p->reply.ni_code = ICMP6_NI_SUCCESS;
+		p->reply.ni_cksum = 0;
+		p->reply.ni_qtype = htons(NI_QTYPE_IPV4ADDR);
+		p->reply.ni_flags = flags & NI_IPV4ADDR_FLAG_ALL;
+
+		/* pass 2: store addresses */
+		p->replydatalen = (sizeof(uint32_t)+sizeof(struct in_addr)) * addrs0;
+		p->replydata = addrs0 ? ni_malloc(p->replydatalen) : NULL;
+
+		if (p->replydatalen && !p->replydata) {
+			p->reply.ni_flags |= NI_NODEADDR_FLAG_TRUNCATE;
+			addrs0 = paddrs0 = 0;
+		}
+
+		for (ifa = ifa0, addrs = 0; 
+		     ifa && addrs < addrs0; 
+		     ifa = ifa->ifa_next) {
+			char *cp;
+			uint32_t ttl;
+
+			if (!ifa->ifa_addr)
+				continue;
+#if 1	/* not used in kernel */
+			if (ifa->ifa_flags & (IFA_F_TENTATIVE))
+				continue;
+#endif
+			if (!(flags & NI_NODEADDR_FLAG_ALL) &&
+			    (ifa->ifa_ifindex != ifindex))
+				continue;
+			if (filter_ipv4addr((struct in_addr *)ifa->ifa_addr, flags))
+				continue;	
+
+#if ENABLE_TTL
+			if (ifa->ifa_cacheinfo) {
+				ttl = ifa->ifa_cacheinfo->ifa_valid > 0x7fffffff ? 
+				      htonl(0x7fffffff) : htonl(ifa->ifa_cacheinfo->ifa_valid);
+			} else {
+				ttl = 0;	/*XXX*/
+			}
+#else
+			ttl = 0;
+#endif
+
+			cp = (p->replydata +
+			      (sizeof(uint32_t)+sizeof(struct in_addr)) * (ifa->ifa_flags & IFA_F_DEPRECATED ? paddrs0+daddrs : paddrs));
+			memcpy(cp, &ttl, sizeof(ttl));
+			memcpy(cp + sizeof(ttl), ifa->ifa_addr, sizeof(struct in_addr));
+
+			addrs++;
+			if (ifa->ifa_flags & IFA_F_DEPRECATED)
+				daddrs++;
+			else
+				paddrs++;
+		}
+	}
+
+	ni_freeifaddrs(ifa0);
+	return 0;
+}
+
diff --git a/iputils/ninfod/ninfod_core.c b/iputils/ninfod/ninfod_core.c
new file mode 100644
index 0000000..389f5c0
--- /dev/null
+++ b/iputils/ninfod/ninfod_core.c
@@ -0,0 +1,698 @@
+/* $USAGI: ninfod_core.c,v 1.29 2003-07-16 09:49:01 yoshfuji Exp $ */
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Author:
+ * 	YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if STDC_HEADERS
+# include <stdio.h>
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#if ENABLE_THREADS && HAVE_PTHREAD_H
+# include <pthread.h>
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if TIME_WITH_SYS_TIME   
+# include <sys/time.h>  
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H     
+#  include <sys/time.h>
+# else                
+#  include <time.h>
+# endif                  
+#endif                   
+
+#if HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#if HAVE_NETINET_ICMP6_H
+# include <netinet/icmp6.h>
+#endif
+#ifndef HAVE_STRUCT_ICMP6_NODEINFO
+# include "icmp6_nodeinfo.h"
+#endif
+
+#if HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#include <errno.h>
+
+#if HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+#include "ninfod.h"
+
+#ifndef offsetof
+# define offsetof(aggregate,member)	((size_t)&((aggregate *)0)->member)
+#endif
+
+#define ARRAY_SIZE(a)		(sizeof(a) / sizeof(a[0]))
+
+/* ---------- */
+/* ID */
+static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod_core.c,v 1.29 2003-07-16 09:49:01 yoshfuji Exp $";
+
+/* Variables */
+int initialized = 0;
+
+#if ENABLE_THREADS && HAVE_LIBPTHREAD
+pthread_attr_t pattr;
+#endif
+
+static uint32_t suptypes[(MAX_SUPTYPES+31)>>5];
+static size_t suptypes_len;
+
+/* ---------- */
+struct subjinfo {
+	uint8_t	code;
+	char	*name;
+	int	(*checksubj)(CHECKANDFILL_ARGS);
+	int	(*init)(INIT_ARGS);
+};
+
+static struct subjinfo subjinfo_table [] = {
+	[ICMP6_NI_SUBJ_IPV6] = {
+		.code = ICMP6_NI_SUBJ_IPV6,
+		.name = "IPv6",
+		//.init = init_nodeinfo_ipv6addr,
+		.checksubj = pr_nodeinfo_ipv6addr,
+	},
+	[ICMP6_NI_SUBJ_FQDN] = {
+		.code = ICMP6_NI_SUBJ_FQDN,
+		.name = "FQDN",
+		//.init = init_nodeinfo_nodename,
+		.checksubj = pr_nodeinfo_nodename,
+	},
+	[ICMP6_NI_SUBJ_IPV4] = {
+		.code = ICMP6_NI_SUBJ_IPV4,
+		.name = "IPv4",
+		//.init = init_nodeinfo_ipv4addr,
+		.checksubj = pr_nodeinfo_ipv4addr,
+	},
+};
+
+static struct subjinfo subjinfo_null = {
+	.name = "null",
+	.checksubj = pr_nodeinfo_noop,
+};
+
+static __inline__ struct subjinfo *subjinfo_lookup(int code)
+{
+	if (code >= ARRAY_SIZE(subjinfo_table))
+		return NULL;
+	if (subjinfo_table[code].name == NULL)
+		return NULL;
+	return &subjinfo_table[code];
+}
+
+/* ---------- */
+#define QTYPEINFO_F_RATELIMIT	0x1
+
+struct qtypeinfo {
+	uint16_t qtype;
+	char	*name;
+	int	(*getreply)(CHECKANDFILL_ARGS);
+	void	(*init)(INIT_ARGS);
+	int	flags;
+};
+
+static struct qtypeinfo qtypeinfo_table[] = {
+	[NI_QTYPE_NOOP]		= {
+		.qtype = NI_QTYPE_NOOP,
+		.name = "NOOP",
+		.getreply = pr_nodeinfo_noop,
+	},
+#if ENABLE_SUPTYPES
+	[NI_QTYPE_SUPTYPES]	= {
+		.qtype = NI_QTYPE_SUPTYPES,
+		.name = "SupTypes",
+		.getreply = pr_nodeinfo_suptypes,
+		.init = init_nodeinfo_suptypes,
+	},
+#endif
+	[NI_QTYPE_DNSNAME]	= {
+		.qtype = NI_QTYPE_DNSNAME,
+		.name = "DnsName",
+		.getreply = pr_nodeinfo_nodename,
+		.init = init_nodeinfo_nodename,
+	},
+	[NI_QTYPE_NODEADDR]	= {
+		.qtype = NI_QTYPE_NODEADDR,
+		.name = "NodeAddr",
+		.getreply = pr_nodeinfo_ipv6addr,
+		.init = init_nodeinfo_ipv6addr,
+	},
+	[NI_QTYPE_IPV4ADDR]	= {
+		.qtype = NI_QTYPE_IPV4ADDR,
+		.name = "IPv4Addr",
+		.getreply = pr_nodeinfo_ipv4addr,
+		.init = init_nodeinfo_ipv4addr,
+	},
+};
+
+static struct qtypeinfo qtypeinfo_unknown = {
+	.name = "unknown",
+	.getreply = pr_nodeinfo_unknown,
+	.flags = QTYPEINFO_F_RATELIMIT,
+};
+
+static struct qtypeinfo qtypeinfo_refused = {
+	.name = "refused",
+	.getreply = pr_nodeinfo_refused,
+	.flags = QTYPEINFO_F_RATELIMIT,
+};
+
+static __inline__ struct qtypeinfo *qtypeinfo_lookup(int qtype)
+{
+	if (qtype >= ARRAY_SIZE(qtypeinfo_table))
+		return &qtypeinfo_unknown;
+	if (qtypeinfo_table[qtype].name == NULL)
+		return &qtypeinfo_unknown;
+	return &qtypeinfo_table[qtype];
+}
+
+/* ---------- */
+/* noop */
+int pr_nodeinfo_noop(CHECKANDFILL_ARGS)
+{
+	DEBUG(LOG_DEBUG, "%s()\n", __func__);
+
+	if (subjlen) {
+		DEBUG(LOG_WARNING,
+		      "%s(): invalid subject length(%zu)\n",
+		      __func__, subjlen);
+		return 1;
+	}
+
+	if (reply) {
+		p->reply.ni_type = ICMP6_NI_REPLY;
+		p->reply.ni_code = ICMP6_NI_SUCCESS;
+		p->reply.ni_cksum = 0;
+		p->reply.ni_qtype = htons(NI_QTYPE_NOOP);
+		p->reply.ni_flags = flags;
+	}
+
+	if (subj_if)
+		*subj_if = 0;
+
+	return 0;
+}
+
+#if ENABLE_SUPTYPES
+/* suptypes */
+int pr_nodeinfo_suptypes(CHECKANDFILL_ARGS)
+{
+	DEBUG(LOG_DEBUG, "%s()\n", __func__);
+
+	if (subjlen) {
+		DEBUG(LOG_WARNING, "%s(): invalid subject length(%zu)\n",
+		      __func__, subjlen);
+		return 1;
+	}
+
+	if (reply) {
+		p->reply.ni_type = ICMP6_NI_REPLY;
+		p->reply.ni_code = ICMP6_NI_SUCCESS;
+		p->reply.ni_cksum = 0;
+		p->reply.ni_qtype = htons(NI_QTYPE_SUPTYPES);
+		p->reply.ni_flags = flags&~NI_SUPTYPE_FLAG_COMPRESS;
+		
+		p->replydatalen = suptypes_len<<2;
+		p->replydata = ni_malloc(p->replydatalen);
+		if (p->replydata == NULL) {
+			p->replydatalen = -1;
+			return -1;	/*XXX*/
+		}
+
+		memcpy(p->replydata, suptypes, p->replydatalen);
+	}
+	return 0;
+}
+
+void init_nodeinfo_suptypes(INIT_ARGS)
+{
+	size_t w, b;
+	int i;
+
+	if (!forced && initialized)
+		return;
+
+	memset(suptypes, 0, sizeof(suptypes));
+	suptypes_len = 0;
+
+	for (i=0; i < ARRAY_SIZE(qtypeinfo_table); i++) {
+		unsigned short qtype;
+
+		if (qtypeinfo_table[i].name == NULL)
+			continue;
+		qtype = qtypeinfo_table[i].qtype;
+		w = qtype>>5;
+		b = qtype&0x1f;
+		if (w >= ARRAY_SIZE(suptypes)) {
+			/* This is programming error. */
+			DEBUG(LOG_ERR, "Warning: Too Large Supported Types\n");
+			exit(1);
+		}
+		suptypes[w] |= htonl(1<<b);
+
+		if (suptypes_len < w)
+			suptypes_len = w;
+	}
+	suptypes_len++;
+}
+#endif
+
+/* ---------- */
+/* unknown qtype response */
+int pr_nodeinfo_unknown(CHECKANDFILL_ARGS)
+{
+	if (!reply)
+		return -1;	/*???*/
+
+	p->reply.ni_type = ICMP6_NI_REPLY;
+	p->reply.ni_code = ICMP6_NI_UNKNOWN;
+	p->reply.ni_cksum = 0;
+	//p->reply.ni_qtype = 0;
+	p->reply.ni_flags = flags;
+
+	p->replydata = NULL;
+	p->replydatalen = 0;
+
+	return 0;
+}
+
+/* refused response */
+int pr_nodeinfo_refused(CHECKANDFILL_ARGS)
+{
+	if (!reply)
+		return -1;	/*???*/
+
+	p->reply.ni_type = ICMP6_NI_REPLY;
+	p->reply.ni_code = ICMP6_NI_REFUSED;
+	p->reply.ni_cksum = 0;
+	//p->reply.ni_qtype = 0;
+	p->reply.ni_flags = flags;
+
+	p->replydata = NULL;
+	p->replydatalen = 0;
+
+	return 0;
+}
+
+/* ---------- */
+/* Policy */
+static int ni_policy(struct packetcontext *p)
+{
+	const struct in6_addr *saddr = &((const struct sockaddr_in6 *)&p->addr)->sin6_addr;
+
+	/*
+	 * >0: reply
+	 *  0: refused
+	 * <0: discard
+	 */
+
+	/* Default policy is to refuse queries from
+	 * non-local addresses; loopback, link-local or
+	 * site-local are okay
+	 */
+	if (!(IN6_IS_ADDR_LINKLOCAL(saddr) ||
+	      IN6_IS_ADDR_SITELOCAL(saddr) ||
+	      IN6_IS_ADDR_LOOPBACK(saddr)))
+		return 0;
+	return 1;
+}
+
+/* ---------- */
+void init_core(int forced)
+{
+	int i;
+
+	DEBUG(LOG_DEBUG, "%s()\n", __func__);
+
+	if (!initialized || forced) {
+		struct timeval tv;
+		unsigned int seed = 0;
+		pid_t pid;
+
+		if (gettimeofday(&tv, NULL) < 0) {
+			DEBUG(LOG_WARNING, "%s(): failed to gettimeofday()\n", __func__);
+		} else {
+			seed = (tv.tv_usec & 0xffffffff);
+		}
+
+		pid = getpid();
+		seed ^= (((unsigned long)pid) & 0xffffffff);
+
+		srand(seed);
+
+#if ENABLE_THREADS && HAVE_LIBPTHREAD
+		if (initialized)
+			pthread_attr_destroy(&pattr);
+
+		pthread_attr_init(&pattr);
+		pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED);
+#endif
+	}
+
+	for (i=0; i < ARRAY_SIZE(subjinfo_table); i++) {
+		if (subjinfo_table[i].name == NULL)
+			continue;
+		if (subjinfo_table[i].init)
+			subjinfo_table[i].init(forced);
+	}
+
+	for (i=0; i < ARRAY_SIZE(qtypeinfo_table); i++) {
+		if (qtypeinfo_table[i].name == NULL)
+			continue;
+		if (qtypeinfo_table[i].init)
+			qtypeinfo_table[i].init(forced);
+	}
+
+	initialized = 1;
+
+	return;
+}
+
+#if ENABLE_THREADS && HAVE_LIBPTHREAD
+static void *ni_send_thread(void *data)
+{
+	int ret;
+	DEBUG(LOG_DEBUG, "%s(): thread=%ld\n", __func__, pthread_self());
+	ret = ni_send(data);
+	DEBUG(LOG_DEBUG, "%s(): thread=%ld => %d\n", __func__, pthread_self(), ret);
+	return NULL;
+}
+#else
+static int ni_send_fork(struct packetcontext *p)
+{
+	pid_t child = fork();
+	if (child < 0)
+		return -1;
+	if (child == 0) {
+		pid_t grandchild = fork();
+		if (grandchild < 0)
+			exit(1);
+		if (grandchild == 0) {
+			int ret;
+			DEBUG(LOG_DEBUG, "%s(): worker=%d\n",
+			      __func__, getpid());
+			ret = ni_send(p);
+			DEBUG(LOG_DEBUG, "%s(): worker=%d => %d\n",
+			      __func__, getpid(), ret);
+			exit(ret > 0 ? 1 : 0);
+		}
+		ni_free(p->replydata);
+		ni_free(p);
+		exit(0);
+	} else {
+		waitpid(child, NULL, 0);
+		ni_free(p->replydata);
+		ni_free(p);
+	}
+	return 0;
+}
+#endif
+
+static int ni_ratelimit(void)
+{
+	static struct timeval last;
+	struct timeval tv, sub;
+
+	if (gettimeofday(&tv, NULL) < 0) {
+		DEBUG(LOG_WARNING, "%s(): gettimeofday(): %s\n",
+		      __func__, strerror(errno));
+		return -1;
+	}
+
+	if (!timerisset(&last)) {
+		last = tv;
+		return 0;
+	}
+
+	timersub(&tv, &last, &sub);
+
+	if (sub.tv_sec < 1)
+		return 1;
+
+	last = tv;
+	return 0;
+}
+
+int pr_nodeinfo(struct packetcontext *p)
+{
+	struct icmp6_nodeinfo *query = (struct icmp6_nodeinfo *)p->query;
+
+	char *subject = (char *)(query + 1);
+	size_t subjlen;
+	struct subjinfo *subjinfo;
+	struct qtypeinfo *qtypeinfo;
+	int replyonsubjcheck = 0;
+	unsigned int subj_if;
+#if ENABLE_DEBUG
+	char printbuf[128];
+	int i;
+	char *cp;
+#endif
+#if ENABLE_THREADS && HAVE_PTHREAD_H
+	pthread_t thread;
+#endif
+	int rc;
+
+	/* Step 0: Check destination address
+	 *		discard non-linklocal multicast
+	 *		discard non-nigroup multicast address(?)
+	 */
+	if (IN6_IS_ADDR_MULTICAST(&p->pktinfo.ipi6_addr)) {
+		if (!IN6_IS_ADDR_MC_LINKLOCAL(&p->pktinfo.ipi6_addr)) {
+			DEBUG(LOG_WARNING,
+			      "Destination is non-link-local multicast address.\n");
+			ni_free(p);
+			return -1;
+		}
+#if 0
+		/* Do not discard NI Queries to multicast address
+		 * other than its own NI Group Address(es) by default.
+		 */
+		if (!check_nigroup(&p->pktinfo.ipi6_addr)) {
+			DEBUG(LOG_WARNING,
+			      "Destination is link-local multicast address other than "
+			      "NI Group address.\n");
+			ni_free(p);
+			return -1;
+		}
+#endif
+	}
+
+	/* Step 1: Check length */
+	if (p->querylen < sizeof(struct icmp6_nodeinfo)) {
+		DEBUG(LOG_WARNING, "Query too short\n");
+		ni_free(p);
+		return -1;
+	}
+
+#if ENABLE_DEBUG
+	cp = printbuf;
+	for (i = 0; i < sizeof(query->icmp6_ni_nonce); i++) {
+		cp += sprintf(cp, " %02x", query->icmp6_ni_nonce[i]);
+	}
+	DEBUG(LOG_DEBUG, "%s(): qtype=%d, flags=0x%04x, nonce[] = {%s }\n",
+	      __func__,
+	      ntohs(query->ni_qtype), ntohs(query->ni_flags), printbuf);
+#endif
+
+	subjlen = p->querylen - sizeof(struct icmp6_nodeinfo);
+
+	/* Step 2: Check Subject Code */
+	switch(htons(query->ni_qtype)) {
+	case NI_QTYPE_NOOP:
+	case NI_QTYPE_SUPTYPES:
+		if (query->ni_code != ICMP6_NI_SUBJ_FQDN) {
+			DEBUG(LOG_WARNING,
+			      "%s(): invalid/unknown code %u\n",
+			      __func__, query->ni_code);
+			subjlen = 0;
+		}
+		subjinfo = &subjinfo_null;
+		break;
+	default:
+		subjinfo = subjinfo_lookup(query->ni_code);
+		if (!subjinfo) {
+			DEBUG(LOG_WARNING,
+			      "%s(): unknown code %u\n",
+			      __func__, query->ni_code);
+			ni_free(p);
+			return -1;
+		}
+	}
+
+	/* Step 3: Lookup Qtype */
+	qtypeinfo = qtypeinfo_lookup(ntohs(query->ni_qtype));
+
+	/* Step 4: Check Subject
+	 *         (And fill reply if it is available now)
+	 */
+	if (qtypeinfo->getreply == subjinfo->checksubj)
+		replyonsubjcheck = 1;
+
+	if (subjinfo->checksubj(p,
+				subject, subjlen,
+				query->ni_flags,
+				replyonsubjcheck ? NULL : &subj_if,
+				replyonsubjcheck)) {
+		if (p->replydatalen < 0) {
+			DEBUG(LOG_WARNING,
+			      "failed to make reply: %s\n",
+			      strerror(errno));
+		}
+		ni_free(p);
+		return -1;
+	}
+
+	/* XXX: Step 5: Check the policy */
+	rc = ni_policy(p);
+	if (rc <= 0) {
+		ni_free(p->replydata);
+		p->replydata = NULL;
+		p->replydatalen = 0;
+		if (rc < 0) {
+			DEBUG(LOG_WARNING, "Ignored by policy.\n");
+			ni_free(p);
+			return -1;
+		}
+		DEBUG(LOG_WARNING, "Refused by policy.\n");
+		replyonsubjcheck = 0;
+		qtypeinfo = &qtypeinfo_refused;
+	}
+
+	/* Step 6: Fill the reply if not yet done */
+	if (!replyonsubjcheck) {
+		if (qtypeinfo->getreply(p,
+					NULL, 0,
+					query->ni_flags,
+					&subj_if,
+					1)) {
+			if (p->replydatalen) {
+				DEBUG(LOG_WARNING,
+				      "failed to make reply: %s\n",
+				      strerror(errno));
+			}
+			ni_free(p);
+			return -1;
+		}
+	}
+
+	/* Step 7: Rate Limit */
+	if (qtypeinfo->flags&QTYPEINFO_F_RATELIMIT &&
+	    ni_ratelimit()) {
+		ni_free(p->replydata);
+		ni_free(p);
+		return -1;
+	}
+
+	/* Step 8: Fill Qtype / Nonce */
+	p->reply.ni_qtype = query->ni_qtype;
+	memcpy(p->reply.icmp6_ni_nonce, query->icmp6_ni_nonce, sizeof(p->reply.icmp6_ni_nonce));
+
+	/* Step 9: Source address selection */
+	if (IN6_IS_ADDR_MULTICAST(&p->pktinfo.ipi6_addr)) {
+		/* if query was sent to multicast address,
+		 * use source address selection in kernel.
+		 * XXX: anycast?
+		 */
+		memset(&p->pktinfo.ipi6_addr, 0, sizeof(p->pktinfo.ipi6_addr));
+
+	 	/* Random Delay between zero and MAX_ANYCAST_DELAY_TIME is
+		 * required if query was sent to anycast or multicast address.
+		 */
+		p->delay = (int) (MAX_ANYCAST_DELAY_TIME*rand()/(RAND_MAX+1.0));
+	} else {
+		p->delay = 0;
+	}
+
+	/* Step 10: Send the reply
+	 * XXX: with possible random delay */
+#if ENABLE_THREADS && HAVE_LIBPTHREAD
+	/* ni_send_thread() frees p */
+	if (pthread_create(&thread, &pattr, ni_send_thread, p)) {
+		ni_free(p->replydata);
+		ni_free(p);
+		return -1;
+	}
+#else
+	/* ni_send_fork() frees p */
+	if (ni_send_fork(p)) {
+		ni_free(p->replydata);
+		ni_free(p);
+		return -1;
+	}
+#endif
+
+	return 0;
+}
+
diff --git a/iputils/ninfod/ninfod_name.c b/iputils/ninfod/ninfod_name.c
new file mode 100644
index 0000000..6d7e92b
--- /dev/null
+++ b/iputils/ninfod/ninfod_name.c
@@ -0,0 +1,389 @@
+/* $USAGI: ninfod_name.c,v 1.15 2003-01-11 14:33:28 yoshfuji Exp $ */
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Author:
+ * 	YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if STDC_HEADERS
+# include <stdio.h>
+# include <stdlib.h>
+# include <stddef.h>
+# include <ctype.h>
+#else
+# if HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if TIME_WITH_SYS_TIME   
+# include <sys/time.h>  
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H     
+#  include <sys/time.h>
+# else                
+#  include <time.h>
+# endif                  
+#endif                   
+
+#if HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#include <sys/socket.h>
+
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#if HAVE_NETINET_ICMP6_H
+# include <netinet/icmp6.h>
+#endif
+#ifndef HAVE_STRUCT_ICMP6_NODEINFO
+# include "icmp6_nodeinfo.h"
+#endif
+
+#include <arpa/inet.h>
+
+#if defined(HAVE_GNUTLS_OPENSSL_H)
+# include <gnutls/openssl.h>
+#elif defined(HAVE_OPENSSL_MD5_H)
+# include <openssl/md5.h>
+#endif
+
+#if HAVE_SYS_UTSNAME_H
+# include <sys/utsname.h>
+#endif
+#if HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#include <errno.h>
+
+#if HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+#include "ninfod.h"
+
+#ifndef offsetof
+# define offsetof(aggregate,member)	((size_t)&((aggregate *)0)->member)
+#endif
+
+/* Hmm,,, */
+#ifndef IPV6_JOIN_GROUP
+# define IPV6_JOIN_GROUP	IPV6_ADD_MEMBERSHIP
+# define IPV6_LEAVE_GROUP	IPV6_DROP_MEMBERSHIP
+#endif
+
+/* ---------- */
+/* ID */
+static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod_name.c,v 1.15 2003-01-11 14:33:28 yoshfuji Exp $";
+
+/* Variables */
+static struct utsname utsname;
+static char *uts_nodename = utsname.nodename;
+
+char nodename[MAX_DNSNAME_SIZE];
+static size_t nodenamelen;
+
+static struct ipv6_mreq nigroup;
+
+/* ---------- */
+/* Functions */
+int check_nigroup(const struct in6_addr *addr)
+{
+	return IN6_IS_ADDR_MULTICAST(&nigroup.ipv6mr_multiaddr) &&
+	       IN6_ARE_ADDR_EQUAL(&nigroup.ipv6mr_multiaddr, addr);
+}
+
+static int encode_dnsname(const char *name, 
+			  char *buf, size_t buflen, 
+			  int fqdn)
+{
+	size_t namelen;
+	int i;
+
+	if (buflen < 0)
+		return -1;
+
+	namelen = strlen(name);
+	if (namelen == 0)
+		return 0;
+	if (namelen > 255 || buflen < namelen+1)
+		return -1;
+
+	i = 0;
+	while(i <= namelen) {
+		const char *e;
+		int llen, ii;
+
+		e = strchr(&name[i], '.');
+		if (e == NULL)
+			e = name + namelen;
+		llen = e - &name[i];
+		if (llen == 0) {
+			if (*e)
+				return -1;
+			if (fqdn < 0)
+				return -1;
+			fqdn = 1;
+			break;
+		}
+		if (llen >= 0x40)
+			return -1;
+		buf[i] = llen;
+		for (ii = 0; ii < llen; ii++) {
+			if (!isascii(name[i+ii]))
+				return -1;
+			if (ii == 0 || ii == llen-1) {
+				if (!isalpha(name[i+ii]) && !isdigit(name[i+ii]))
+					return -1;
+			} else if (!isalnum(name[i+ii]) && name[i+ii] != '-')
+				return -1;
+			buf[i+ii+1] = isupper(name[i+ii]) ? tolower(name[i+ii]) : name[i+ii];
+		}
+		i += llen + 1;
+	}
+	if (buflen < i + 1 + !(fqdn > 0))
+		return -1;
+	buf[i++] = 0;
+	if (!(fqdn > 0))
+		buf[i++] = 0;
+	return i;
+}
+
+static int compare_dnsname(const char *s, size_t slen,
+			   const char *n, size_t nlen)
+{
+	const char *s0 = s, *n0 = n;
+	int done = 0, retcode = 0;
+	if (slen < 1 || nlen < 1)
+		return -1;	/* invalid length */
+	/* simple case */
+	if (slen == nlen && memcmp(s, n, slen) == 0)
+		return 0;
+	if (*(s0 + slen - 1) || *(n0 + nlen - 1))
+		return -1;	/* invalid termination */
+	while (s < s0 + slen && n < n0 + nlen) {
+		if (*s >= 0x40 || *n >= 0x40)
+			return -1;	/* DNS compression is not allowed here */
+		if (s + *s + 1 > s0 + slen || n + *n + 1 > n0 + nlen)
+			return -1;	/* overrun */
+		if (*s == '\0') {
+			if (s == s0 + slen - 1)
+				break;	/* FQDN */
+			else if (s + 1 == s0 + slen - 1)
+				return retcode;	/* truncated */
+			else
+				return -1;	/* more than one subject */
+		}
+		if (!done) {
+			if (*n == '\0') {
+				if (n == n0 + nlen - 1) {
+					done = 1;	/* FQDN */
+				} else if (n + 1 == n0 + nlen - 1) {
+					retcode = 1;	// trunc
+					done = 1;
+				} else
+					return -1;
+			} else {
+				if (*s != *n) {
+					done = 1;
+					retcode = 1;
+				} else {
+					if (memcmp(s+1, n+1, *s)) {
+						done = 1;
+						retcode = 1;
+					}
+				}
+			}
+		}
+		s += *s + 1;
+		n += done ? 0 : (*n + 1);
+	}
+	return retcode;
+}
+
+static int nodeinfo_group(const char *dnsname, int namelen, 
+			  struct in6_addr *nigroup)
+{
+	MD5_CTX ctxt;
+	unsigned char digest[16];
+
+	if (!dnsname || !nigroup)
+		return -1;
+
+	MD5_Init(&ctxt);
+	MD5_Update(&ctxt, dnsname, *dnsname);
+	MD5_Final(digest, &ctxt);
+
+#ifdef s6_addr32
+	nigroup->s6_addr32[0] = htonl(0xff020000);
+	nigroup->s6_addr32[1] = 0;
+	nigroup->s6_addr32[2] = htonl(0x00000002);
+#else
+	memset(nigroup, 0, sizeof(*nigroup));
+	nigroup->s6_addr[ 0] = 0xff;
+	nigroup->s6_addr[ 1] = 0x02;
+	nigroup->s6_addr[11] = 0x02;
+#endif
+	memcpy(&nigroup->s6_addr[12], digest, 4);
+
+	return 0;
+}
+
+/* ---------- */
+void init_nodeinfo_nodename(int forced)
+{
+	struct utsname newname;
+	int len;
+	int changed = 0;
+
+	DEBUG(LOG_DEBUG, "%s()\n", __func__);
+
+	uname(&newname);
+	changed = strcmp(newname.nodename, utsname.nodename);
+
+	if (!changed && !forced)
+		return;
+
+	memcpy(&utsname, &newname, sizeof(newname));
+
+	/* leave old group */
+	if ((changed || forced) && !IN6_IS_ADDR_UNSPECIFIED(&nigroup.ipv6mr_multiaddr)) {
+		if (setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &nigroup, sizeof(nigroup)) < 0) {
+#if ENABLE_DEBUG
+			char niaddrbuf[INET6_ADDRSTRLEN];
+			if (inet_ntop(AF_INET6, &nigroup, niaddrbuf, sizeof(niaddrbuf)) == NULL)
+				strcpy(niaddrbuf, "???");
+#endif
+			DEBUG(LOG_WARNING,
+			      "%s(): failed to leave group %s.\n",
+			      __func__, niaddrbuf);
+			memset(&nigroup, 0, sizeof(nigroup));
+		}
+	}
+
+	len = encode_dnsname(uts_nodename,
+			     nodename, 
+			     sizeof(nodename),
+			     0);
+
+	/* setup ni reply */
+	nodenamelen = len > 0 ? len : 0;
+
+	/* setup ni group */
+	if (changed || forced) {
+		if (nodenamelen) {
+			memset(&nigroup, 0, sizeof(nigroup));
+			nodeinfo_group(nodename, len, &nigroup.ipv6mr_multiaddr);
+			nigroup.ipv6mr_interface = 0;
+			if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &nigroup, sizeof(nigroup)) < 0) {
+#if ENABLE_DEBUG
+				char niaddrbuf[INET6_ADDRSTRLEN];
+				if (inet_ntop(AF_INET6, &nigroup, niaddrbuf, sizeof(niaddrbuf)) == NULL)
+					strcpy(niaddrbuf, "???");
+#endif
+				DEBUG(LOG_WARNING,
+				      "%s(): failed to join group %s.\n",
+				      __func__, niaddrbuf);
+				memset(&nigroup, 0, sizeof(nigroup));
+			}
+		} else {
+			memset(&nigroup, 0, sizeof(nigroup));
+		}
+	}
+
+	return;
+}
+
+/* ---------- */
+/* nodename */
+int pr_nodeinfo_nodename(CHECKANDFILL_ARGS)
+{
+	DEBUG(LOG_DEBUG, "%s()\n", __func__);
+
+	if (subject) {
+		if (!nodenamelen ||
+		    compare_dnsname(subject, subjlen, 
+				    nodename, 
+				    nodenamelen))
+			return 1;
+		if (subj_if)
+			*subj_if = p->pktinfo.ipi6_ifindex;
+	}
+
+	if (reply) {
+		uint32_t ttl = 0;
+
+		p->reply.ni_type = ICMP6_NI_REPLY;
+		p->reply.ni_code = ICMP6_NI_SUCCESS;
+		p->reply.ni_cksum = 0;
+		p->reply.ni_qtype = htons(NI_QTYPE_DNSNAME);
+		p->reply.ni_flags = 0;
+
+		p->replydatalen = nodenamelen ? sizeof(ttl)+nodenamelen : 0;
+		p->replydata = nodenamelen ? ni_malloc(p->replydatalen) : NULL;
+		if (p->replydata) {
+			memcpy(p->replydata, &ttl, sizeof(ttl));
+			memcpy(p->replydata + sizeof(ttl), &nodename, nodenamelen);
+		}
+	}
+
+	return 0;
+}
+
diff --git a/iputils/ping.c b/iputils/ping.c
new file mode 100644
index 0000000..ec4e040
--- /dev/null
+++ b/iputils/ping.c
@@ -0,0 +1,1431 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Muuss.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ *			P I N G . C
+ *
+ * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
+ * measure round-trip-delays and packet loss across network paths.
+ *
+ * Author -
+ *	Mike Muuss
+ *	U. S. Army Ballistic Research Laboratory
+ *	December, 1983
+ *
+ * Status -
+ *	Public Domain.  Distribution Unlimited.
+ * Bugs -
+ *	More statistics could always be gathered.
+ *	This program has to run SUID to ROOT to access the ICMP socket.
+ */
+
+#include "ping_common.h"
+
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#ifndef WITHOUT_IFADDRS
+#include <ifaddrs.h>
+#endif
+
+#ifndef ICMP_FILTER
+#define ICMP_FILTER	1
+struct icmp_filter {
+	__u32	data;
+};
+#endif
+
+#define	MAXIPLEN	60
+#define	MAXICMPLEN	76
+#define	NROUTES		9		/* number of record route slots */
+#define TOS_MAX		255		/* 8-bit TOS field */
+#define MAX_HOSTNAMELEN	NI_MAXHOST
+
+
+static int ts_type;
+static int nroute = 0;
+static __u32 route[10];
+
+
+
+struct sockaddr_in whereto;	/* who to ping */
+int optlen = 0;
+int settos = 0;			/* Set TOS, Precendence or other QOS options */
+int icmp_sock;			/* socket file descriptor */
+u_char outpack[0x10000];
+int maxpacket = sizeof(outpack);
+
+static int broadcast_pings = 0;
+
+static char *pr_addr(__u32);
+static void pr_options(unsigned char * cp, int hlen);
+static void pr_iph(struct iphdr *ip);
+static void usage(void) __attribute__((noreturn));
+static u_short in_cksum(const u_short *addr, int len, u_short salt);
+static void pr_icmph(__u8 type, __u8 code, __u32 info, struct icmphdr *icp);
+static int parsetos(char *str);
+
+static struct {
+	struct cmsghdr cm;
+	struct in_pktinfo ipi;
+} cmsg = { {sizeof(struct cmsghdr) + sizeof(struct in_pktinfo), SOL_IP, IP_PKTINFO},
+	   {0, }};
+int cmsg_len;
+
+struct sockaddr_in source;
+char *device;
+int pmtudisc = -1;
+
+
+int
+main(int argc, char **argv)
+{
+	struct hostent *hp;
+	int ch, hold, packlen;
+	int socket_errno = 0;
+	u_char *packet;
+	char *target;
+#ifdef USE_IDN
+	char *hnamebuf = NULL;
+#else
+	char hnamebuf[MAX_HOSTNAMELEN];
+#endif
+	char rspace[3 + 4 * NROUTES + 1];	/* record route space */
+
+#ifdef ANDROID
+	android_check_security();
+#endif
+
+	limit_capabilities();
+
+#ifdef USE_IDN
+	setlocale(LC_ALL, "");
+#endif
+
+	icmp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+	if (icmp_sock < 0) {
+		enable_capability_raw();
+		icmp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+		socket_errno = errno;
+		disable_capability_raw();
+		using_ping_socket = 0;
+	}
+
+	source.sin_family = AF_INET;
+
+	preload = 1;
+	while ((ch = getopt(argc, argv, COMMON_OPTSTR "bRT:")) != EOF) {
+		switch(ch) {
+		case 'b':
+			broadcast_pings = 1;
+			break;
+		case 'Q':
+			settos = parsetos(optarg);
+			if (settos &&
+			    (setsockopt(icmp_sock, IPPROTO_IP, IP_TOS,
+					(char *)&settos, sizeof(int)) < 0)) {
+				perror("ping: error setting QOS sockopts");
+				exit(2);
+			}
+			break;
+		case 'R':
+			if (options & F_TIMESTAMP) {
+				fprintf(stderr, "Only one of -T or -R may be used\n");
+				exit(2);
+			}
+			options |= F_RROUTE;
+			break;
+		case 'T':
+			if (options & F_RROUTE) {
+				fprintf(stderr, "Only one of -T or -R may be used\n");
+				exit(2);
+			}
+			options |= F_TIMESTAMP;
+			if (strcmp(optarg, "tsonly") == 0)
+				ts_type = IPOPT_TS_TSONLY;
+			else if (strcmp(optarg, "tsandaddr") == 0)
+				ts_type = IPOPT_TS_TSANDADDR;
+			else if (strcmp(optarg, "tsprespec") == 0)
+				ts_type = IPOPT_TS_PRESPEC;
+			else {
+				fprintf(stderr, "Invalid timestamp type\n");
+				exit(2);
+			}
+			break;
+		case 'I':
+		{
+#if 0
+			char dummy;
+			int i1, i2, i3, i4;
+
+			if (sscanf(optarg, "%u.%u.%u.%u%c",
+				   &i1, &i2, &i3, &i4, &dummy) == 4) {
+				__u8 *ptr;
+				ptr = (__u8*)&source.sin_addr;
+				ptr[0] = i1;
+				ptr[1] = i2;
+				ptr[2] = i3;
+				ptr[3] = i4;
+				options |= F_STRICTSOURCE;
+			} else {
+				device = optarg;
+			}
+#else
+			if (inet_pton(AF_INET, optarg, &source.sin_addr) > 0)
+				options |= F_STRICTSOURCE;
+			else
+				device = optarg;
+#endif
+			break;
+		}
+		case 'M':
+			if (strcmp(optarg, "do") == 0)
+				pmtudisc = IP_PMTUDISC_DO;
+			else if (strcmp(optarg, "dont") == 0)
+				pmtudisc = IP_PMTUDISC_DONT;
+			else if (strcmp(optarg, "want") == 0)
+				pmtudisc = IP_PMTUDISC_WANT;
+			else {
+				fprintf(stderr, "ping: wrong value for -M: do, dont, want are valid ones.\n");
+				exit(2);
+			}
+			break;
+		case 'V':
+			printf("ping utility, iputils-%s\n", SNAPSHOT);
+			exit(0);
+		COMMON_OPTIONS
+			common_options(ch);
+			break;
+		default:
+			usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc == 0)
+		usage();
+	if (argc > 1) {
+		if (options & F_RROUTE)
+			usage();
+		else if (options & F_TIMESTAMP) {
+			if (ts_type != IPOPT_TS_PRESPEC)
+				usage();
+			if (argc > 5)
+				usage();
+		} else {
+			if (argc > 10)
+				usage();
+			options |= F_SOURCEROUTE;
+		}
+	}
+	while (argc > 0) {
+		target = *argv;
+
+		memset((char *)&whereto, 0, sizeof(whereto));
+		whereto.sin_family = AF_INET;
+		if (inet_aton(target, &whereto.sin_addr) == 1) {
+			hostname = target;
+			if (argc == 1)
+				options |= F_NUMERIC;
+		} else {
+			char *idn;
+#ifdef USE_IDN
+			int rc;
+
+			if (hnamebuf) {
+				free(hnamebuf);
+				hnamebuf = NULL;
+			}
+
+			rc = idna_to_ascii_lz(target, &idn, 0);
+			if (rc != IDNA_SUCCESS) {
+				fprintf(stderr, "ping: IDN encoding failed: %s\n", idna_strerror(rc));
+				exit(2);
+			}
+#else
+			idn = target;
+#endif
+			hp = gethostbyname(idn);
+			if (!hp) {
+				fprintf(stderr, "ping: unknown host %s\n", target);
+				exit(2);
+			}
+#ifdef USE_IDN
+			free(idn);
+#endif
+			memcpy(&whereto.sin_addr, hp->h_addr, 4);
+#ifdef USE_IDN
+			if (idna_to_unicode_lzlz(hp->h_name, &hnamebuf, 0) != IDNA_SUCCESS) {
+				hnamebuf = strdup(hp->h_name);
+				if (!hnamebuf) {
+					perror("ping: strdup");
+					exit(-1);
+				}
+			}
+#else
+			strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
+			hnamebuf[sizeof(hnamebuf) - 1] = 0;
+#endif
+			hostname = hnamebuf;
+		}
+		if (argc > 1)
+			route[nroute++] = whereto.sin_addr.s_addr;
+		argc--;
+		argv++;
+	}
+
+	if (source.sin_addr.s_addr == 0) {
+		socklen_t alen;
+		struct sockaddr_in dst = whereto;
+		int probe_fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+		if (probe_fd < 0) {
+			perror("socket");
+			exit(2);
+		}
+		if (device) {
+			struct ifreq ifr;
+			int rc;
+
+			memset(&ifr, 0, sizeof(ifr));
+			strncpy(ifr.ifr_name, device, IFNAMSIZ-1);
+
+			enable_capability_raw();
+			rc = setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1);
+			disable_capability_raw();
+
+			if (rc == -1) {
+				if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) {
+					struct ip_mreqn imr;
+					if (ioctl(probe_fd, SIOCGIFINDEX, &ifr) < 0) {
+						fprintf(stderr, "ping: unknown iface %s\n", device);
+						exit(2);
+					}
+					memset(&imr, 0, sizeof(imr));
+					imr.imr_ifindex = ifr.ifr_ifindex;
+					if (setsockopt(probe_fd, SOL_IP, IP_MULTICAST_IF, &imr, sizeof(imr)) == -1) {
+						perror("ping: IP_MULTICAST_IF");
+						exit(2);
+					}
+				} else {
+					perror("ping: SO_BINDTODEVICE");
+					exit(2);
+				}
+			}
+		}
+
+		if (settos &&
+		    setsockopt(probe_fd, IPPROTO_IP, IP_TOS, (char *)&settos, sizeof(int)) < 0)
+			perror("Warning: error setting QOS sockopts");
+
+		dst.sin_port = htons(1025);
+		if (nroute)
+			dst.sin_addr.s_addr = route[0];
+
+		sock_setmark(probe_fd);
+
+		if (connect(probe_fd, (struct sockaddr*)&dst, sizeof(dst)) == -1) {
+			if (errno == EACCES) {
+				if (broadcast_pings == 0) {
+					fprintf(stderr, "Do you want to ping broadcast? Then -b\n");
+					exit(2);
+				}
+				fprintf(stderr, "WARNING: pinging broadcast address\n");
+				if (setsockopt(probe_fd, SOL_SOCKET, SO_BROADCAST,
+					       &broadcast_pings, sizeof(broadcast_pings)) < 0) {
+					perror ("can't set broadcasting");
+					exit(2);
+				}
+				if (connect(probe_fd, (struct sockaddr*)&dst, sizeof(dst)) == -1) {
+					perror("connect");
+					exit(2);
+				}
+			} else {
+				perror("connect");
+				exit(2);
+			}
+		}
+		alen = sizeof(source);
+		if (getsockname(probe_fd, (struct sockaddr*)&source, &alen) == -1) {
+			perror("getsockname");
+			exit(2);
+		}
+		source.sin_port = 0;
+
+#ifndef WITHOUT_IFADDRS
+		if (device) {
+			struct ifaddrs *ifa0, *ifa;
+			int ret;
+
+			ret = getifaddrs(&ifa0);
+			if (ret) {
+				fprintf(stderr, "gatifaddrs() failed.\n");
+				exit(2);
+			}
+			for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
+				if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET)
+					continue;
+				if (!strncmp(ifa->ifa_name, device, sizeof(device) - 1) &&
+				    !memcmp(&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
+					    &source.sin_addr, sizeof(source.sin_addr)))
+					break;
+			}
+			freeifaddrs(ifa0);
+			if (!ifa)
+				fprintf(stderr, "ping: Warning: source address might be selected on device other than %s.\n", device);
+		}
+#endif
+		close(probe_fd);
+	} while (0);
+
+	if (whereto.sin_addr.s_addr == 0)
+		whereto.sin_addr.s_addr = source.sin_addr.s_addr;
+
+	if (icmp_sock < 0) {
+		errno = socket_errno;
+		perror("ping: icmp open socket");
+		exit(2);
+	}
+
+	if (device) {
+		struct ifreq ifr;
+
+		memset(&ifr, 0, sizeof(ifr));
+		strncpy(ifr.ifr_name, device, IFNAMSIZ-1);
+		if (ioctl(icmp_sock, SIOCGIFINDEX, &ifr) < 0) {
+			fprintf(stderr, "ping: unknown iface %s\n", device);
+			exit(2);
+		}
+		cmsg.ipi.ipi_ifindex = ifr.ifr_ifindex;
+		cmsg_len = sizeof(cmsg);
+	}
+
+	if (broadcast_pings || IN_MULTICAST(ntohl(whereto.sin_addr.s_addr))) {
+		if (uid) {
+			if (interval < 1000) {
+				fprintf(stderr, "ping: broadcast ping with too short interval.\n");
+				exit(2);
+			}
+			if (pmtudisc >= 0 && pmtudisc != IP_PMTUDISC_DO) {
+				fprintf(stderr, "ping: broadcast ping does not fragment.\n");
+				exit(2);
+			}
+		}
+		if (pmtudisc < 0)
+			pmtudisc = IP_PMTUDISC_DO;
+	}
+
+	if (pmtudisc >= 0) {
+		if (setsockopt(icmp_sock, SOL_IP, IP_MTU_DISCOVER, &pmtudisc, sizeof(pmtudisc)) == -1) {
+			perror("ping: IP_MTU_DISCOVER");
+			exit(2);
+		}
+	}
+
+	if ((options&F_STRICTSOURCE) &&
+	    bind(icmp_sock, (struct sockaddr*)&source, sizeof(source)) == -1) {
+		perror("bind");
+		exit(2);
+	}
+
+	if (!using_ping_socket) {
+		struct icmp_filter filt;
+		filt.data = ~((1<<ICMP_SOURCE_QUENCH)|
+			      (1<<ICMP_DEST_UNREACH)|
+			      (1<<ICMP_TIME_EXCEEDED)|
+			      (1<<ICMP_PARAMETERPROB)|
+			      (1<<ICMP_REDIRECT)|
+			      (1<<ICMP_ECHOREPLY));
+		if (setsockopt(icmp_sock, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1)
+			perror("WARNING: setsockopt(ICMP_FILTER)");
+	}
+
+	hold = 1;
+	if (setsockopt(icmp_sock, SOL_IP, IP_RECVERR, (char *)&hold, sizeof(hold)))
+		fprintf(stderr, "WARNING: your kernel is veeery old. No problems.\n");
+	if (using_ping_socket) {
+		if (setsockopt(icmp_sock, SOL_IP, IP_RECVTTL, (char *)&hold, sizeof(hold)))
+			perror("WARNING: setsockopt(IP_RECVTTL)");
+		if (setsockopt(icmp_sock, SOL_IP, IP_RETOPTS, (char *)&hold, sizeof(hold)))
+			perror("WARNING: setsockopt(IP_RETOPTS)");
+	}
+
+	/* record route option */
+	if (options & F_RROUTE) {
+		memset(rspace, 0, sizeof(rspace));
+		rspace[0] = IPOPT_NOP;
+		rspace[1+IPOPT_OPTVAL] = IPOPT_RR;
+		rspace[1+IPOPT_OLEN] = sizeof(rspace)-1;
+		rspace[1+IPOPT_OFFSET] = IPOPT_MINOFF;
+		optlen = 40;
+		if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, sizeof(rspace)) < 0) {
+			perror("ping: record route");
+			exit(2);
+		}
+	}
+	if (options & F_TIMESTAMP) {
+		memset(rspace, 0, sizeof(rspace));
+		rspace[0] = IPOPT_TIMESTAMP;
+		rspace[1] = (ts_type==IPOPT_TS_TSONLY ? 40 : 36);
+		rspace[2] = 5;
+		rspace[3] = ts_type;
+		if (ts_type == IPOPT_TS_PRESPEC) {
+			int i;
+			rspace[1] = 4+nroute*8;
+			for (i=0; i<nroute; i++)
+				*(__u32*)&rspace[4+i*8] = route[i];
+		}
+		if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, rspace[1]) < 0) {
+			rspace[3] = 2;
+			if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, rspace[1]) < 0) {
+				perror("ping: ts option");
+				exit(2);
+			}
+		}
+		optlen = 40;
+	}
+	if (options & F_SOURCEROUTE) {
+		int i;
+		memset(rspace, 0, sizeof(rspace));
+		rspace[0] = IPOPT_NOOP;
+		rspace[1+IPOPT_OPTVAL] = (options & F_SO_DONTROUTE) ? IPOPT_SSRR
+			: IPOPT_LSRR;
+		rspace[1+IPOPT_OLEN] = 3 + nroute*4;
+		rspace[1+IPOPT_OFFSET] = IPOPT_MINOFF;
+		for (i=0; i<nroute; i++)
+			*(__u32*)&rspace[4+i*4] = route[i];
+
+		if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, 4 + nroute*4) < 0) {
+			perror("ping: record route");
+			exit(2);
+		}
+		optlen = 40;
+	}
+
+	/* Estimate memory eaten by single packet. It is rough estimate.
+	 * Actually, for small datalen's it depends on kernel side a lot. */
+	hold = datalen + 8;
+	hold += ((hold+511)/512)*(optlen + 20 + 16 + 64 + 160);
+	sock_setbufs(icmp_sock, hold);
+
+	if (broadcast_pings) {
+		if (setsockopt(icmp_sock, SOL_SOCKET, SO_BROADCAST,
+			       &broadcast_pings, sizeof(broadcast_pings)) < 0) {
+			perror ("ping: can't set broadcasting");
+			exit(2);
+		}
+	}
+
+	if (options & F_NOLOOP) {
+		int loop = 0;
+		if (setsockopt(icmp_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
+							&loop, 1) == -1) {
+			perror ("ping: can't disable multicast loopback");
+			exit(2);
+		}
+	}
+	if (options & F_TTL) {
+		int ittl = ttl;
+		if (setsockopt(icmp_sock, IPPROTO_IP, IP_MULTICAST_TTL,
+							&ttl, 1) == -1) {
+			perror ("ping: can't set multicast time-to-live");
+			exit(2);
+		}
+		if (setsockopt(icmp_sock, IPPROTO_IP, IP_TTL,
+							&ittl, sizeof(ittl)) == -1) {
+			perror ("ping: can't set unicast time-to-live");
+			exit(2);
+		}
+	}
+
+	if (datalen > 0xFFFF - 8 - optlen - 20) {
+		if (uid || datalen > sizeof(outpack)-8) {
+			fprintf(stderr, "Error: packet size %d is too large. Maximum is %d\n", datalen, 0xFFFF-8-20-optlen);
+			exit(2);
+		}
+		/* Allow small oversize to root yet. It will cause EMSGSIZE. */
+		fprintf(stderr, "WARNING: packet size %d is too large. Maximum is %d\n", datalen, 0xFFFF-8-20-optlen);
+	}
+
+	if (datalen >= sizeof(struct timeval))	/* can we time transfer */
+		timing = 1;
+	packlen = datalen + MAXIPLEN + MAXICMPLEN;
+	if (!(packet = (u_char *)malloc((u_int)packlen))) {
+		fprintf(stderr, "ping: out of memory.\n");
+		exit(2);
+	}
+
+	printf("PING %s (%s) ", hostname, inet_ntoa(whereto.sin_addr));
+	if (device || (options&F_STRICTSOURCE))
+		printf("from %s %s: ", inet_ntoa(source.sin_addr), device ?: "");
+	printf("%d(%d) bytes of data.\n", datalen, datalen+8+optlen+20);
+
+	setup(icmp_sock);
+
+	main_loop(icmp_sock, packet, packlen);
+}
+
+
+int receive_error_msg()
+{
+	int res;
+	char cbuf[512];
+	struct iovec  iov;
+	struct msghdr msg;
+	struct cmsghdr *cmsg;
+	struct sock_extended_err *e;
+	struct icmphdr icmph;
+	struct sockaddr_in target;
+	int net_errors = 0;
+	int local_errors = 0;
+	int saved_errno = errno;
+
+	iov.iov_base = &icmph;
+	iov.iov_len = sizeof(icmph);
+	msg.msg_name = (void*)&target;
+	msg.msg_namelen = sizeof(target);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_flags = 0;
+	msg.msg_control = cbuf;
+	msg.msg_controllen = sizeof(cbuf);
+
+	res = recvmsg(icmp_sock, &msg, MSG_ERRQUEUE|MSG_DONTWAIT);
+	if (res < 0)
+		goto out;
+
+	e = NULL;
+	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+		if (cmsg->cmsg_level == SOL_IP) {
+			if (cmsg->cmsg_type == IP_RECVERR)
+				e = (struct sock_extended_err *)CMSG_DATA(cmsg);
+		}
+	}
+	if (e == NULL)
+		abort();
+
+	if (e->ee_origin == SO_EE_ORIGIN_LOCAL) {
+		local_errors++;
+		if (options & F_QUIET)
+			goto out;
+		if (options & F_FLOOD)
+			write_stdout("E", 1);
+		else if (e->ee_errno != EMSGSIZE)
+			fprintf(stderr, "ping: local error: %s\n", strerror(e->ee_errno));
+		else
+			fprintf(stderr, "ping: local error: Message too long, mtu=%u\n", e->ee_info);
+		nerrors++;
+	} else if (e->ee_origin == SO_EE_ORIGIN_ICMP) {
+		struct sockaddr_in *sin = (struct sockaddr_in*)(e+1);
+		int error_pkt;
+
+		if (res < sizeof(icmph) ||
+		    target.sin_addr.s_addr != whereto.sin_addr.s_addr ||
+		    icmph.type != ICMP_ECHO ||
+		    !is_ours(icmph.un.echo.id)) {
+			/* Not our error, not an error at all. Clear. */
+			saved_errno = 0;
+			goto out;
+		}
+
+		error_pkt = (e->ee_type != ICMP_REDIRECT &&
+			     e->ee_type != ICMP_SOURCE_QUENCH);
+		if (error_pkt) {
+			acknowledge(ntohs(icmph.un.echo.sequence));
+			net_errors++;
+			nerrors++;
+		}
+		else {
+			saved_errno = 0;
+		}
+
+		if (!using_ping_socket && !working_recverr) {
+			struct icmp_filter filt;
+			working_recverr = 1;
+			/* OK, it works. Add stronger filter. */
+			filt.data = ~((1<<ICMP_SOURCE_QUENCH)|
+				      (1<<ICMP_REDIRECT)|
+				      (1<<ICMP_ECHOREPLY));
+			if (setsockopt(icmp_sock, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1)
+				perror("\rWARNING: setsockopt(ICMP_FILTER)");
+		}
+
+		if (options & F_QUIET)
+			goto out;
+		if (options & F_FLOOD) {
+			if (error_pkt)
+				write_stdout("\bE", 2);
+		} else {
+			print_timestamp();
+			printf("From %s: icmp_seq=%u ", pr_addr(sin->sin_addr.s_addr), ntohs(icmph.un.echo.sequence));
+			pr_icmph(e->ee_type, e->ee_code, e->ee_info, NULL);
+			fflush(stdout);
+		}
+	}
+
+out:
+	errno = saved_errno;
+	return net_errors ? : -local_errors;
+}
+
+/*
+ * pinger --
+ * 	Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
+ * will be added on by the kernel.  The ID field is our UNIX process ID,
+ * and the sequence number is an ascending integer.  The first 8 bytes
+ * of the data portion are used to hold a UNIX "timeval" struct in VAX
+ * byte-order, to compute the round-trip time.
+ */
+int send_probe()
+{
+	struct icmphdr *icp;
+	int cc;
+	int i;
+
+	icp = (struct icmphdr *)outpack;
+	icp->type = ICMP_ECHO;
+	icp->code = 0;
+	icp->checksum = 0;
+	icp->un.echo.sequence = htons(ntransmitted+1);
+	icp->un.echo.id = ident;			/* ID */
+
+	rcvd_clear(ntransmitted+1);
+
+	if (timing) {
+		if (options&F_LATENCY) {
+			struct timeval tmp_tv;
+			gettimeofday(&tmp_tv, NULL);
+			memcpy(icp+1, &tmp_tv, sizeof(tmp_tv));
+		} else {
+			memset(icp+1, 0, sizeof(struct timeval));
+		}
+	}
+
+	cc = datalen + 8;			/* skips ICMP portion */
+
+	/* compute ICMP checksum here */
+	icp->checksum = in_cksum((u_short *)icp, cc, 0);
+
+	if (timing && !(options&F_LATENCY)) {
+		struct timeval tmp_tv;
+		gettimeofday(&tmp_tv, NULL);
+		memcpy(icp+1, &tmp_tv, sizeof(tmp_tv));
+		icp->checksum = in_cksum((u_short *)&tmp_tv, sizeof(tmp_tv), ~icp->checksum);
+	}
+
+	do {
+		static struct iovec iov = {outpack, 0};
+		static struct msghdr m = { &whereto, sizeof(whereto),
+						   &iov, 1, &cmsg, 0, 0 };
+		m.msg_controllen = cmsg_len;
+		iov.iov_len = cc;
+
+		i = sendmsg(icmp_sock, &m, confirm);
+		confirm = 0;
+	} while (0);
+
+	return (cc == i ? 0 : i);
+}
+
+/*
+ * parse_reply --
+ *	Print out the packet, if it came from us.  This logic is necessary
+ * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
+ * which arrive ('tis only fair).  This permits multiple copies of this
+ * program to be run without having intermingled output (or statistics!).
+ */
+void pr_echo_reply(__u8 *_icp, int len)
+{
+	struct icmphdr *icp = (struct icmphdr *)_icp;
+	printf(" icmp_seq=%u", ntohs(icp->un.echo.sequence));
+}
+
+int
+parse_reply(struct msghdr *msg, int cc, void *addr, struct timeval *tv)
+{
+	struct sockaddr_in *from = addr;
+	__u8 *buf = msg->msg_iov->iov_base;
+	struct icmphdr *icp;
+	struct iphdr *ip;
+	int hlen;
+	int csfailed;
+	struct cmsghdr *cmsg;
+	int ttl;
+	__u8 *opts;
+	int optlen;
+
+	/* Check the IP header */
+	ip = (struct iphdr *)buf;
+	if (!using_ping_socket) {
+		hlen = ip->ihl*4;
+		if (cc < hlen + 8 || ip->ihl < 5) {
+			if (options & F_VERBOSE)
+				fprintf(stderr, "ping: packet too short (%d bytes) from %s\n", cc,
+					pr_addr(from->sin_addr.s_addr));
+			return 1;
+		}
+		ttl = ip->ttl;
+		opts = buf + sizeof(struct iphdr);
+		optlen = hlen - sizeof(struct iphdr);
+	} else {
+		hlen = 0;
+		ttl = 0;
+		opts = buf;
+		optlen = 0;
+		for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+			if (cmsg->cmsg_level != SOL_IP)
+				continue;
+			if (cmsg->cmsg_type == IP_TTL) {
+				if (cmsg->cmsg_len < sizeof(int))
+					continue;
+				ttl = *(int *) CMSG_DATA(cmsg);
+			} else if (cmsg->cmsg_type == IP_RETOPTS) {
+				opts = (__u8 *) CMSG_DATA(cmsg);
+				optlen = cmsg->cmsg_len;
+			}
+		}
+	}
+
+	/* Now the ICMP part */
+	cc -= hlen;
+	icp = (struct icmphdr *)(buf + hlen);
+	csfailed = in_cksum((u_short *)icp, cc, 0);
+
+	if (icp->type == ICMP_ECHOREPLY) {
+		if (!is_ours(icp->un.echo.id))
+			return 1;			/* 'Twas not our ECHO */
+		if (gather_statistics((__u8*)icp, sizeof(*icp), cc,
+				      ntohs(icp->un.echo.sequence),
+				      ttl, 0, tv, pr_addr(from->sin_addr.s_addr),
+				      pr_echo_reply))
+			return 0;
+	} else {
+		/* We fall here when a redirect or source quench arrived.
+		 * Also this branch processes icmp errors, when IP_RECVERR
+		 * is broken. */
+
+		switch (icp->type) {
+		case ICMP_ECHO:
+			/* MUST NOT */
+			return 1;
+		case ICMP_SOURCE_QUENCH:
+		case ICMP_REDIRECT:
+		case ICMP_DEST_UNREACH:
+		case ICMP_TIME_EXCEEDED:
+		case ICMP_PARAMETERPROB:
+			{
+				struct iphdr * iph = (struct  iphdr *)(&icp[1]);
+				struct icmphdr *icp1 = (struct icmphdr*)((unsigned char *)iph + iph->ihl*4);
+				int error_pkt;
+				if (cc < 8+sizeof(struct iphdr)+8 ||
+				    cc < 8+iph->ihl*4+8)
+					return 1;
+				if (icp1->type != ICMP_ECHO ||
+				    iph->daddr != whereto.sin_addr.s_addr ||
+				    !is_ours(icp1->un.echo.id))
+					return 1;
+				error_pkt = (icp->type != ICMP_REDIRECT &&
+					     icp->type != ICMP_SOURCE_QUENCH);
+				if (error_pkt) {
+					acknowledge(ntohs(icp1->un.echo.sequence));
+					if (working_recverr) {
+						return 0;
+					} else {
+						static int once;
+						/* Sigh, IP_RECVERR for raw socket
+						 * was broken until 2.4.9. So, we ignore
+						 * the first error and warn on the second.
+						 */
+						if (once++ == 1)
+							fprintf(stderr, "\rWARNING: kernel is not very fresh, upgrade is recommended.\n");
+						if (once == 1)
+							return 0;
+					}
+				}
+				nerrors+=error_pkt;
+				if (options&F_QUIET)
+					return !error_pkt;
+				if (options & F_FLOOD) {
+					if (error_pkt)
+						write_stdout("\bE", 2);
+					return !error_pkt;
+				}
+				print_timestamp();
+				printf("From %s: icmp_seq=%u ",
+				       pr_addr(from->sin_addr.s_addr),
+				       ntohs(icp1->un.echo.sequence));
+				if (csfailed)
+					printf("(BAD CHECKSUM)");
+				pr_icmph(icp->type, icp->code, ntohl(icp->un.gateway), icp);
+				return !error_pkt;
+			}
+		default:
+			/* MUST NOT */
+			break;
+		}
+		if ((options & F_FLOOD) && !(options & (F_VERBOSE|F_QUIET))) {
+			if (!csfailed)
+				write_stdout("!E", 2);
+			else
+				write_stdout("!EC", 3);
+			return 0;
+		}
+		if (!(options & F_VERBOSE) || uid)
+			return 0;
+		if (options & F_PTIMEOFDAY) {
+			struct timeval recv_time;
+			gettimeofday(&recv_time, NULL);
+			printf("%lu.%06lu ", (unsigned long)recv_time.tv_sec, (unsigned long)recv_time.tv_usec);
+		}
+		printf("From %s: ", pr_addr(from->sin_addr.s_addr));
+		if (csfailed) {
+			printf("(BAD CHECKSUM)\n");
+			return 0;
+		}
+		pr_icmph(icp->type, icp->code, ntohl(icp->un.gateway), icp);
+		return 0;
+	}
+
+	if (!(options & F_FLOOD)) {
+		pr_options(opts, optlen + sizeof(struct iphdr));
+
+		if (options & F_AUDIBLE)
+			putchar('\a');
+		putchar('\n');
+		fflush(stdout);
+	} else {
+		putchar('\a');
+		fflush(stdout);
+	}
+	return 0;
+}
+
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+# define ODDBYTE(v)	(v)
+#elif BYTE_ORDER == BIG_ENDIAN
+# define ODDBYTE(v)	((u_short)(v) << 8)
+#else
+# define ODDBYTE(v)	htons((u_short)(v) << 8)
+#endif
+
+u_short
+in_cksum(const u_short *addr, register int len, u_short csum)
+{
+	register int nleft = len;
+	const u_short *w = addr;
+	register u_short answer;
+	register int sum = csum;
+
+	/*
+	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
+	 *  we add sequential 16 bit words to it, and at the end, fold
+	 *  back all the carry bits from the top 16 bits into the lower
+	 *  16 bits.
+	 */
+	while (nleft > 1)  {
+		sum += *w++;
+		nleft -= 2;
+	}
+
+	/* mop up an odd byte, if necessary */
+	if (nleft == 1)
+		sum += ODDBYTE(*(u_char *)w); /* le16toh() may be unavailable on old systems */
+
+	/*
+	 * add back carry outs from top 16 bits to low 16 bits
+	 */
+	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
+	sum += (sum >> 16);			/* add carry */
+	answer = ~sum;				/* truncate to 16 bits */
+	return (answer);
+}
+
+/*
+ * pr_icmph --
+ *	Print a descriptive string about an ICMP header.
+ */
+void pr_icmph(__u8 type, __u8 code, __u32 info, struct icmphdr *icp)
+{
+	switch(type) {
+	case ICMP_ECHOREPLY:
+		printf("Echo Reply\n");
+		/* XXX ID + Seq + Data */
+		break;
+	case ICMP_DEST_UNREACH:
+		switch(code) {
+		case ICMP_NET_UNREACH:
+			printf("Destination Net Unreachable\n");
+			break;
+		case ICMP_HOST_UNREACH:
+			printf("Destination Host Unreachable\n");
+			break;
+		case ICMP_PROT_UNREACH:
+			printf("Destination Protocol Unreachable\n");
+			break;
+		case ICMP_PORT_UNREACH:
+			printf("Destination Port Unreachable\n");
+			break;
+		case ICMP_FRAG_NEEDED:
+			printf("Frag needed and DF set (mtu = %u)\n", info);
+			break;
+		case ICMP_SR_FAILED:
+			printf("Source Route Failed\n");
+			break;
+		case ICMP_NET_UNKNOWN:
+			printf("Destination Net Unknown\n");
+			break;
+		case ICMP_HOST_UNKNOWN:
+			printf("Destination Host Unknown\n");
+			break;
+		case ICMP_HOST_ISOLATED:
+			printf("Source Host Isolated\n");
+			break;
+		case ICMP_NET_ANO:
+			printf("Destination Net Prohibited\n");
+			break;
+		case ICMP_HOST_ANO:
+			printf("Destination Host Prohibited\n");
+			break;
+		case ICMP_NET_UNR_TOS:
+			printf("Destination Net Unreachable for Type of Service\n");
+			break;
+		case ICMP_HOST_UNR_TOS:
+			printf("Destination Host Unreachable for Type of Service\n");
+			break;
+		case ICMP_PKT_FILTERED:
+			printf("Packet filtered\n");
+			break;
+		case ICMP_PREC_VIOLATION:
+			printf("Precedence Violation\n");
+			break;
+		case ICMP_PREC_CUTOFF:
+			printf("Precedence Cutoff\n");
+			break;
+		default:
+			printf("Dest Unreachable, Bad Code: %d\n", code);
+			break;
+		}
+		if (icp && (options & F_VERBOSE))
+			pr_iph((struct iphdr*)(icp + 1));
+		break;
+	case ICMP_SOURCE_QUENCH:
+		printf("Source Quench\n");
+		if (icp && (options & F_VERBOSE))
+			pr_iph((struct iphdr*)(icp + 1));
+		break;
+	case ICMP_REDIRECT:
+		switch(code) {
+		case ICMP_REDIR_NET:
+			printf("Redirect Network");
+			break;
+		case ICMP_REDIR_HOST:
+			printf("Redirect Host");
+			break;
+		case ICMP_REDIR_NETTOS:
+			printf("Redirect Type of Service and Network");
+			break;
+		case ICMP_REDIR_HOSTTOS:
+			printf("Redirect Type of Service and Host");
+			break;
+		default:
+			printf("Redirect, Bad Code: %d", code);
+			break;
+		}
+		printf("(New nexthop: %s)\n", pr_addr(icp ? icp->un.gateway : info));
+		if (icp && (options & F_VERBOSE))
+			pr_iph((struct iphdr*)(icp + 1));
+		break;
+	case ICMP_ECHO:
+		printf("Echo Request\n");
+		/* XXX ID + Seq + Data */
+		break;
+	case ICMP_TIME_EXCEEDED:
+		switch(code) {
+		case ICMP_EXC_TTL:
+			printf("Time to live exceeded\n");
+			break;
+		case ICMP_EXC_FRAGTIME:
+			printf("Frag reassembly time exceeded\n");
+			break;
+		default:
+			printf("Time exceeded, Bad Code: %d\n", code);
+			break;
+		}
+		if (icp && (options & F_VERBOSE))
+			pr_iph((struct iphdr*)(icp + 1));
+		break;
+	case ICMP_PARAMETERPROB:
+		printf("Parameter problem: pointer = %u\n", icp ? (ntohl(icp->un.gateway)>>24) : info);
+		if (icp && (options & F_VERBOSE))
+			pr_iph((struct iphdr*)(icp + 1));
+		break;
+	case ICMP_TIMESTAMP:
+		printf("Timestamp\n");
+		/* XXX ID + Seq + 3 timestamps */
+		break;
+	case ICMP_TIMESTAMPREPLY:
+		printf("Timestamp Reply\n");
+		/* XXX ID + Seq + 3 timestamps */
+		break;
+	case ICMP_INFO_REQUEST:
+		printf("Information Request\n");
+		/* XXX ID + Seq */
+		break;
+	case ICMP_INFO_REPLY:
+		printf("Information Reply\n");
+		/* XXX ID + Seq */
+		break;
+#ifdef ICMP_MASKREQ
+	case ICMP_MASKREQ:
+		printf("Address Mask Request\n");
+		break;
+#endif
+#ifdef ICMP_MASKREPLY
+	case ICMP_MASKREPLY:
+		printf("Address Mask Reply\n");
+		break;
+#endif
+	default:
+		printf("Bad ICMP type: %d\n", type);
+	}
+}
+
+void pr_options(unsigned char * cp, int hlen)
+{
+	int i, j;
+	int optlen, totlen;
+	unsigned char * optptr;
+	static int old_rrlen;
+	static char old_rr[MAX_IPOPTLEN];
+
+	totlen = hlen-sizeof(struct iphdr);
+	optptr = cp;
+
+	while (totlen > 0) {
+		if (*optptr == IPOPT_EOL)
+			break;
+		if (*optptr == IPOPT_NOP) {
+			totlen--;
+			optptr++;
+			printf("\nNOP");
+			continue;
+		}
+		cp = optptr;
+		optlen = optptr[1];
+		if (optlen < 2 || optlen > totlen)
+			break;
+
+		switch (*cp) {
+		case IPOPT_SSRR:
+		case IPOPT_LSRR:
+			printf("\n%cSRR: ", *cp==IPOPT_SSRR ? 'S' : 'L');
+			j = *++cp;
+			i = *++cp;
+			i -= 4;
+			cp++;
+			if (j > IPOPT_MINOFF) {
+				for (;;) {
+					__u32 address;
+					memcpy(&address, cp, 4);
+					cp += 4;
+					if (address == 0)
+						printf("\t0.0.0.0");
+					else
+						printf("\t%s", pr_addr(address));
+					j -= 4;
+					putchar('\n');
+					if (j <= IPOPT_MINOFF)
+						break;
+				}
+			}
+			break;
+		case IPOPT_RR:
+			j = *++cp;		/* get length */
+			i = *++cp;		/* and pointer */
+			if (i > j)
+				i = j;
+			i -= IPOPT_MINOFF;
+			if (i <= 0)
+				break;
+			if (i == old_rrlen
+			    && !memcmp(cp, old_rr, i)
+			    && !(options & F_FLOOD)) {
+				printf("\t(same route)");
+				i = ((i + 3) / 4) * 4;
+				cp += i;
+				break;
+			}
+			old_rrlen = i;
+			memcpy(old_rr, (char *)cp, i);
+			printf("\nRR: ");
+			cp++;
+			for (;;) {
+				__u32 address;
+				memcpy(&address, cp, 4);
+				cp += 4;
+				if (address == 0)
+					printf("\t0.0.0.0");
+				else
+					printf("\t%s", pr_addr(address));
+				i -= 4;
+				putchar('\n');
+				if (i <= 0)
+					break;
+			}
+			break;
+		case IPOPT_TS:
+		{
+			int stdtime = 0, nonstdtime = 0;
+			__u8 flags;
+			j = *++cp;		/* get length */
+			i = *++cp;		/* and pointer */
+			if (i > j)
+				i = j;
+			i -= 5;
+			if (i <= 0)
+				break;
+			flags = *++cp;
+			printf("\nTS: ");
+			cp++;
+			for (;;) {
+				long l;
+
+				if ((flags&0xF) != IPOPT_TS_TSONLY) {
+					__u32 address;
+					memcpy(&address, cp, 4);
+					cp += 4;
+					if (address == 0)
+						printf("\t0.0.0.0");
+					else
+						printf("\t%s", pr_addr(address));
+					i -= 4;
+					if (i <= 0)
+						break;
+				}
+				l = *cp++;
+				l = (l<<8) + *cp++;
+				l = (l<<8) + *cp++;
+				l = (l<<8) + *cp++;
+
+				if  (l & 0x80000000) {
+					if (nonstdtime==0)
+						printf("\t%ld absolute not-standard", l&0x7fffffff);
+					else
+						printf("\t%ld not-standard", (l&0x7fffffff) - nonstdtime);
+					nonstdtime = l&0x7fffffff;
+				} else {
+					if (stdtime==0)
+						printf("\t%ld absolute", l);
+					else
+						printf("\t%ld", l - stdtime);
+					stdtime = l;
+				}
+				i -= 4;
+				putchar('\n');
+				if (i <= 0)
+					break;
+			}
+			if (flags>>4)
+				printf("Unrecorded hops: %d\n", flags>>4);
+			break;
+		}
+		default:
+			printf("\nunknown option %x", *cp);
+			break;
+		}
+		totlen -= optlen;
+		optptr += optlen;
+	}
+}
+
+
+/*
+ * pr_iph --
+ *	Print an IP header with options.
+ */
+void pr_iph(struct iphdr *ip)
+{
+	int hlen;
+	u_char *cp;
+
+	hlen = ip->ihl << 2;
+	cp = (u_char *)ip + 20;		/* point to options */
+
+	printf("Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst Data\n");
+	printf(" %1x  %1x  %02x %04x %04x",
+	       ip->version, ip->ihl, ip->tos, ip->tot_len, ip->id);
+	printf("   %1x %04x", ((ip->frag_off) & 0xe000) >> 13,
+	       (ip->frag_off) & 0x1fff);
+	printf("  %02x  %02x %04x", ip->ttl, ip->protocol, ip->check);
+	printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->saddr));
+	printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->daddr));
+	printf("\n");
+	pr_options(cp, hlen);
+}
+
+/*
+ * pr_addr --
+ *	Return an ascii host address as a dotted quad and optionally with
+ * a hostname.
+ */
+char *
+pr_addr(__u32 addr)
+{
+	struct hostent *hp;
+	static char buf[4096];
+
+	in_pr_addr = !setjmp(pr_addr_jmp);
+
+	if (exiting || (options & F_NUMERIC) ||
+	    !(hp = gethostbyaddr((char *)&addr, 4, AF_INET)))
+		sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&addr));
+	else {
+		char *s;
+#if USE_IDN
+		if (idna_to_unicode_lzlz(hp->h_name, &s, 0) != IDNA_SUCCESS)
+			s = NULL;
+#else
+		s = NULL;
+#endif
+		snprintf(buf, sizeof(buf), "%s (%s)", s ? s : hp->h_name,
+			 inet_ntoa(*(struct in_addr *)&addr));
+#if USE_IDN
+		free(s);
+#endif
+	}
+
+	in_pr_addr = 0;
+
+	return(buf);
+}
+
+
+/* Set Type of Service (TOS) and other Quality of Service relating bits */
+int parsetos(char *str)
+{
+	const char *cp;
+	int tos;
+	char *ep;
+
+	/* handle both hex and decimal values */
+	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
+		cp = str + 2;
+		tos = (int)strtol(cp, &ep, 16);
+	} else
+		tos = (int)strtol(str, &ep, 10);
+
+	/* doesn't look like decimal or hex, eh? */
+	if (*ep != '\0') {
+		fprintf(stderr, "ping: \"%s\" bad value for TOS\n", str);
+		exit(2);
+	}
+
+	if (tos > TOS_MAX) {
+		fprintf(stderr, "ping: the decimal value of TOS bits must be 0-254 (or zero)\n");
+		exit(2);
+	}
+	return(tos);
+}
+
+#include <linux/filter.h>
+
+void install_filter(void)
+{
+	static int once;
+	static struct sock_filter insns[] = {
+		BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), /* Skip IP header. F..g BSD... Look into ping6. */
+		BPF_STMT(BPF_LD|BPF_H|BPF_IND, 4), /* Load icmp echo ident */
+		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xAAAA, 0, 1), /* Ours? */
+		BPF_STMT(BPF_RET|BPF_K, ~0U), /* Yes, it passes. */
+		BPF_STMT(BPF_LD|BPF_B|BPF_IND, 0), /* Load icmp type */
+		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */
+		BPF_STMT(BPF_RET|BPF_K, 0xFFFFFFF), /* No. It passes. */
+		BPF_STMT(BPF_RET|BPF_K, 0) /* Echo with wrong ident. Reject. */
+	};
+	static struct sock_fprog filter = {
+		sizeof insns / sizeof(insns[0]),
+		insns
+	};
+
+	if (once || using_ping_socket)
+		return;
+	once = 1;
+
+	/* Patch bpflet for current identifier. */
+	insns[2] = (struct sock_filter)BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(ident), 0, 1);
+
+	if (setsockopt(icmp_sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)))
+		perror("WARNING: failed to install socket filter\n");
+}
+
+#define USAGE_NEWLINE	"\n           "
+
+void usage(void)
+{
+	fprintf(stderr,
+		"Usage: ping"
+		" [-"
+			"aAbBdDfhLnOqrRUvV"
+		"]"
+		" [-c count]"
+		" [-i interval]"
+		" [-I interface]"
+		USAGE_NEWLINE
+		" [-m mark]"
+		" [-M pmtudisc_option]"
+		" [-l preload]"
+		" [-p pattern]"
+		" [-Q tos]"
+		USAGE_NEWLINE
+		" [-s packetsize]"
+		" [-S sndbuf]"
+		" [-t ttl]"
+		" [-T timestamp_option]"
+		USAGE_NEWLINE
+		" [-w deadline]"
+		" [-W timeout]"
+		" [hop1 ...] destination"
+		"\n"
+	);
+	exit(2);
+}
diff --git a/iputils/ping6.c b/iputils/ping6.c
new file mode 100644
index 0000000..baa0768
--- /dev/null
+++ b/iputils/ping6.c
@@ -0,0 +1,1878 @@
+/*
+ *
+ *	Modified for AF_INET6 by Pedro Roque
+ *
+ *	<roque@di.fc.ul.pt>
+ *
+ *	Original copyright notice included bellow
+ */
+
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Muuss.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ *			P I N G . C
+ *
+ * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
+ * measure round-trip-delays and packet loss across network paths.
+ *
+ * Author -
+ *	Mike Muuss
+ *	U. S. Army Ballistic Research Laboratory
+ *	December, 1983
+ *
+ * Status -
+ *	Public Domain.  Distribution Unlimited.
+ * Bugs -
+ *	More statistics could always be gathered.
+ *	This program has to run SUID to ROOT to access the ICMP socket.
+ */
+#include "ping_common.h"
+
+#include <linux/filter.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <resolv.h>
+#ifndef WITHOUT_IFADDRS
+#include <ifaddrs.h>
+#endif
+
+#ifdef USE_IDN
+#include <stringprep.h>
+#endif
+
+#include "ping6_niquery.h"
+#include "in6_flowlabel.h"
+
+#ifndef SOL_IPV6
+#define SOL_IPV6 IPPROTO_IPV6
+#endif
+
+#ifndef SOL_ICMPV6
+#define SOL_ICMPV6 IPPROTO_ICMPV6
+#endif
+
+/* RFC3542 */
+#ifndef ICMP6_DST_UNREACH_BEYONDSCOPE
+#define ICMP6_DST_UNREACH_BEYONDSCOPE ICMP6_DST_UNREACH_NOTNEIGHBOR
+#endif
+
+#if defined(ENABLE_PING6_RTHDR) && !defined(ENABLE_PING6_RTHDR_RFC3542)
+#ifndef IPV6_SRCRT_TYPE_0
+#define IPV6_SRCRT_TYPE_0	0
+#endif
+#endif
+
+#ifndef MLD_LISTENER_QUERY
+#define MLD_LISTENER_QUERY	130
+#define MLD_LISTENER_REPORT	131
+#define MLD_LISTENER_REDUCTION	132
+#endif
+
+#define BIT_CLEAR(nr, addr) do { ((__u32 *)(addr))[(nr) >> 5] &= ~(1U << ((nr) & 31)); } while(0)
+#define BIT_SET(nr, addr) do { ((__u32 *)(addr))[(nr) >> 5] |= (1U << ((nr) & 31)); } while(0)
+#define BIT_TEST(nr, addr) do { (__u32 *)(addr))[(nr) >> 5] & (1U << ((nr) & 31)); } while(0)
+
+#ifndef ICMP6_FILTER_WILLPASS
+#define ICMP6_FILTER_WILLPASS(type, filterp) \
+	(BIT_TEST((type), filterp) == 0)
+
+#define ICMP6_FILTER_WILLBLOCK(type, filterp) \
+	BIT_TEST((type), filterp)
+
+#define ICMP6_FILTER_SETPASS(type, filterp) \
+	BIT_CLEAR((type), filterp)
+
+#define ICMP6_FILTER_SETBLOCK(type, filterp) \
+	BIT_SET((type), filterp)
+
+#define ICMP6_FILTER_SETPASSALL(filterp) \
+	memset(filterp, 0, sizeof(struct icmp6_filter));
+
+#define ICMP6_FILTER_SETBLOCKALL(filterp) \
+	memset(filterp, 0xFF, sizeof(struct icmp6_filter));
+#endif
+
+#define	MAXPACKET	128000		/* max packet size */
+
+#ifdef SO_TIMESTAMP
+#define HAVE_SIN6_SCOPEID 1
+#endif
+
+#ifndef SCOPE_DELIMITER
+# define SCOPE_DELIMITER '%'
+#endif
+
+__u32 flowlabel;
+__u32 tclass;
+#ifdef ENABLE_PING6_RTHDR
+struct cmsghdr *srcrt;
+#endif
+
+struct sockaddr_in6 whereto;	/* who to ping */
+u_char outpack[MAXPACKET];
+int maxpacket = sizeof(outpack);
+
+static unsigned char cmsgbuf[4096];
+static int cmsglen = 0;
+
+static char * pr_addr(struct in6_addr *addr);
+static char * pr_addr_n(struct in6_addr *addr);
+static int pr_icmph(__u8 type, __u8 code, __u32 info);
+static void usage(void) __attribute((noreturn));
+
+struct sockaddr_in6 source;
+char *device;
+int pmtudisc=-1;
+
+static int icmp_sock;
+
+#ifdef USE_GNUTLS
+# include <gnutls/openssl.h>
+#else
+# include <openssl/md5.h>
+#endif
+
+/* Node Information query */
+int ni_query = -1;
+int ni_flag = 0;
+void *ni_subject = NULL;
+int ni_subject_len = 0;
+int ni_subject_type = -1;
+char *ni_group;
+
+static inline int ntohsp(__u16 *p)
+{
+	__u16 v;
+	memcpy(&v, p, sizeof(v));
+	return ntohs(v);
+}
+
+#if defined(ENABLE_PING6_RTHDR) && !defined(ENABLE_PING6_RTHDR_RFC3542)
+size_t inet6_srcrt_space(int type, int segments)
+{
+	if (type != 0 || segments > 24)
+		return 0;
+
+	return (sizeof(struct cmsghdr) + sizeof(struct ip6_rthdr0) +
+		segments * sizeof(struct in6_addr));
+}
+
+extern struct cmsghdr *	inet6_srcrt_init(void *bp, int type)
+{
+	struct cmsghdr *cmsg;
+
+	if (type)
+		return NULL;
+
+	memset(bp, 0, sizeof(struct cmsghdr) + sizeof(struct ip6_rthdr0));
+	cmsg = (struct cmsghdr *) bp;
+
+	cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct ip6_rthdr0);
+	cmsg->cmsg_level = SOL_IPV6;
+	cmsg->cmsg_type = IPV6_RTHDR;
+
+	return cmsg;
+}
+
+int inet6_srcrt_add(struct cmsghdr *cmsg, const struct in6_addr *addr)
+{
+	struct ip6_rthdr0 *hdr;
+
+	hdr = (struct ip6_rthdr0 *) CMSG_DATA(cmsg);
+
+	cmsg->cmsg_len += sizeof(struct in6_addr);
+	hdr->ip6r0_len += sizeof(struct in6_addr) / 8;
+
+	memcpy(&hdr->ip6r0_addr[hdr->ip6r0_segleft++], addr,
+	       sizeof(struct in6_addr));
+
+	return 0;
+}
+#endif
+
+unsigned int if_name2index(const char *ifname)
+{
+	unsigned int i = if_nametoindex(ifname);
+	if (!i) {
+		fprintf(stderr, "ping: unknown iface %s\n", ifname);
+		exit(2);
+	}
+	return i;
+}
+
+struct niquery_option {
+	char *name;
+	int namelen;
+	int has_arg;
+	int data;
+	int (*handler)(int index, const char *arg);
+};
+
+#define NIQUERY_OPTION(_name, _has_arg, _data, _handler)	\
+	{							\
+		.name = _name,					\
+		.namelen = sizeof(_name) - 1,			\
+		.has_arg = _has_arg,				\
+		.data = _data,					\
+		.handler = _handler				\
+	}
+
+static int niquery_option_name_handler(int index, const char *arg);
+static int niquery_option_ipv6_handler(int index, const char *arg);
+static int niquery_option_ipv6_flag_handler(int index, const char *arg);
+static int niquery_option_ipv4_handler(int index, const char *arg);
+static int niquery_option_ipv4_flag_handler(int index, const char *arg);
+static int niquery_option_subject_addr_handler(int index, const char *arg);
+static int niquery_option_subject_name_handler(int index, const char *arg);
+static int niquery_option_help_handler(int index, const char *arg);
+
+struct niquery_option niquery_options[] = {
+	NIQUERY_OPTION("name",			0,	0,				niquery_option_name_handler),
+	NIQUERY_OPTION("fqdn",			0,	0,				niquery_option_name_handler),
+	NIQUERY_OPTION("ipv6",			0,	0,				niquery_option_ipv6_handler),
+	NIQUERY_OPTION("ipv6-all",		0,	NI_IPV6ADDR_F_ALL,		niquery_option_ipv6_flag_handler),
+	NIQUERY_OPTION("ipv6-compatible",	0,	NI_IPV6ADDR_F_COMPAT,		niquery_option_ipv6_flag_handler),
+	NIQUERY_OPTION("ipv6-linklocal",	0,	NI_IPV6ADDR_F_LINKLOCAL,	niquery_option_ipv6_flag_handler),
+	NIQUERY_OPTION("ipv6-sitelocal",	0,	NI_IPV6ADDR_F_SITELOCAL,	niquery_option_ipv6_flag_handler),
+	NIQUERY_OPTION("ipv6-global",		0,	NI_IPV6ADDR_F_GLOBAL,		niquery_option_ipv6_flag_handler),
+	NIQUERY_OPTION("ipv4",			0,	0,				niquery_option_ipv4_handler),
+	NIQUERY_OPTION("ipv4-all",		0,	NI_IPV4ADDR_F_ALL,		niquery_option_ipv4_flag_handler),
+	NIQUERY_OPTION("subject-ipv6",		1,	NI_SUBJ_IPV6,			niquery_option_subject_addr_handler),
+	NIQUERY_OPTION("subject-ipv4",		1,	NI_SUBJ_IPV4,			niquery_option_subject_addr_handler),
+	NIQUERY_OPTION("subject-name",		1,	0,				niquery_option_subject_name_handler),
+	NIQUERY_OPTION("subject-fqdn",		1,	-1,				niquery_option_subject_name_handler),
+	NIQUERY_OPTION("help",			0,	0,				niquery_option_help_handler),
+	{},
+};
+
+static inline int niquery_is_enabled(void)
+{
+	return ni_query >= 0;
+}
+
+#if PING6_NONCE_MEMORY
+__u8 *ni_nonce_ptr;
+#else
+struct {
+	struct timeval tv;
+	pid_t pid;
+} ni_nonce_secret;
+#endif
+
+static void niquery_init_nonce(void)
+{
+#if PING6_NONCE_MEMORY
+	struct timeval tv;
+	unsigned long seed;
+
+	seed = (unsigned long)getpid();
+	if (!gettimeofday(&tv, NULL))
+		seed ^= tv.tv_usec;
+	srand(seed);
+
+	ni_nonce_ptr = calloc(NI_NONCE_SIZE, MAX_DUP_CHK);
+	if (!ni_nonce_ptr) {
+		perror("ping6: calloc");
+		exit(2);
+	}
+
+	ni_nonce_ptr[0] = ~0;
+#else
+	gettimeofday(&ni_nonce_secret.tv, NULL);
+	ni_nonce_secret.pid = getpid();
+#endif
+}
+
+#if !PING6_NONCE_MEMORY
+static int niquery_nonce(__u8 *nonce, int fill)
+{
+	static __u8 digest[MD5_DIGEST_LENGTH];
+	static int seq = -1;
+
+	if (fill || seq != *(__u16 *)nonce || seq < 0) {
+		MD5_CTX ctxt;
+
+		MD5_Init(&ctxt);
+		MD5_Update(&ctxt, &ni_nonce_secret, sizeof(ni_nonce_secret));
+		MD5_Update(&ctxt, nonce, sizeof(__u16));
+		MD5_Final(digest, &ctxt);
+
+		seq = *(__u16 *)nonce;
+	}
+
+	if (fill) {
+		memcpy(nonce + sizeof(__u16), digest, NI_NONCE_SIZE - sizeof(__u16));
+		return 0;
+	} else {
+		if (memcmp(nonce + sizeof(__u16), digest, NI_NONCE_SIZE - sizeof(__u16)))
+			return -1;
+		return ntohsp((__u16 *)nonce);
+	}
+}
+#endif
+
+static inline void niquery_fill_nonce(__u16 seq, __u8 *nonce)
+{
+	__u16 v = htons(seq);
+#if PING6_NONCE_MEMORY
+	int i;
+
+	memcpy(&ni_nonce_ptr[NI_NONCE_SIZE * (seq % MAX_DUP_CHK)], &v, sizeof(v));
+
+	for (i = sizeof(v); i < NI_NONCE_SIZE; i++)
+		ni_nonce_ptr[NI_NONCE_SIZE * (seq % MAX_DUP_CHK) + i] = 0x100 * (rand() / (RAND_MAX + 1.0));
+
+	memcpy(nonce, &ni_nonce_ptr[NI_NONCE_SIZE * (seq % MAX_DUP_CHK)], NI_NONCE_SIZE);
+#else
+	memcpy(nonce, &v, sizeof(v));
+	niquery_nonce(nonce, 1);
+#endif
+}
+
+static inline int niquery_check_nonce(__u8 *nonce)
+{
+#if PING6_NONCE_MEMORY
+	__u16 seq = ntohsp((__u16 *)nonce);
+	if (memcmp(nonce, &ni_nonce_ptr[NI_NONCE_SIZE * (seq % MAX_DUP_CHK)], NI_NONCE_SIZE))
+		return -1;
+	return seq;
+#else
+	return niquery_nonce(nonce, 0);
+#endif
+}
+
+static int niquery_set_qtype(int type)
+{
+	if (niquery_is_enabled() && ni_query != type) {
+		printf("Qtype conflict\n");
+		return -1;
+	}
+	ni_query = type;
+	return 0;
+}
+
+static int niquery_option_name_handler(int index, const char *arg)
+{
+	if (niquery_set_qtype(NI_QTYPE_NAME) < 0)
+		return -1;
+	return 0;
+}
+
+static int niquery_option_ipv6_handler(int index, const char *arg)
+{
+	if (niquery_set_qtype(NI_QTYPE_IPV6ADDR) < 0)
+		return -1;
+	return 0;
+}
+
+static int niquery_option_ipv6_flag_handler(int index, const char *arg)
+{
+	if (niquery_set_qtype(NI_QTYPE_IPV6ADDR) < 0)
+		return -1;
+	ni_flag |= niquery_options[index].data;
+	return 0;
+}
+
+static int niquery_option_ipv4_handler(int index, const char *arg)
+{
+	if (niquery_set_qtype(NI_QTYPE_IPV4ADDR) < 0)
+		return -1;
+	return 0;
+}
+
+static int niquery_option_ipv4_flag_handler(int index, const char *arg)
+{
+	if (niquery_set_qtype(NI_QTYPE_IPV4ADDR) < 0)
+		return -1;
+	ni_flag |= niquery_options[index].data;
+	return 0;
+}
+
+static inline int niquery_is_subject_valid(void)
+{
+	return ni_subject_type >= 0 && ni_subject;
+}
+
+static int niquery_set_subject_type(int type)
+{
+	if (niquery_is_subject_valid() && ni_subject_type != type) {
+		printf("Subject type conflict\n");
+		return -1;
+	}
+	ni_subject_type = type;
+	return 0;
+}
+
+#define ARRAY_SIZE(array)	(sizeof(array) / sizeof(array[0]))
+#define OFFSET_OF(type,elem)	((size_t)&((type *)0)->elem)
+
+static int niquery_option_subject_addr_handler(int index, const char *arg)
+{
+	struct addrinfo hints, *ai0, *ai;
+	int offset;
+	int gai;
+
+	if (niquery_set_subject_type(niquery_options[index].data) < 0)
+		return -1;
+
+	ni_subject_type = niquery_options[index].data;
+
+	memset(&hints, 0, sizeof(hints));
+
+	switch (niquery_options[index].data) {
+	case NI_SUBJ_IPV6:
+		ni_subject_len = sizeof(struct in6_addr);
+		offset = OFFSET_OF(struct sockaddr_in6, sin6_addr);
+		hints.ai_family = AF_INET6;
+		break;
+	case NI_SUBJ_IPV4:
+		ni_subject_len = sizeof(struct in_addr);
+		offset = OFFSET_OF(struct sockaddr_in, sin_addr);
+		hints.ai_family = AF_INET;
+		break;
+	default:
+		/* should not happen. */
+		offset = -1;
+	}
+
+	hints.ai_socktype = SOCK_DGRAM;
+#ifdef USE_IDN
+	hints.ai_flags = AI_IDN;
+#endif
+
+	gai = getaddrinfo(arg, 0, &hints, &ai0);
+	if (gai) {
+		fprintf(stderr, "Unknown host: %s\n", arg);
+		return -1;
+	}
+
+	for (ai = ai0; ai; ai = ai->ai_next) {
+		void *p = malloc(ni_subject_len);
+		if (!p)
+			continue;
+		memcpy(p, (__u8 *)ai->ai_addr + offset, ni_subject_len);
+		free(ni_subject);
+		ni_subject = p;
+		break;
+	}
+	freeaddrinfo(ai0);
+
+	return 0;
+}
+
+static int niquery_option_subject_name_handler(int index, const char *arg)
+{
+	static char nigroup_buf[INET6_ADDRSTRLEN + 1 + IFNAMSIZ];
+	unsigned char *dnptrs[2], **dpp, **lastdnptr;
+	int n;
+	int i;
+	char *name, *p;
+	char *canonname = NULL, *idn = NULL;
+	unsigned char *buf = NULL;
+	size_t namelen;
+	size_t buflen;
+	int dots, fqdn = niquery_options[index].data;
+	MD5_CTX ctxt;
+	__u8 digest[MD5_DIGEST_LENGTH];
+#ifdef USE_IDN
+	int rc;
+#endif
+
+	if (niquery_set_subject_type(NI_SUBJ_NAME) < 0)
+		return -1;
+
+#ifdef USE_IDN
+	name = stringprep_locale_to_utf8(arg);
+	if (!name) {
+		fprintf(stderr, "ping6: IDN support failed.\n");
+		exit(2);
+	}
+#else
+	name = strdup(arg);
+	if (!name)
+		goto oomexit;
+#endif
+
+	p = strchr(name, SCOPE_DELIMITER);
+	if (p) {
+		*p = '\0';
+		if (strlen(p + 1) >= IFNAMSIZ) {
+			fprintf(stderr, "ping6: too long scope name.\n");
+			exit(1);
+		}
+	}
+
+#ifdef USE_IDN
+	rc = idna_to_ascii_8z(name, &idn, 0);
+	if (rc) {
+		fprintf(stderr, "ping6: IDN encoding error: %s\n",
+			idna_strerror(rc));
+		exit(2);
+	}
+#else
+	idn = strdup(name);
+	if (!idn)
+		goto oomexit;
+#endif
+
+	namelen = strlen(idn);
+	canonname = malloc(namelen + 1);
+	if (!canonname)
+		goto oomexit;
+
+	dots = 0;
+	for (i = 0; i < namelen + 1; i++) {
+		canonname[i] = isupper(idn[i]) ? tolower(idn[i]) : idn[i];
+		if (idn[i] == '.')
+			dots++;
+	}
+
+	if (fqdn == 0) {
+		/* guess if hostname is FQDN */
+		fqdn = dots ? 1 : -1;
+	}
+
+	buflen = namelen + 3 + 1;	/* dn_comp() requrires strlen() + 3,
+					   plus non-fqdn indicator. */
+	buf = malloc(buflen);
+	if (!buf) {
+		fprintf(stderr, "ping6: out of memory.\n");
+		goto errexit;
+	}
+
+	dpp = dnptrs;
+	lastdnptr = &dnptrs[ARRAY_SIZE(dnptrs)];
+
+	*dpp++ = (unsigned char *)buf;
+	*dpp++ = NULL;
+
+	n = dn_comp(canonname, (unsigned char *)buf, buflen, dnptrs, lastdnptr);
+	if (n < 0) {
+		fprintf(stderr, "ping6: Inappropriate subject name: %s\n", canonname);
+		goto errexit;
+	} else if (n >= buflen) {
+		fprintf(stderr, "ping6: dn_comp() returned too long result.\n");
+		goto errexit;
+	}
+
+	MD5_Init(&ctxt);
+	MD5_Update(&ctxt, buf, buf[0]);
+	MD5_Final(digest, &ctxt);
+
+	sprintf(nigroup_buf, "ff02::2:%02x%02x:%02x%02x%s%s",
+		digest[0], digest[1], digest[2], digest[3],
+		p ? "%" : "",
+		p ? p + 1 : "");
+
+	if (fqdn < 0)
+		buf[n] = 0;
+
+	free(ni_subject);
+
+	ni_group = nigroup_buf;
+	ni_subject = buf;
+	ni_subject_len = n + (fqdn < 0);
+	ni_group = nigroup_buf;
+
+	free(canonname);
+	free(idn);
+	free(name);
+
+	return 0;
+oomexit:
+	fprintf(stderr, "ping6: out of memory.\n");
+errexit:
+	free(buf);
+	free(canonname);
+	free(idn);
+	free(name);
+	exit(1);
+}
+
+int niquery_option_help_handler(int index, const char *arg)
+{
+	fprintf(stderr, "ping6 -N suboptions\n"
+			"\tHelp:\n"
+			"\t\thelp\n"
+			"\tQuery:\n"
+			"\t\tname,\n"
+			"\t\tipv6,ipv6-all,ipv6-compatible,ipv6-linklocal,ipv6-sitelocal,ipv6-global,\n"
+			"\t\tipv4,ipv4-all,\n"
+			"\tSubject:\n"
+			"\t\tsubject-ipv6=addr,subject-ipv4=addr,subject-name=name,subject-fqdn=name,\n"
+		);
+	exit(2);
+}
+
+int niquery_option_handler(const char *opt_arg)
+{
+	struct niquery_option *p;
+	int i;
+	int ret = -1;
+	for (i = 0, p = niquery_options; p->name; i++, p++) {
+		if (strncmp(p->name, opt_arg, p->namelen))
+			continue;
+		if (!p->has_arg) {
+			if (opt_arg[p->namelen] == '\0') {
+				ret = p->handler(i, NULL);
+				if (ret >= 0)
+					break;
+			}
+		} else {
+			if (opt_arg[p->namelen] == '=') {
+				ret = p->handler(i, &opt_arg[p->namelen] + 1);
+				if (ret >= 0)
+					break;
+			}
+		}
+	}
+	if (!p->name)
+		ret = niquery_option_help_handler(0, NULL);
+	return ret;
+}
+
+static int hextoui(const char *str)
+{
+	unsigned long val;
+	char *ep;
+
+	errno = 0;
+	val = strtoul(str, &ep, 16);
+	if (*ep) {
+		if (!errno)
+			errno = EINVAL;
+		return -1;
+	}
+
+	if (val > UINT_MAX) {
+		errno = ERANGE;
+		return UINT_MAX;
+	}
+
+	return val;
+}
+
+int main(int argc, char *argv[])
+{
+	int ch, hold, packlen;
+	u_char *packet;
+	char *target;
+	struct addrinfo hints, *ai;
+	int gai;
+	struct sockaddr_in6 firsthop;
+	int socket_errno = 0;
+	struct icmp6_filter filter;
+	int err;
+#ifdef __linux__
+	int csum_offset, sz_opt;
+#endif
+	static uint32_t scope_id = 0;
+
+#ifdef ANDROID
+	android_check_security();
+#endif
+
+	limit_capabilities();
+
+#ifdef USE_IDN
+	setlocale(LC_ALL, "");
+#endif
+
+	icmp_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
+	if (icmp_sock < 0) {
+		enable_capability_raw();
+		icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+		socket_errno = errno;
+		disable_capability_raw();
+		using_ping_socket = 0;
+	}
+
+	source.sin6_family = AF_INET6;
+	memset(&firsthop, 0, sizeof(firsthop));
+	firsthop.sin6_family = AF_INET6;
+
+	preload = 1;
+	while ((ch = getopt(argc, argv, COMMON_OPTSTR "F:N:")) != EOF) {
+		switch(ch) {
+		case 'F':
+			flowlabel = hextoui(optarg);
+			if (errno || (flowlabel & ~IPV6_FLOWINFO_FLOWLABEL)) {
+				fprintf(stderr, "ping: Invalid flowinfo %s\n", optarg);
+				exit(2);
+			}
+			options |= F_FLOWINFO;
+			break;
+		case 'Q':
+			tclass = hextoui(optarg);
+			if (errno || (tclass & ~0xff)) {
+				fprintf(stderr, "ping: Invalid tclass %s\n", optarg);
+				exit(2);
+			}
+			options |= F_TCLASS;
+			break;
+		case 'I':
+			if (strchr(optarg, ':')) {
+				char *p, *addr = strdup(optarg);
+
+				if (!addr) {
+					fprintf(stderr, "ping: out of memory\n");
+					exit(2);
+				}
+
+				p = strchr(addr, SCOPE_DELIMITER);
+				if (p) {
+					*p = '\0';
+					device = optarg + (p - addr) + 1;
+				}
+
+				if (inet_pton(AF_INET6, addr, (char*)&source.sin6_addr) <= 0) {
+					fprintf(stderr, "ping: invalid source address %s\n", optarg);
+					exit(2);
+				}
+
+				options |= F_STRICTSOURCE;
+
+				free(addr);
+			} else {
+				device = optarg;
+			}
+			break;
+		case 'M':
+			if (strcmp(optarg, "do") == 0)
+				pmtudisc = IPV6_PMTUDISC_DO;
+			else if (strcmp(optarg, "dont") == 0)
+				pmtudisc = IPV6_PMTUDISC_DONT;
+			else if (strcmp(optarg, "want") == 0)
+				pmtudisc = IPV6_PMTUDISC_WANT;
+			else {
+				fprintf(stderr, "ping: wrong value for -M: do, dont, want are valid ones.\n");
+				exit(2);
+			}
+			break;
+		case 'V':
+			printf("ping6 utility, iputils-%s\n", SNAPSHOT);
+			exit(0);
+		case 'N':
+			if (using_ping_socket) {
+				fprintf(stderr, "ping: -N requires raw socket permissions\n");
+				exit(2);
+			}
+			if (niquery_option_handler(optarg) < 0) {
+				usage();
+				break;
+			}
+			break;
+		COMMON_OPTIONS
+			common_options(ch);
+			break;
+		default:
+			usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+#ifdef ENABLE_PING6_RTHDR
+	while (argc > 1) {
+		struct in6_addr *addr;
+
+		if (srcrt == NULL) {
+			int space;
+
+			fprintf(stderr, "ping6: Warning: "
+					"Source routing is deprecated by RFC5095.\n");
+
+#ifdef ENABLE_PING6_RTHDR_RFC3542
+			space = inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1);
+#else
+			space = inet6_srcrt_space(IPV6_SRCRT_TYPE_0, argc - 1);
+#endif
+			if (space == 0)	{
+				fprintf(stderr, "srcrt_space failed\n");
+				exit(2);
+			}
+#ifdef ENABLE_PING6_RTHDR_RFC3542
+			if (cmsglen + CMSG_SPACE(space) > sizeof(cmsgbuf)) {
+				fprintf(stderr, "no room for options\n");
+				exit(2);
+			}
+#else
+			if (space + cmsglen > sizeof(cmsgbuf)) {
+				fprintf(stderr, "no room for options\n");
+				exit(2);
+			}
+#endif
+			srcrt = (struct cmsghdr*)(cmsgbuf+cmsglen);
+#ifdef ENABLE_PING6_RTHDR_RFC3542
+			memset(srcrt, 0, CMSG_SPACE(0));
+			srcrt->cmsg_len = CMSG_LEN(space);
+			srcrt->cmsg_level = IPPROTO_IPV6;
+			srcrt->cmsg_type = IPV6_RTHDR;
+			inet6_rth_init(CMSG_DATA(srcrt), space, IPV6_RTHDR_TYPE_0, argc - 1);
+			cmsglen += CMSG_SPACE(space);
+#else
+			cmsglen += CMSG_ALIGN(space);
+			inet6_srcrt_init(srcrt, IPV6_SRCRT_TYPE_0);
+#endif
+		}
+
+		target = *argv;
+
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_family = AF_INET6;
+#ifdef USE_IDN
+		hints.ai_flags = AI_IDN;
+#endif
+		gai = getaddrinfo(target, NULL, &hints, &ai);
+		if (gai) {
+			fprintf(stderr, "unknown host\n");
+			exit(2);
+		}
+		addr = &((struct sockaddr_in6 *)(ai->ai_addr))->sin6_addr;
+#ifdef ENABLE_PING6_RTHDR_RFC3542
+		inet6_rth_add(CMSG_DATA(srcrt), addr);
+#else
+		inet6_srcrt_add(srcrt, addr);
+#endif
+		if (IN6_IS_ADDR_UNSPECIFIED(&firsthop.sin6_addr)) {
+			memcpy(&firsthop.sin6_addr, addr, 16);
+#ifdef HAVE_SIN6_SCOPEID
+			firsthop.sin6_scope_id = ((struct sockaddr_in6 *)(ai->ai_addr))->sin6_scope_id;
+			/* Verify scope_id is the same as previous nodes */
+			if (firsthop.sin6_scope_id && scope_id && firsthop.sin6_scope_id != scope_id) {
+				fprintf(stderr, "scope discrepancy among the nodes\n");
+				exit(2);
+			} else if (!scope_id) {
+				scope_id = firsthop.sin6_scope_id;
+			}
+#endif
+		}
+		freeaddrinfo(ai);
+
+		argv++;
+		argc--;
+	}
+#endif
+
+	if (niquery_is_enabled()) {
+		niquery_init_nonce();
+
+		if (!niquery_is_subject_valid()) {
+			ni_subject = &whereto.sin6_addr;
+			ni_subject_len = sizeof(whereto.sin6_addr);
+			ni_subject_type = NI_SUBJ_IPV6;
+		}
+	}
+
+	if (argc > 1) {
+#ifndef ENABLE_PING6_RTHDR
+		fprintf(stderr, "ping6: Source routing is deprecated by RFC5095.\n");
+#endif
+		usage();
+	} else if (argc == 1) {
+		target = *argv;
+	} else {
+		if (ni_query < 0 && ni_subject_type != NI_SUBJ_NAME)
+			usage();
+		target = ni_group;
+	}
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_INET6;
+#ifdef USE_IDN
+	hints.ai_flags = AI_IDN;
+#endif
+	gai = getaddrinfo(target, NULL, &hints, &ai);
+	if (gai) {
+		fprintf(stderr, "unknown host\n");
+		exit(2);
+	}
+
+	memcpy(&whereto, ai->ai_addr, sizeof(whereto));
+	whereto.sin6_port = htons(IPPROTO_ICMPV6);
+
+	if (memchr(target, ':', strlen(target)))
+		options |= F_NUMERIC;
+
+	freeaddrinfo(ai);
+
+	if (IN6_IS_ADDR_UNSPECIFIED(&firsthop.sin6_addr)) {
+		memcpy(&firsthop.sin6_addr, &whereto.sin6_addr, 16);
+#ifdef HAVE_SIN6_SCOPEID
+		firsthop.sin6_scope_id = whereto.sin6_scope_id;
+		/* Verify scope_id is the same as intermediate nodes */
+		if (firsthop.sin6_scope_id && scope_id && firsthop.sin6_scope_id != scope_id) {
+			fprintf(stderr, "scope discrepancy among the nodes\n");
+			exit(2);
+		} else if (!scope_id) {
+			scope_id = firsthop.sin6_scope_id;
+		}
+#endif
+	}
+
+	hostname = target;
+
+	if (IN6_IS_ADDR_UNSPECIFIED(&source.sin6_addr)) {
+		socklen_t alen;
+		int probe_fd = socket(AF_INET6, SOCK_DGRAM, 0);
+
+		if (probe_fd < 0) {
+			perror("socket");
+			exit(2);
+		}
+		if (device) {
+#if defined(IPV6_RECVPKTINFO) || defined(HAVE_SIN6_SCOPEID)
+			unsigned int iface = if_name2index(device);
+#endif
+#ifdef IPV6_RECVPKTINFO
+			struct in6_pktinfo ipi;
+
+			memset(&ipi, 0, sizeof(ipi));
+			ipi.ipi6_ifindex = iface;
+#endif
+
+#ifdef HAVE_SIN6_SCOPEID
+			if (IN6_IS_ADDR_LINKLOCAL(&firsthop.sin6_addr) ||
+			    IN6_IS_ADDR_MC_LINKLOCAL(&firsthop.sin6_addr))
+				firsthop.sin6_scope_id = iface;
+#endif
+			enable_capability_raw();
+			if (
+#ifdef IPV6_RECVPKTINFO
+			    setsockopt(probe_fd, IPPROTO_IPV6, IPV6_PKTINFO, &ipi, sizeof(ipi)) == -1 &&
+#endif
+			    setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1) {
+				perror("setsockopt(SO_BINDTODEVICE)");
+				exit(2);
+			}
+			disable_capability_raw();
+		}
+		firsthop.sin6_port = htons(1025);
+
+		sock_setmark(probe_fd);
+
+		if (connect(probe_fd, (struct sockaddr*)&firsthop, sizeof(firsthop)) == -1) {
+			perror("connect");
+			exit(2);
+		}
+		alen = sizeof(source);
+		if (getsockname(probe_fd, (struct sockaddr*)&source, &alen) == -1) {
+			perror("getsockname");
+			exit(2);
+		}
+		source.sin6_port = 0;
+		close(probe_fd);
+
+#ifndef WITHOUT_IFADDRS
+		if (device) {
+			struct ifaddrs *ifa0, *ifa;
+
+			if (getifaddrs(&ifa0)) {
+				perror("getifaddrs");
+				exit(2);
+			}
+
+			for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
+				if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6)
+					continue;
+				if (!strncmp(ifa->ifa_name, device, sizeof(device) - 1) &&
+				    IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
+						       &source.sin6_addr))
+					break;
+			}
+			if (!ifa)
+				fprintf(stderr, "ping6: Warning: source address might be selected on device other than %s.\n", device);
+
+			freeifaddrs(ifa0);
+		}
+#endif
+	}
+#ifdef HAVE_SIN6_SCOPEID
+	else if (device && (IN6_IS_ADDR_LINKLOCAL(&source.sin6_addr) ||
+			    IN6_IS_ADDR_MC_LINKLOCAL(&source.sin6_addr)))
+		source.sin6_scope_id = if_name2index(device);
+#endif
+
+	if (icmp_sock < 0) {
+		errno = socket_errno;
+		perror("ping: icmp open socket");
+		exit(2);
+	}
+
+	if (device) {
+		struct cmsghdr *cmsg;
+		struct in6_pktinfo *ipi;
+
+		cmsg = (struct cmsghdr*)(cmsgbuf+cmsglen);
+		cmsglen += CMSG_SPACE(sizeof(*ipi));
+		cmsg->cmsg_len = CMSG_LEN(sizeof(*ipi));
+		cmsg->cmsg_level = SOL_IPV6;
+		cmsg->cmsg_type = IPV6_PKTINFO;
+
+		ipi = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+		memset(ipi, 0, sizeof(*ipi));
+		ipi->ipi6_ifindex = if_name2index(device);
+	}
+
+	if ((whereto.sin6_addr.s6_addr16[0]&htons(0xff00)) == htons (0xff00)) {
+		if (uid) {
+			if (interval < 1000) {
+				fprintf(stderr, "ping: multicast ping with too short interval.\n");
+				exit(2);
+			}
+			if (pmtudisc >= 0 && pmtudisc != IPV6_PMTUDISC_DO) {
+				fprintf(stderr, "ping: multicast ping does not fragment.\n");
+				exit(2);
+			}
+		}
+		if (pmtudisc < 0)
+			pmtudisc = IPV6_PMTUDISC_DO;
+	}
+
+	if (pmtudisc >= 0) {
+		if (setsockopt(icmp_sock, SOL_IPV6, IPV6_MTU_DISCOVER, &pmtudisc, sizeof(pmtudisc)) == -1) {
+			perror("ping: IPV6_MTU_DISCOVER");
+			exit(2);
+		}
+	}
+
+	if ((options&F_STRICTSOURCE) &&
+	    bind(icmp_sock, (struct sockaddr*)&source, sizeof(source)) == -1) {
+		perror("ping: bind icmp socket");
+		exit(2);
+	}
+
+	if (datalen >= sizeof(struct timeval) && (ni_query < 0)) {
+		/* can we time transfer */
+		timing = 1;
+	}
+	packlen = datalen + 8 + 4096 + 40 + 8; /* 4096 for rthdr */
+	if (!(packet = (u_char *)malloc((u_int)packlen))) {
+		fprintf(stderr, "ping: out of memory.\n");
+		exit(2);
+	}
+
+	working_recverr = 1;
+	hold = 1;
+	if (setsockopt(icmp_sock, SOL_IPV6, IPV6_RECVERR, (char *)&hold, sizeof(hold))) {
+		fprintf(stderr, "WARNING: your kernel is veeery old. No problems.\n");
+		working_recverr = 0;
+	}
+
+	/* Estimate memory eaten by single packet. It is rough estimate.
+	 * Actually, for small datalen's it depends on kernel side a lot. */
+	hold = datalen+8;
+	hold += ((hold+511)/512)*(40+16+64+160);
+	sock_setbufs(icmp_sock, hold);
+
+	if (!using_ping_socket) {
+#ifdef __linux__
+		csum_offset = 2;
+		sz_opt = sizeof(int);
+
+		err = setsockopt(icmp_sock, SOL_RAW, IPV6_CHECKSUM,
+				 &csum_offset, sz_opt);
+		if (err < 0) {
+			/* checksum should be enabled by default and setting
+			 * this option might fail anyway.
+			 */
+			fprintf(stderr, "setsockopt(RAW_CHECKSUM) failed"
+				" - try to continue.");
+		}
+#endif
+
+		/*
+		 *	select icmp echo reply as icmp type to receive
+		 */
+
+		ICMP6_FILTER_SETBLOCKALL(&filter);
+
+		if (!working_recverr) {
+			ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &filter);
+			ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &filter);
+			ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &filter);
+			ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &filter);
+		}
+
+		if (niquery_is_enabled())
+			ICMP6_FILTER_SETPASS(ICMPV6_NI_REPLY, &filter);
+		else
+			ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
+
+		err = setsockopt(icmp_sock, IPPROTO_ICMPV6, ICMP6_FILTER,
+				 &filter, sizeof(struct icmp6_filter));
+
+		if (err < 0) {
+			perror("setsockopt(ICMP6_FILTER)");
+			exit(2);
+		}
+	}
+
+	if (options & F_NOLOOP) {
+		int loop = 0;
+		if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
+				&loop, sizeof(loop)) == -1) {
+			perror ("can't disable multicast loopback");
+			exit(2);
+		}
+	}
+	if (options & F_TTL) {
+		if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+			       &ttl, sizeof(ttl)) == -1) {
+			perror ("can't set multicast hop limit");
+			exit(2);
+		}
+		if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
+			       &ttl, sizeof(ttl)) == -1) {
+			perror ("can't set unicast hop limit");
+			exit(2);
+		}
+	}
+
+	if (1) {
+		int on = 1;
+		if (
+#ifdef IPV6_RECVHOPLIMIT
+		    setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
+			       &on, sizeof(on)) == -1 &&
+		    setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_2292HOPLIMIT,
+			       &on, sizeof(on)) == -1
+#else
+		    setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_HOPLIMIT,
+			       &on, sizeof(on)) == -1
+#endif
+		   ){
+			perror ("can't receive hop limit");
+			exit(2);
+		}
+	}
+
+	if (options & F_TCLASS) {
+#ifdef IPV6_TCLASS
+		if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_TCLASS,
+			       &tclass, sizeof(tclass)) == -1) {
+			perror ("setsockopt(IPV6_TCLASS)");
+			exit(2);
+		}
+#else
+		fprintf(stderr, "Traffic class is not supported.\n");
+#endif
+	}
+
+	if (options&F_FLOWINFO) {
+#ifdef IPV6_FLOWINFO_SEND
+		int on = 1;
+#endif
+#ifdef IPV6_FLOWLABEL_MGR
+		char freq_buf[CMSG_ALIGN(sizeof(struct in6_flowlabel_req)) + cmsglen];
+		struct in6_flowlabel_req *freq = (struct in6_flowlabel_req *)freq_buf;
+		int freq_len = sizeof(*freq);
+#ifdef ENABLE_PING6_RTHDR
+		if (srcrt)
+			freq_len = CMSG_ALIGN(sizeof(*freq)) + srcrt->cmsg_len;
+#endif
+		memset(freq, 0, sizeof(*freq));
+		freq->flr_label = htonl(flowlabel & IPV6_FLOWINFO_FLOWLABEL);
+		freq->flr_action = IPV6_FL_A_GET;
+		freq->flr_flags = IPV6_FL_F_CREATE;
+		freq->flr_share = IPV6_FL_S_EXCL;
+		memcpy(&freq->flr_dst, &whereto.sin6_addr, 16);
+#ifdef ENABLE_PING6_RTHDR
+		if (srcrt)
+			memcpy(freq_buf + CMSG_ALIGN(sizeof(*freq)), srcrt, srcrt->cmsg_len);
+#endif
+		if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR,
+			       freq, freq_len) == -1) {
+			perror ("can't set flowlabel");
+			exit(2);
+		}
+		flowlabel = freq->flr_label;
+#ifdef ENABLE_PING6_RTHDR
+		if (srcrt) {
+			cmsglen = (char*)srcrt - (char*)cmsgbuf;
+			srcrt = NULL;
+		}
+#endif
+#else
+		fprintf(stderr, "Flow labels are not supported.\n");
+		exit(2);
+#endif
+
+#ifdef IPV6_FLOWINFO_SEND
+		whereto.sin6_flowinfo = flowlabel;
+		if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_FLOWINFO_SEND,
+			       &on, sizeof(on)) == -1) {
+			perror ("can't send flowinfo");
+			exit(2);
+		}
+#else
+		fprintf(stderr, "Flowinfo is not supported.\n");
+		exit(2);
+#endif
+	}
+
+	printf("PING %s(%s) ", hostname, pr_addr(&whereto.sin6_addr));
+	if (flowlabel)
+		printf(", flow 0x%05x, ", (unsigned)ntohl(flowlabel));
+	if (device || (options&F_STRICTSOURCE)) {
+		printf("from %s %s: ",
+		       pr_addr_n(&source.sin6_addr), device ? : "");
+	}
+	printf("%d data bytes\n", datalen);
+
+	setup(icmp_sock);
+
+	drop_capabilities();
+
+	main_loop(icmp_sock, packet, packlen);
+}
+
+int receive_error_msg()
+{
+	int res;
+	char cbuf[512];
+	struct iovec  iov;
+	struct msghdr msg;
+	struct cmsghdr *cmsg;
+	struct sock_extended_err *e;
+	struct icmp6_hdr icmph;
+	struct sockaddr_in6 target;
+	int net_errors = 0;
+	int local_errors = 0;
+	int saved_errno = errno;
+
+	iov.iov_base = &icmph;
+	iov.iov_len = sizeof(icmph);
+	msg.msg_name = (void*)&target;
+	msg.msg_namelen = sizeof(target);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_flags = 0;
+	msg.msg_control = cbuf;
+	msg.msg_controllen = sizeof(cbuf);
+
+	res = recvmsg(icmp_sock, &msg, MSG_ERRQUEUE|MSG_DONTWAIT);
+	if (res < 0)
+		goto out;
+
+	e = NULL;
+	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+		if (cmsg->cmsg_level == SOL_IPV6) {
+			if (cmsg->cmsg_type == IPV6_RECVERR)
+				e = (struct sock_extended_err *)CMSG_DATA(cmsg);
+		}
+	}
+	if (e == NULL)
+		abort();
+
+	if (e->ee_origin == SO_EE_ORIGIN_LOCAL) {
+		local_errors++;
+		if (options & F_QUIET)
+			goto out;
+		if (options & F_FLOOD)
+			write_stdout("E", 1);
+		else if (e->ee_errno != EMSGSIZE)
+			fprintf(stderr, "ping: local error: %s\n", strerror(e->ee_errno));
+		else
+			fprintf(stderr, "ping: local error: Message too long, mtu=%u\n", e->ee_info);
+		nerrors++;
+	} else if (e->ee_origin == SO_EE_ORIGIN_ICMP6) {
+		struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)(e+1);
+
+		if (res < sizeof(icmph) ||
+		    memcmp(&target.sin6_addr, &whereto.sin6_addr, 16) ||
+		    icmph.icmp6_type != ICMP6_ECHO_REQUEST ||
+		    !is_ours(icmph.icmp6_id)) {
+			/* Not our error, not an error at all. Clear. */
+			saved_errno = 0;
+			goto out;
+		}
+
+		net_errors++;
+		nerrors++;
+		if (options & F_QUIET)
+			goto out;
+		if (options & F_FLOOD) {
+			write_stdout("\bE", 2);
+		} else {
+			print_timestamp();
+			printf("From %s icmp_seq=%u ", pr_addr(&sin6->sin6_addr), ntohs(icmph.icmp6_seq));
+			pr_icmph(e->ee_type, e->ee_code, e->ee_info);
+			putchar('\n');
+			fflush(stdout);
+		}
+	}
+
+out:
+	errno = saved_errno;
+	return net_errors ? : -local_errors;
+}
+
+/*
+ * pinger --
+ * 	Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
+ * will be added on by the kernel.  The ID field is our UNIX process ID,
+ * and the sequence number is an ascending integer.  The first 8 bytes
+ * of the data portion are used to hold a UNIX "timeval" struct in VAX
+ * byte-order, to compute the round-trip time.
+ */
+int build_echo(__u8 *_icmph)
+{
+	struct icmp6_hdr *icmph;
+	int cc;
+
+	icmph = (struct icmp6_hdr *)_icmph;
+	icmph->icmp6_type = ICMP6_ECHO_REQUEST;
+	icmph->icmp6_code = 0;
+	icmph->icmp6_cksum = 0;
+	icmph->icmp6_seq = htons(ntransmitted+1);
+	icmph->icmp6_id = ident;
+
+	if (timing)
+		gettimeofday((struct timeval *)&outpack[8],
+		    (struct timezone *)NULL);
+
+	cc = datalen + 8;			/* skips ICMP portion */
+
+	return cc;
+}
+
+
+int build_niquery(__u8 *_nih)
+{
+	struct ni_hdr *nih;
+	int cc;
+
+	nih = (struct ni_hdr *)_nih;
+	nih->ni_cksum = 0;
+
+	nih->ni_type = ICMPV6_NI_QUERY;
+	cc = sizeof(*nih);
+	datalen = 0;
+
+	niquery_fill_nonce(ntransmitted + 1, nih->ni_nonce);
+	nih->ni_code = ni_subject_type;
+	nih->ni_qtype = htons(ni_query);
+	nih->ni_flags = ni_flag;
+	memcpy(nih + 1, ni_subject, ni_subject_len);
+	cc += ni_subject_len;
+
+	return cc;
+}
+
+int send_probe(void)
+{
+	int len, cc;
+
+	rcvd_clear(ntransmitted + 1);
+
+	if (niquery_is_enabled())
+		len = build_niquery(outpack);
+	else
+		len = build_echo(outpack);
+
+	if (cmsglen == 0) {
+		cc = sendto(icmp_sock, (char *)outpack, len, confirm,
+			    (struct sockaddr *) &whereto,
+			    sizeof(struct sockaddr_in6));
+	} else {
+		struct msghdr mhdr;
+		struct iovec iov;
+
+		iov.iov_len  = len;
+		iov.iov_base = outpack;
+
+		memset(&mhdr, 0, sizeof(mhdr));
+		mhdr.msg_name = &whereto;
+		mhdr.msg_namelen = sizeof(struct sockaddr_in6);
+		mhdr.msg_iov = &iov;
+		mhdr.msg_iovlen = 1;
+		mhdr.msg_control = cmsgbuf;
+		mhdr.msg_controllen = cmsglen;
+
+		cc = sendmsg(icmp_sock, &mhdr, confirm);
+	}
+	confirm = 0;
+
+	return (cc == len ? 0 : cc);
+}
+
+void pr_echo_reply(__u8 *_icmph, int cc)
+{
+	struct icmp6_hdr *icmph = (struct icmp6_hdr *) _icmph;
+	printf(" icmp_seq=%u", ntohs(icmph->icmp6_seq));
+};
+
+static void putchar_safe(char c)
+{
+	if (isprint(c))
+		putchar(c);
+	else
+		printf("\\%03o", c);
+}
+
+void pr_niquery_reply_name(struct ni_hdr *nih, int len)
+{
+	__u8 *h = (__u8 *)(nih + 1);
+	__u8 *p = h + 4;
+	__u8 *end = (__u8 *)nih + len;
+	int continued = 0;
+	char buf[1024];
+	int ret;
+
+	len -= sizeof(struct ni_hdr) + 4;
+
+	if (len < 0) {
+		printf(" parse error (too short)");
+		return;
+	}
+	while (p < end) {
+		int fqdn = 1;
+		int i;
+
+		memset(buf, 0xff, sizeof(buf));
+
+		if (continued)
+			putchar(',');
+
+		ret = dn_expand(h, end, p, buf, sizeof(buf));
+		if (ret < 0) {
+			printf(" parse error (truncated)");
+			break;
+		}
+		if (p + ret < end && *(p + ret) == '\0')
+			fqdn = 0;
+
+		putchar(' ');
+		for (i = 0; i < strlen(buf); i++)
+			putchar_safe(buf[i]);
+		if (fqdn)
+			putchar('.');
+
+		p += ret + !fqdn;
+
+		continued = 1;
+	}
+}
+
+void pr_niquery_reply_addr(struct ni_hdr *nih, int len)
+{
+	__u8 *h = (__u8 *)(nih + 1);
+	__u8 *p = h + 4;
+	__u8 *end = (__u8 *)nih + len;
+	int af;
+	int aflen;
+	int continued = 0;
+	int truncated;
+	char buf[1024];
+
+	switch (ntohs(nih->ni_qtype)) {
+	case NI_QTYPE_IPV4ADDR:
+		af = AF_INET;
+		aflen = sizeof(struct in_addr);
+		truncated = nih->ni_flags & NI_IPV6ADDR_F_TRUNCATE;
+		break;
+	case NI_QTYPE_IPV6ADDR:
+		af = AF_INET6;
+		aflen = sizeof(struct in6_addr);
+		truncated = nih->ni_flags & NI_IPV4ADDR_F_TRUNCATE;
+		break;
+	default:
+		/* should not happen */
+		af = aflen = truncated = 0;
+	}
+	p = h;
+	if (len < 0) {
+		printf(" parse error (too short)");
+		return;
+	}
+
+	while (p < end) {
+		if (continued)
+			putchar(',');
+
+		if (p + sizeof(__u32) + aflen > end) {
+			printf(" parse error (truncated)");
+			break;
+		}
+		if (!inet_ntop(af, p + sizeof(__u32), buf, sizeof(buf)))
+			printf(" unexpeced error in inet_ntop(%s)",
+			       strerror(errno));
+		else
+			printf(" %s", buf);
+		p += sizeof(__u32) + aflen;
+
+		continued = 1;
+	}
+	if (truncated)
+		printf(" (truncated)");
+}
+
+void pr_niquery_reply(__u8 *_nih, int len)
+{
+	struct ni_hdr *nih = (struct ni_hdr *)_nih;
+
+	switch (nih->ni_code) {
+	case NI_SUCCESS:
+		switch (ntohs(nih->ni_qtype)) {
+		case NI_QTYPE_NAME:
+			pr_niquery_reply_name(nih, len);
+			break;
+		case NI_QTYPE_IPV4ADDR:
+		case NI_QTYPE_IPV6ADDR:
+			pr_niquery_reply_addr(nih, len);
+			break;
+		default:
+			printf(" unknown qtype(0x%02x)", ntohs(nih->ni_qtype));
+		}
+		break;
+	case NI_REFUSED:
+		printf(" refused");
+		break;
+	case NI_UNKNOWN:
+		printf(" unknown");
+		break;
+	default:
+		printf(" unknown code(%02x)", ntohs(nih->ni_code));
+	}
+	printf("; seq=%u;", ntohsp((__u16*)nih->ni_nonce));
+}
+
+/*
+ * parse_reply --
+ *	Print out the packet, if it came from us.  This logic is necessary
+ * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
+ * which arrive ('tis only fair).  This permits multiple copies of this
+ * program to be run without having intermingled output (or statistics!).
+ */
+int
+parse_reply(struct msghdr *msg, int cc, void *addr, struct timeval *tv)
+{
+	struct sockaddr_in6 *from = addr;
+	__u8 *buf = msg->msg_iov->iov_base;
+	struct cmsghdr *c;
+	struct icmp6_hdr *icmph;
+	int hops = -1;
+
+	for (c = CMSG_FIRSTHDR(msg); c; c = CMSG_NXTHDR(msg, c)) {
+		if (c->cmsg_level != SOL_IPV6)
+			continue;
+		switch(c->cmsg_type) {
+		case IPV6_HOPLIMIT:
+#ifdef IPV6_2292HOPLIMIT
+		case IPV6_2292HOPLIMIT:
+#endif
+			if (c->cmsg_len < CMSG_LEN(sizeof(int)))
+				continue;
+			memcpy(&hops, CMSG_DATA(c), sizeof(hops));
+		}
+	}
+
+
+	/* Now the ICMP part */
+
+	icmph = (struct icmp6_hdr *) buf;
+	if (cc < 8) {
+		if (options & F_VERBOSE)
+			fprintf(stderr, "ping: packet too short (%d bytes)\n", cc);
+		return 1;
+	}
+
+	if (icmph->icmp6_type == ICMP6_ECHO_REPLY) {
+		if (!is_ours(icmph->icmp6_id))
+			return 1;
+		if (gather_statistics((__u8*)icmph, sizeof(*icmph), cc,
+				      ntohs(icmph->icmp6_seq),
+				      hops, 0, tv, pr_addr(&from->sin6_addr),
+				      pr_echo_reply))
+			return 0;
+	} else if (icmph->icmp6_type == ICMPV6_NI_REPLY) {
+		struct ni_hdr *nih = (struct ni_hdr *)icmph;
+		int seq = niquery_check_nonce(nih->ni_nonce);
+		if (seq < 0)
+			return 1;
+		if (gather_statistics((__u8*)icmph, sizeof(*icmph), cc,
+				      seq,
+				      hops, 0, tv, pr_addr(&from->sin6_addr),
+				      pr_niquery_reply))
+			return 0;
+	} else {
+		int nexthdr;
+		struct ip6_hdr *iph1 = (struct ip6_hdr*)(icmph+1);
+		struct icmp6_hdr *icmph1 = (struct icmp6_hdr *)(iph1+1);
+
+		/* We must not ever fall here. All the messages but
+		 * echo reply are blocked by filter and error are
+		 * received with IPV6_RECVERR. Ugly code is preserved
+		 * however, just to remember what crap we avoided
+		 * using RECVRERR. :-)
+		 */
+
+		if (cc < 8+sizeof(struct ip6_hdr)+8)
+			return 1;
+
+		if (memcmp(&iph1->ip6_dst, &whereto.sin6_addr, 16))
+			return 1;
+
+		nexthdr = iph1->ip6_nxt;
+
+		if (nexthdr == 44) {
+			nexthdr = *(__u8*)icmph1;
+			icmph1++;
+		}
+		if (nexthdr == IPPROTO_ICMPV6) {
+			if (icmph1->icmp6_type != ICMP6_ECHO_REQUEST ||
+			    !is_ours(icmph1->icmp6_id))
+				return 1;
+			acknowledge(ntohs(icmph1->icmp6_seq));
+			if (working_recverr)
+				return 0;
+			nerrors++;
+			if (options & F_FLOOD) {
+				write_stdout("\bE", 2);
+				return 0;
+			}
+			print_timestamp();
+			printf("From %s: icmp_seq=%u ", pr_addr(&from->sin6_addr), ntohs(icmph1->icmp6_seq));
+		} else {
+			/* We've got something other than an ECHOREPLY */
+			if (!(options & F_VERBOSE) || uid)
+				return 1;
+			print_timestamp();
+			printf("From %s: ", pr_addr(&from->sin6_addr));
+		}
+		pr_icmph(icmph->icmp6_type, icmph->icmp6_code, ntohl(icmph->icmp6_mtu));
+	}
+
+	if (!(options & F_FLOOD)) {
+		if (options & F_AUDIBLE)
+			putchar('\a');
+		putchar('\n');
+		fflush(stdout);
+	} else {
+		putchar('\a');
+		fflush(stdout);
+	}
+	return 0;
+}
+
+
+int pr_icmph(__u8 type, __u8 code, __u32 info)
+{
+	switch(type) {
+	case ICMP6_DST_UNREACH:
+		printf("Destination unreachable: ");
+		switch (code) {
+		case ICMP6_DST_UNREACH_NOROUTE:
+			printf("No route");
+			break;
+		case ICMP6_DST_UNREACH_ADMIN:
+			printf("Administratively prohibited");
+			break;
+		case ICMP6_DST_UNREACH_BEYONDSCOPE:
+			printf("Beyond scope of source address");
+			break;
+		case ICMP6_DST_UNREACH_ADDR:
+			printf("Address unreachable");
+			break;
+		case ICMP6_DST_UNREACH_NOPORT:
+			printf("Port unreachable");
+			break;
+		default:
+			printf("Unknown code %d", code);
+			break;
+		}
+		break;
+	case ICMP6_PACKET_TOO_BIG:
+		printf("Packet too big: mtu=%u", info);
+		if (code)
+			printf(", code=%d", code);
+		break;
+	case ICMP6_TIME_EXCEEDED:
+		printf("Time exceeded: ");
+		if (code == ICMP6_TIME_EXCEED_TRANSIT)
+			printf("Hop limit");
+		else if (code == ICMP6_TIME_EXCEED_REASSEMBLY)
+			printf("Defragmentation failure");
+		else
+			printf("code %d", code);
+		break;
+	case ICMP6_PARAM_PROB:
+		printf("Parameter problem: ");
+		if (code == ICMP6_PARAMPROB_HEADER)
+			printf("Wrong header field ");
+		else if (code == ICMP6_PARAMPROB_NEXTHEADER)
+			printf("Unknown header ");
+		else if (code == ICMP6_PARAMPROB_OPTION)
+			printf("Unknown option ");
+		else
+			printf("code %d ", code);
+		printf ("at %u", info);
+		break;
+	case ICMP6_ECHO_REQUEST:
+		printf("Echo request");
+		break;
+	case ICMP6_ECHO_REPLY:
+		printf("Echo reply");
+		break;
+	case MLD_LISTENER_QUERY:
+		printf("MLD Query");
+		break;
+	case MLD_LISTENER_REPORT:
+		printf("MLD Report");
+		break;
+	case MLD_LISTENER_REDUCTION:
+		printf("MLD Reduction");
+		break;
+	default:
+		printf("unknown icmp type: %u", type);
+
+	}
+	return 0;
+}
+
+#include <linux/filter.h>
+
+void install_filter(void)
+{
+	static int once;
+	static struct sock_filter insns[] = {
+		BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 4),  /* Load icmp echo ident */
+		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xAAAA, 0, 1),  /* Ours? */
+		BPF_STMT(BPF_RET|BPF_K, ~0U),  /* Yes, it passes. */
+		BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0),  /* Load icmp type */
+		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ICMP6_ECHO_REPLY, 1, 0), /* Echo? */
+		BPF_STMT(BPF_RET|BPF_K, ~0U), /* No. It passes. This must not happen. */
+		BPF_STMT(BPF_RET|BPF_K, 0), /* Echo with wrong ident. Reject. */
+	};
+	static struct sock_fprog filter = {
+		sizeof insns / sizeof(insns[0]),
+		insns
+	};
+
+	if (once)
+		return;
+	once = 1;
+
+	/* Patch bpflet for current identifier. */
+	insns[1] = (struct sock_filter)BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(ident), 0, 1);
+
+	if (setsockopt(icmp_sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)))
+		perror("WARNING: failed to install socket filter\n");
+}
+
+
+/*
+ * pr_addr --
+ *	Return an ascii host address as a dotted quad and optionally with
+ * a hostname.
+ */
+char * pr_addr(struct in6_addr *addr)
+{
+	struct hostent *hp = NULL;
+	static char *s;
+
+#ifdef USE_IDN
+	free(s);
+#endif
+
+	in_pr_addr = !setjmp(pr_addr_jmp);
+
+	if (!(exiting || options&F_NUMERIC))
+		hp = gethostbyaddr((__u8*)addr, sizeof(struct in6_addr), AF_INET6);
+
+	in_pr_addr = 0;
+
+	if (!hp
+#ifdef USE_IDN
+	    || idna_to_unicode_lzlz(hp->h_name, &s, 0) != IDNA_SUCCESS
+#endif
+	    )
+		s = NULL;
+
+	return hp ? (s ? s : hp->h_name) : pr_addr_n(addr);
+}
+
+char * pr_addr_n(struct in6_addr *addr)
+{
+	static char str[64];
+	inet_ntop(AF_INET6, addr, str, sizeof(str));
+	return str;
+}
+
+#define USAGE_NEWLINE	"\n            "
+
+void usage(void)
+{
+	fprintf(stderr,
+		"Usage: ping6"
+		" [-"
+			"aAbBdDfhLnOqrRUvV"
+		"]"
+		" [-c count]"
+		" [-i interval]"
+		" [-I interface]"
+		USAGE_NEWLINE
+		" [-l preload]"
+		" [-m mark]"
+		" [-M pmtudisc_option]"
+		USAGE_NEWLINE
+		" [-N nodeinfo_option]"
+		" [-p pattern]"
+		" [-Q tclass]"
+		" [-s packetsize]"
+		USAGE_NEWLINE
+		" [-S sndbuf]"
+		" [-t ttl]"
+		" [-T timestamp_option]"
+		" [-w deadline]"
+		USAGE_NEWLINE
+		" [-W timeout]"
+#ifdef ENABLE_PING6_RTHDR
+		" [hop1 ...]"
+#endif
+		" destination"
+		"\n"
+	);
+	exit(2);
+}
diff --git a/iputils/ping6_niquery.h b/iputils/ping6_niquery.h
new file mode 100644
index 0000000..fa6624a
--- /dev/null
+++ b/iputils/ping6_niquery.h
@@ -0,0 +1,49 @@
+#include <asm/byteorder.h>
+
+#define NI_NONCE_SIZE			8
+
+/* Node Information Query */
+struct ni_hdr {
+	struct icmp6_hdr		ni_u;
+	__u8				ni_nonce[NI_NONCE_SIZE];
+};
+
+#define ni_type		ni_u.icmp6_type
+#define ni_code		ni_u.icmp6_code
+#define ni_cksum	ni_u.icmp6_cksum
+#define ni_qtype	ni_u.icmp6_data16[0]
+#define ni_flags	ni_u.icmp6_data16[1]
+
+/* Types */
+#ifndef ICMPV6_NI_QUERY
+# define ICMPV6_NI_QUERY		139
+# define ICMPV6_NI_REPLY		140
+#endif
+
+/* Query Codes */
+#define NI_SUBJ_IPV6			0
+#define NI_SUBJ_NAME			1
+#define NI_SUBJ_IPV4			2
+
+/* Reply Codes */
+#define NI_SUCCESS			0
+#define NI_REFUSED			1
+#define NI_UNKNOWN			2
+
+/* Qtypes */
+#define NI_QTYPE_NOOP			0
+#define NI_QTYPE_NAME			2
+#define NI_QTYPE_IPV6ADDR		3
+#define NI_QTYPE_IPV4ADDR		4
+
+/* Flags */
+#define NI_IPV6ADDR_F_TRUNCATE		__constant_cpu_to_be16(0x0001)
+#define NI_IPV6ADDR_F_ALL		__constant_cpu_to_be16(0x0002)
+#define NI_IPV6ADDR_F_COMPAT		__constant_cpu_to_be16(0x0004)
+#define NI_IPV6ADDR_F_LINKLOCAL		__constant_cpu_to_be16(0x0008)
+#define NI_IPV6ADDR_F_SITELOCAL		__constant_cpu_to_be16(0x0010)
+#define NI_IPV6ADDR_F_GLOBAL		__constant_cpu_to_be16(0x0020)
+
+#define NI_IPV4ADDR_F_TRUNCATE		NI_IPV6ADDR_F_TRUNCATE
+#define NI_IPV4ADDR_F_ALL		NI_IPV6ADDR_F_ALL
+
diff --git a/iputils/ping_common.c b/iputils/ping_common.c
new file mode 100644
index 0000000..cc9342d
--- /dev/null
+++ b/iputils/ping_common.c
@@ -0,0 +1,1093 @@
+#include "ping_common.h"
+#include <ctype.h>
+#include <sched.h>
+#include <math.h>
+
+int options;
+
+__u32 mark;
+int sndbuf;
+int ttl;
+int rtt;
+int rtt_addend;
+__u16 acked;
+
+struct rcvd_table rcvd_tbl;
+int using_ping_socket = 1;
+
+
+/* counters */
+long npackets;			/* max packets to transmit */
+long nreceived;			/* # of packets we got back */
+long nrepeats;			/* number of duplicates */
+long ntransmitted;		/* sequence # for outbound packets = #sent */
+long nchecksum;			/* replies with bad checksum */
+long nerrors;			/* icmp errors */
+int interval = 1000;		/* interval between packets (msec) */
+int preload;
+int deadline = 0;		/* time to die */
+int lingertime = MAXWAIT*1000;
+struct timeval start_time, cur_time;
+volatile int exiting;
+volatile int status_snapshot;
+int confirm = 0;
+volatile int in_pr_addr = 0;	/* pr_addr() is executing */
+jmp_buf pr_addr_jmp;
+
+/* Stupid workarounds for bugs/missing functionality in older linuces.
+ * confirm_flag fixes refusing service of kernels without MSG_CONFIRM.
+ * i.e. for linux-2.2 */
+int confirm_flag = MSG_CONFIRM;
+/* And this is workaround for bug in IP_RECVERR on raw sockets which is present
+ * in linux-2.2.[0-19], linux-2.4.[0-7] */
+int working_recverr;
+
+/* timing */
+int timing;			/* flag to do timing */
+long tmin = LONG_MAX;		/* minimum round trip time */
+long tmax;			/* maximum round trip time */
+/* Message for rpm maintainers: have _shame_. If you want
+ * to fix something send the patch to me for sanity checking.
+ * "sparcfix" patch is a complete non-sense, apparenly the person
+ * prepared it was stoned.
+ */
+long long tsum;			/* sum of all times, for doing average */
+long long tsum2;
+int  pipesize = -1;
+
+int datalen = DEFDATALEN;
+
+char *hostname;
+int uid;
+uid_t euid;
+int ident = 0;			/* process id to identify our packets */
+
+static int screen_width = INT_MAX;
+
+#define ARRAY_SIZE(a)	(sizeof(a) / sizeof(a[0]))
+
+#ifdef CAPABILITIES
+static cap_value_t cap_raw = CAP_NET_RAW;
+static cap_value_t cap_admin = CAP_NET_ADMIN;
+#endif
+
+void limit_capabilities(void)
+{
+#ifdef CAPABILITIES
+	cap_t cap_cur_p;
+	cap_t cap_p;
+	cap_flag_value_t cap_ok;
+
+	cap_cur_p = cap_get_proc();
+	if (!cap_cur_p) {
+		perror("ping: cap_get_proc");
+		exit(-1);
+	}
+
+	cap_p = cap_init();
+	if (!cap_p) {
+		perror("ping: cap_init");
+		exit(-1);
+	}
+
+	cap_ok = CAP_CLEAR;
+	cap_get_flag(cap_cur_p, CAP_NET_ADMIN, CAP_PERMITTED, &cap_ok);
+
+	if (cap_ok != CAP_CLEAR)
+		cap_set_flag(cap_p, CAP_PERMITTED, 1, &cap_admin, CAP_SET);
+
+	cap_ok = CAP_CLEAR;
+	cap_get_flag(cap_cur_p, CAP_NET_RAW, CAP_PERMITTED, &cap_ok);
+
+	if (cap_ok != CAP_CLEAR)
+		cap_set_flag(cap_p, CAP_PERMITTED, 1, &cap_raw, CAP_SET);
+
+	if (cap_set_proc(cap_p) < 0) {
+		perror("ping: cap_set_proc");
+		exit(-1);
+	}
+
+	if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+		perror("ping: prctl");
+		exit(-1);
+	}
+
+	if (setuid(getuid()) < 0) {
+		perror("setuid");
+		exit(-1);
+	}
+
+	if (prctl(PR_SET_KEEPCAPS, 0) < 0) {
+		perror("ping: prctl");
+		exit(-1);
+	}
+
+	cap_free(cap_p);
+	cap_free(cap_cur_p);
+#endif
+	uid = getuid();
+	euid = geteuid();
+#ifndef CAPABILITIES
+	if (seteuid(uid)) {
+		perror("ping: setuid");
+		exit(-1);
+	}
+#endif
+}
+
+#ifdef CAPABILITIES
+int modify_capability(cap_value_t cap, cap_flag_value_t on)
+{
+	cap_t cap_p = cap_get_proc();
+	cap_flag_value_t cap_ok;
+	int rc = -1;
+
+	if (!cap_p) {
+		perror("ping: cap_get_proc");
+		goto out;
+	}
+
+	cap_ok = CAP_CLEAR;
+	cap_get_flag(cap_p, cap, CAP_PERMITTED, &cap_ok);
+	if (cap_ok == CAP_CLEAR) {
+		rc = on ? -1 : 0;
+		goto out;
+	}
+
+	cap_set_flag(cap_p, CAP_EFFECTIVE, 1, &cap, on);
+
+	if (cap_set_proc(cap_p) < 0) {
+		perror("ping: cap_set_proc");
+		goto out;
+	}
+
+	cap_free(cap_p);
+
+	rc = 0;
+out:
+	if (cap_p)
+		cap_free(cap_p);
+	return rc;
+}
+#else
+int modify_capability(int on)
+{
+	if (seteuid(on ? euid : getuid())) {
+		perror("seteuid");
+		return -1;
+	}
+
+	return 0;
+}
+#endif
+
+void drop_capabilities(void)
+{
+#ifdef CAPABILITIES
+	cap_t cap = cap_init();
+	if (cap_set_proc(cap) < 0) {
+		perror("ping: cap_set_proc");
+		exit(-1);
+	}
+	cap_free(cap);
+#else
+	if (setuid(getuid())) {
+		perror("ping: setuid");
+		exit(-1);
+	}
+#endif
+}
+
+void android_check_security(void)
+{
+	if (getauxval(AT_SECURE) != 0) {
+		fprintf(stderr, "This version of ping should NOT run with privileges. Aborting\n");
+		exit(1);
+	}
+}
+
+/* Fills all the outpack, excluding ICMP header, but _including_
+ * timestamp area with supplied pattern.
+ */
+static void fill(char *patp)
+{
+	int ii, jj, kk;
+	int pat[16];
+	char *cp;
+	u_char *bp = outpack+8;
+
+#ifdef USE_IDN
+	setlocale(LC_ALL, "C");
+#endif
+
+	for (cp = patp; *cp; cp++) {
+		if (!isxdigit(*cp)) {
+			fprintf(stderr,
+				"ping: patterns must be specified as hex digits.\n");
+			exit(2);
+		}
+	}
+	ii = sscanf(patp,
+	    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
+	    &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
+	    &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
+	    &pat[13], &pat[14], &pat[15]);
+
+	if (ii > 0) {
+		for (kk = 0; kk <= maxpacket - (8 + ii); kk += ii)
+			for (jj = 0; jj < ii; ++jj)
+				bp[jj + kk] = pat[jj];
+	}
+	if (!(options & F_QUIET)) {
+		printf("PATTERN: 0x");
+		for (jj = 0; jj < ii; ++jj)
+			printf("%02x", bp[jj] & 0xFF);
+		printf("\n");
+	}
+
+#ifdef USE_IDN
+	setlocale(LC_ALL, "");
+#endif
+}
+
+void common_options(int ch)
+{
+	switch(ch) {
+	case 'a':
+		options |= F_AUDIBLE;
+		break;
+	case 'A':
+		options |= F_ADAPTIVE;
+		break;
+	case 'c':
+		npackets = atoi(optarg);
+		if (npackets <= 0) {
+			fprintf(stderr, "ping: bad number of packets to transmit.\n");
+			exit(2);
+		}
+		break;
+	case 'd':
+		options |= F_SO_DEBUG;
+		break;
+	case 'D':
+		options |= F_PTIMEOFDAY;
+		break;
+	case 'i':		/* wait between sending packets */
+	{
+		double dbl;
+		char *ep;
+
+		errno = 0;
+		dbl = strtod(optarg, &ep);
+
+		if (errno || *ep != '\0' ||
+		    !finite(dbl) || dbl < 0.0 || dbl >= (double)INT_MAX / 1000 - 1.0) {
+			fprintf(stderr, "ping: bad timing interval\n");
+			exit(2);
+		}
+
+		interval = (int)(dbl * 1000);
+
+		options |= F_INTERVAL;
+		break;
+	}
+	case 'm':
+	{
+		char *endp;
+		mark = strtoul(optarg, &endp, 0);
+		if (*endp != '\0') {
+			fprintf(stderr, "ping: invalid mark %s\n", optarg);
+			exit(2);
+		}
+		options |= F_MARK;
+		break;
+	}
+	case 'w':
+		deadline = atoi(optarg);
+		if (deadline < 0) {
+			fprintf(stderr, "ping: bad wait time.\n");
+			exit(2);
+		}
+		break;
+	case 'l':
+		preload = atoi(optarg);
+		if (preload <= 0) {
+			fprintf(stderr, "ping: bad preload value, should be 1..%d\n", MAX_DUP_CHK);
+			exit(2);
+		}
+		if (preload > MAX_DUP_CHK)
+			preload = MAX_DUP_CHK;
+		if (uid && preload > 3) {
+			fprintf(stderr, "ping: cannot set preload to value > 3\n");
+			exit(2);
+		}
+		break;
+	case 'O':
+		options |= F_OUTSTANDING;
+		break;
+	case 'S':
+		sndbuf = atoi(optarg);
+		if (sndbuf <= 0) {
+			fprintf(stderr, "ping: bad sndbuf value.\n");
+			exit(2);
+		}
+		break;
+	case 'f':
+		options |= F_FLOOD;
+		setbuf(stdout, (char *)NULL);
+		/* fallthrough to numeric - avoid gethostbyaddr during flood */
+	case 'n':
+		options |= F_NUMERIC;
+		break;
+	case 'p':		/* fill buffer with user pattern */
+		options |= F_PINGFILLED;
+		fill(optarg);
+		break;
+	case 'q':
+		options |= F_QUIET;
+		break;
+	case 'r':
+		options |= F_SO_DONTROUTE;
+		break;
+	case 's':		/* size of packet to send */
+		datalen = atoi(optarg);
+		if (datalen < 0) {
+			fprintf(stderr, "ping: illegal negative packet size %d.\n", datalen);
+			exit(2);
+		}
+		if (datalen > maxpacket - 8) {
+			fprintf(stderr, "ping: packet size too large: %d\n",
+				datalen);
+			exit(2);
+		}
+		break;
+	case 'v':
+		options |= F_VERBOSE;
+		break;
+	case 'L':
+		options |= F_NOLOOP;
+		break;
+	case 't':
+		options |= F_TTL;
+		ttl = atoi(optarg);
+		if (ttl < 0 || ttl > 255) {
+			fprintf(stderr, "ping: ttl %u out of range\n", ttl);
+			exit(2);
+		}
+		break;
+	case 'U':
+		options |= F_LATENCY;
+		break;
+	case 'B':
+		options |= F_STRICTSOURCE;
+		break;
+	case 'W':
+		lingertime = atoi(optarg);
+		if (lingertime < 0 || lingertime > INT_MAX/1000000) {
+			fprintf(stderr, "ping: bad linger time.\n");
+			exit(2);
+		}
+		lingertime *= 1000;
+		break;
+	case 'V':
+		printf("ping utility, iputils-%s\n", SNAPSHOT);
+		exit(0);
+	default:
+		abort();
+	}
+}
+
+
+static void sigexit(int signo)
+{
+	exiting = 1;
+	if (in_pr_addr)
+		longjmp(pr_addr_jmp, 0);
+}
+
+static void sigstatus(int signo)
+{
+	status_snapshot = 1;
+}
+
+
+int __schedule_exit(int next)
+{
+	static unsigned long waittime;
+	struct itimerval it;
+
+	if (waittime)
+		return next;
+
+	if (nreceived) {
+		waittime = 2 * tmax;
+		if (waittime < 1000*interval)
+			waittime = 1000*interval;
+	} else
+		waittime = lingertime*1000;
+
+	if (next < 0 || next < waittime/1000)
+		next = waittime/1000;
+
+	it.it_interval.tv_sec = 0;
+	it.it_interval.tv_usec = 0;
+	it.it_value.tv_sec = waittime/1000000;
+	it.it_value.tv_usec = waittime%1000000;
+	setitimer(ITIMER_REAL, &it, NULL);
+	return next;
+}
+
+static inline void update_interval(void)
+{
+	int est = rtt ? rtt/8 : interval*1000;
+
+	interval = (est+rtt_addend+500)/1000;
+	if (uid && interval < MINUSERINTERVAL)
+		interval = MINUSERINTERVAL;
+}
+
+/*
+ * Print timestamp
+ */
+void print_timestamp(void)
+{
+	if (options & F_PTIMEOFDAY) {
+		struct timeval tv;
+		gettimeofday(&tv, NULL);
+		printf("[%lu.%06lu] ",
+		       (unsigned long)tv.tv_sec, (unsigned long)tv.tv_usec);
+	}
+}
+
+/*
+ * pinger --
+ * 	Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
+ * will be added on by the kernel.  The ID field is our UNIX process ID,
+ * and the sequence number is an ascending integer.  The first 8 bytes
+ * of the data portion are used to hold a UNIX "timeval" struct in VAX
+ * byte-order, to compute the round-trip time.
+ */
+int pinger(void)
+{
+	static int oom_count;
+	static int tokens;
+	int i;
+
+	/* Have we already sent enough? If we have, return an arbitrary positive value. */
+	if (exiting || (npackets && ntransmitted >= npackets && !deadline))
+		return 1000;
+
+	/* Check that packets < rate*time + preload */
+	if (cur_time.tv_sec == 0) {
+		gettimeofday(&cur_time, NULL);
+		tokens = interval*(preload-1);
+	} else {
+		long ntokens;
+		struct timeval tv;
+
+		gettimeofday(&tv, NULL);
+		ntokens = (tv.tv_sec - cur_time.tv_sec)*1000 +
+			(tv.tv_usec-cur_time.tv_usec)/1000;
+		if (!interval) {
+			/* Case of unlimited flood is special;
+			 * if we see no reply, they are limited to 100pps */
+			if (ntokens < MININTERVAL && in_flight() >= preload)
+				return MININTERVAL-ntokens;
+		}
+		ntokens += tokens;
+		if (ntokens > interval*preload)
+			ntokens = interval*preload;
+		if (ntokens < interval)
+			return interval - ntokens;
+
+		cur_time = tv;
+		tokens = ntokens - interval;
+	}
+
+	if (options & F_OUTSTANDING) {
+		if (ntransmitted > 0 && !rcvd_test(ntransmitted)) {
+			print_timestamp();
+			printf("no answer yet for icmp_seq=%lu\n", (ntransmitted % MAX_DUP_CHK));
+			fflush(stdout);
+		}
+	}
+
+resend:
+	i = send_probe();
+
+	if (i == 0) {
+		oom_count = 0;
+		advance_ntransmitted();
+		if (!(options & F_QUIET) && (options & F_FLOOD)) {
+			/* Very silly, but without this output with
+			 * high preload or pipe size is very confusing. */
+			if ((preload < screen_width && pipesize < screen_width) ||
+			    in_flight() < screen_width)
+				write_stdout(".", 1);
+		}
+		return interval - tokens;
+	}
+
+	/* And handle various errors... */
+	if (i > 0) {
+		/* Apparently, it is some fatal bug. */
+		abort();
+	} else if (errno == ENOBUFS || errno == ENOMEM) {
+		int nores_interval;
+
+		/* Device queue overflow or OOM. Packet is not sent. */
+		tokens = 0;
+		/* Slowdown. This works only in adaptive mode (option -A) */
+		rtt_addend += (rtt < 8*50000 ? rtt/8 : 50000);
+		if (options&F_ADAPTIVE)
+			update_interval();
+		nores_interval = SCHINT(interval/2);
+		if (nores_interval > 500)
+			nores_interval = 500;
+		oom_count++;
+		if (oom_count*nores_interval < lingertime)
+			return nores_interval;
+		i = 0;
+		/* Fall to hard error. It is to avoid complete deadlock
+		 * on stuck output device even when dealine was not requested.
+		 * Expected timings are screwed up in any case, but we will
+		 * exit some day. :-) */
+	} else if (errno == EAGAIN) {
+		/* Socket buffer is full. */
+		tokens += interval;
+		return MININTERVAL;
+	} else {
+		if ((i=receive_error_msg()) > 0) {
+			/* An ICMP error arrived. */
+			tokens += interval;
+			return MININTERVAL;
+		}
+		/* Compatibility with old linuces. */
+		if (i == 0 && confirm_flag && errno == EINVAL) {
+			confirm_flag = 0;
+			errno = 0;
+		}
+		if (!errno)
+			goto resend;
+	}
+
+	/* Hard local error. Pretend we sent packet. */
+	advance_ntransmitted();
+
+	if (i == 0 && !(options & F_QUIET)) {
+		if (options & F_FLOOD)
+			write_stdout("E", 1);
+		else
+			perror("ping: sendmsg");
+	}
+	tokens = 0;
+	return SCHINT(interval);
+}
+
+/* Set socket buffers, "alloc" is an estimate of memory taken by single packet. */
+
+void sock_setbufs(int icmp_sock, int alloc)
+{
+	int rcvbuf, hold;
+	socklen_t tmplen = sizeof(hold);
+
+	if (!sndbuf)
+		sndbuf = alloc;
+	setsockopt(icmp_sock, SOL_SOCKET, SO_SNDBUF, (char *)&sndbuf, sizeof(sndbuf));
+
+	rcvbuf = hold = alloc * preload;
+	if (hold < 65536)
+		hold = 65536;
+	setsockopt(icmp_sock, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold));
+	if (getsockopt(icmp_sock, SOL_SOCKET, SO_RCVBUF, (char *)&hold, &tmplen) == 0) {
+		if (hold < rcvbuf)
+			fprintf(stderr, "WARNING: probably, rcvbuf is not enough to hold preload.\n");
+	}
+}
+
+void sock_setmark(int icmp_sock) {
+#ifdef SO_MARK
+	if (options & F_MARK) {
+		int ret;
+
+		enable_capability_admin();
+		ret = setsockopt(icmp_sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark));
+		disable_capability_admin();
+
+		if (ret == -1) {
+			/* we probably dont wanna exit since old kernels
+			 * dont support mark ..
+			*/
+			fprintf(stderr, "Warning: Failed to set mark %d\n", mark);
+		}
+	}
+#endif
+}
+
+/* Protocol independent setup and parameter checks. */
+
+void setup(int icmp_sock)
+{
+	int hold;
+	struct timeval tv;
+	sigset_t sset;
+
+	if ((options & F_FLOOD) && !(options & F_INTERVAL))
+		interval = 0;
+
+	if (uid && interval < MINUSERINTERVAL) {
+		fprintf(stderr, "ping: cannot flood; minimal interval, allowed for user, is %dms\n", MINUSERINTERVAL);
+		exit(2);
+	}
+
+	if (interval >= INT_MAX/preload) {
+		fprintf(stderr, "ping: illegal preload and/or interval\n");
+		exit(2);
+	}
+
+	hold = 1;
+	if (options & F_SO_DEBUG)
+		setsockopt(icmp_sock, SOL_SOCKET, SO_DEBUG, (char *)&hold, sizeof(hold));
+	if (options & F_SO_DONTROUTE)
+		setsockopt(icmp_sock, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, sizeof(hold));
+
+#ifdef SO_TIMESTAMP
+	if (!(options&F_LATENCY)) {
+		int on = 1;
+		if (setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)))
+			fprintf(stderr, "Warning: no SO_TIMESTAMP support, falling back to SIOCGSTAMP\n");
+	}
+#endif
+
+	sock_setmark(icmp_sock);
+
+	/* Set some SNDTIMEO to prevent blocking forever
+	 * on sends, when device is too slow or stalls. Just put limit
+	 * of one second, or "interval", if it is less.
+	 */
+	tv.tv_sec = 1;
+	tv.tv_usec = 0;
+	if (interval < 1000) {
+		tv.tv_sec = 0;
+		tv.tv_usec = 1000 * SCHINT(interval);
+	}
+	setsockopt(icmp_sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));
+
+	/* Set RCVTIMEO to "interval". Note, it is just an optimization
+	 * allowing to avoid redundant poll(). */
+	tv.tv_sec = SCHINT(interval)/1000;
+	tv.tv_usec = 1000*(SCHINT(interval)%1000);
+	if (setsockopt(icmp_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)))
+		options |= F_FLOOD_POLL;
+
+	if (!(options & F_PINGFILLED)) {
+		int i;
+		u_char *p = outpack+8;
+
+		/* Do not forget about case of small datalen,
+		 * fill timestamp area too!
+		 */
+		for (i = 0; i < datalen; ++i)
+			*p++ = i;
+	}
+
+	if (!using_ping_socket)
+		ident = htons(getpid() & 0xFFFF);
+
+	set_signal(SIGINT, sigexit);
+	set_signal(SIGALRM, sigexit);
+	set_signal(SIGQUIT, sigstatus);
+
+	sigemptyset(&sset);
+	sigprocmask(SIG_SETMASK, &sset, NULL);
+
+	gettimeofday(&start_time, NULL);
+
+	if (deadline) {
+		struct itimerval it;
+
+		it.it_interval.tv_sec = 0;
+		it.it_interval.tv_usec = 0;
+		it.it_value.tv_sec = deadline;
+		it.it_value.tv_usec = 0;
+		setitimer(ITIMER_REAL, &it, NULL);
+	}
+
+	if (isatty(STDOUT_FILENO)) {
+		struct winsize w;
+
+		if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) {
+			if (w.ws_col > 0)
+				screen_width = w.ws_col;
+		}
+	}
+}
+
+void main_loop(int icmp_sock, __u8 *packet, int packlen)
+{
+	char addrbuf[128];
+	char ans_data[4096];
+	struct iovec iov;
+	struct msghdr msg;
+	struct cmsghdr *c;
+	int cc;
+	int next;
+	int polling;
+
+	iov.iov_base = (char *)packet;
+
+	for (;;) {
+		/* Check exit conditions. */
+		if (exiting)
+			break;
+		if (npackets && nreceived + nerrors >= npackets)
+			break;
+		if (deadline && nerrors)
+			break;
+		/* Check for and do special actions. */
+		if (status_snapshot)
+			status();
+
+		/* Send probes scheduled to this time. */
+		do {
+			next = pinger();
+			next = schedule_exit(next);
+		} while (next <= 0);
+
+		/* "next" is time to send next probe, if positive.
+		 * If next<=0 send now or as soon as possible. */
+
+		/* Technical part. Looks wicked. Could be dropped,
+		 * if everyone used the newest kernel. :-)
+		 * Its purpose is:
+		 * 1. Provide intervals less than resolution of scheduler.
+		 *    Solution: spinning.
+		 * 2. Avoid use of poll(), when recvmsg() can provide
+		 *    timed waiting (SO_RCVTIMEO). */
+		polling = 0;
+		if ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || next<SCHINT(interval)) {
+			int recv_expected = in_flight();
+
+			/* If we are here, recvmsg() is unable to wait for
+			 * required timeout. */
+			if (1000 % HZ == 0 ? next <= 1000 / HZ : (next < INT_MAX / HZ && next * HZ <= 1000)) {
+				/* Very short timeout... So, if we wait for
+				 * something, we sleep for MININTERVAL.
+				 * Otherwise, spin! */
+				if (recv_expected) {
+					next = MININTERVAL;
+				} else {
+					next = 0;
+					/* When spinning, no reasons to poll.
+					 * Use nonblocking recvmsg() instead. */
+					polling = MSG_DONTWAIT;
+					/* But yield yet. */
+					sched_yield();
+				}
+			}
+
+			if (!polling &&
+			    ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || interval)) {
+				struct pollfd pset;
+				pset.fd = icmp_sock;
+				pset.events = POLLIN|POLLERR;
+				pset.revents = 0;
+				if (poll(&pset, 1, next) < 1 ||
+				    !(pset.revents&(POLLIN|POLLERR)))
+					continue;
+				polling = MSG_DONTWAIT;
+			}
+		}
+
+		for (;;) {
+			struct timeval *recv_timep = NULL;
+			struct timeval recv_time;
+			int not_ours = 0; /* Raw socket can receive messages
+					   * destined to other running pings. */
+
+			iov.iov_len = packlen;
+			memset(&msg, 0, sizeof(msg));
+			msg.msg_name = addrbuf;
+			msg.msg_namelen = sizeof(addrbuf);
+			msg.msg_iov = &iov;
+			msg.msg_iovlen = 1;
+			msg.msg_control = ans_data;
+			msg.msg_controllen = sizeof(ans_data);
+
+			cc = recvmsg(icmp_sock, &msg, polling);
+			polling = MSG_DONTWAIT;
+
+			if (cc < 0) {
+				if (errno == EAGAIN || errno == EINTR)
+					break;
+				if (!receive_error_msg()) {
+					if (errno) {
+						perror("ping: recvmsg");
+						break;
+					}
+					not_ours = 1;
+				}
+			} else {
+
+#ifdef SO_TIMESTAMP
+				for (c = CMSG_FIRSTHDR(&msg); c; c = CMSG_NXTHDR(&msg, c)) {
+					if (c->cmsg_level != SOL_SOCKET ||
+					    c->cmsg_type != SO_TIMESTAMP)
+						continue;
+					if (c->cmsg_len < CMSG_LEN(sizeof(struct timeval)))
+						continue;
+					recv_timep = (struct timeval*)CMSG_DATA(c);
+				}
+#endif
+
+				if ((options&F_LATENCY) || recv_timep == NULL) {
+					if ((options&F_LATENCY) ||
+					    ioctl(icmp_sock, SIOCGSTAMP, &recv_time))
+						gettimeofday(&recv_time, NULL);
+					recv_timep = &recv_time;
+				}
+
+				not_ours = parse_reply(&msg, cc, addrbuf, recv_timep);
+			}
+
+			/* See? ... someone runs another ping on this host. */
+			if (not_ours && !using_ping_socket)
+				install_filter();
+
+			/* If nothing is in flight, "break" returns us to pinger. */
+			if (in_flight() == 0)
+				break;
+
+			/* Otherwise, try to recvmsg() again. recvmsg()
+			 * is nonblocking after the first iteration, so that
+			 * if nothing is queued, it will receive EAGAIN
+			 * and return to pinger. */
+		}
+	}
+	finish();
+}
+
+int gather_statistics(__u8 *icmph, int icmplen,
+		      int cc, __u16 seq, int hops,
+		      int csfailed, struct timeval *tv, char *from,
+		      void (*pr_reply)(__u8 *icmph, int cc))
+{
+	int dupflag = 0;
+	long triptime = 0;
+	__u8 *ptr = icmph + icmplen;
+
+	++nreceived;
+	if (!csfailed)
+		acknowledge(seq);
+
+	if (timing && cc >= 8+sizeof(struct timeval)) {
+		struct timeval tmp_tv;
+		memcpy(&tmp_tv, ptr, sizeof(tmp_tv));
+
+restamp:
+		tvsub(tv, &tmp_tv);
+		triptime = tv->tv_sec * 1000000 + tv->tv_usec;
+		if (triptime < 0) {
+			fprintf(stderr, "Warning: time of day goes back (%ldus), taking countermeasures.\n", triptime);
+			triptime = 0;
+			if (!(options & F_LATENCY)) {
+				gettimeofday(tv, NULL);
+				options |= F_LATENCY;
+				goto restamp;
+			}
+		}
+		if (!csfailed) {
+			tsum += triptime;
+			tsum2 += (long long)triptime * (long long)triptime;
+			if (triptime < tmin)
+				tmin = triptime;
+			if (triptime > tmax)
+				tmax = triptime;
+			if (!rtt)
+				rtt = triptime*8;
+			else
+				rtt += triptime-rtt/8;
+			if (options&F_ADAPTIVE)
+				update_interval();
+		}
+	}
+
+	if (csfailed) {
+		++nchecksum;
+		--nreceived;
+	} else if (rcvd_test(seq)) {
+		++nrepeats;
+		--nreceived;
+		dupflag = 1;
+	} else {
+		rcvd_set(seq);
+		dupflag = 0;
+	}
+	confirm = confirm_flag;
+
+	if (options & F_QUIET)
+		return 1;
+
+	if (options & F_FLOOD) {
+		if (!csfailed)
+			write_stdout("\b \b", 3);
+		else
+			write_stdout("\bC", 2);
+	} else {
+		int i;
+		__u8 *cp, *dp;
+
+		print_timestamp();
+		printf("%d bytes from %s:", cc, from);
+
+		if (pr_reply)
+			pr_reply(icmph, cc);
+
+		if (hops >= 0)
+			printf(" ttl=%d", hops);
+
+		if (cc < datalen+8) {
+			printf(" (truncated)\n");
+			return 1;
+		}
+		if (timing) {
+			if (triptime >= 100000)
+				printf(" time=%ld ms", triptime/1000);
+			else if (triptime >= 10000)
+				printf(" time=%ld.%01ld ms", triptime/1000,
+				       (triptime%1000)/100);
+			else if (triptime >= 1000)
+				printf(" time=%ld.%02ld ms", triptime/1000,
+				       (triptime%1000)/10);
+			else
+				printf(" time=%ld.%03ld ms", triptime/1000,
+				       triptime%1000);
+		}
+		if (dupflag)
+			printf(" (DUP!)");
+		if (csfailed)
+			printf(" (BAD CHECKSUM!)");
+
+		/* check the data */
+		cp = ((u_char*)ptr) + sizeof(struct timeval);
+		dp = &outpack[8 + sizeof(struct timeval)];
+		for (i = sizeof(struct timeval); i < datalen; ++i, ++cp, ++dp) {
+			if (*cp != *dp) {
+				printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
+				       i, *dp, *cp);
+				cp = (u_char*)ptr + sizeof(struct timeval);
+				for (i = sizeof(struct timeval); i < datalen; ++i, ++cp) {
+					if ((i % 32) == sizeof(struct timeval))
+						printf("\n#%d\t", i);
+					printf("%x ", *cp);
+				}
+				break;
+			}
+		}
+	}
+	return 0;
+}
+
+static long llsqrt(long long a)
+{
+	long long prev = ~((long long)1 << 63);
+	long long x = a;
+
+	if (x > 0) {
+		while (x < prev) {
+			prev = x;
+			x = (x+(a/x))/2;
+		}
+	}
+
+	return (long)x;
+}
+
+/*
+ * finish --
+ *	Print out statistics, and give up.
+ */
+void finish(void)
+{
+	struct timeval tv = cur_time;
+	char *comma = "";
+
+	tvsub(&tv, &start_time);
+
+	putchar('\n');
+	fflush(stdout);
+	printf("--- %s ping statistics ---\n", hostname);
+	printf("%ld packets transmitted, ", ntransmitted);
+	printf("%ld received", nreceived);
+	if (nrepeats)
+		printf(", +%ld duplicates", nrepeats);
+	if (nchecksum)
+		printf(", +%ld corrupted", nchecksum);
+	if (nerrors)
+		printf(", +%ld errors", nerrors);
+	if (ntransmitted) {
+		printf(", %d%% packet loss",
+		       (int) ((((long long)(ntransmitted - nreceived)) * 100) /
+			      ntransmitted));
+		printf(", time %ldms", 1000*tv.tv_sec+tv.tv_usec/1000);
+	}
+	putchar('\n');
+
+	if (nreceived && timing) {
+		long tmdev;
+
+		tsum /= nreceived + nrepeats;
+		tsum2 /= nreceived + nrepeats;
+		tmdev = llsqrt(tsum2 - tsum * tsum);
+
+		printf("rtt min/avg/max/mdev = %ld.%03ld/%lu.%03ld/%ld.%03ld/%ld.%03ld ms",
+		       (long)tmin/1000, (long)tmin%1000,
+		       (unsigned long)(tsum/1000), (long)(tsum%1000),
+		       (long)tmax/1000, (long)tmax%1000,
+		       (long)tmdev/1000, (long)tmdev%1000
+		       );
+		comma = ", ";
+	}
+	if (pipesize > 1) {
+		printf("%spipe %d", comma, pipesize);
+		comma = ", ";
+	}
+	if (nreceived && (!interval || (options&(F_FLOOD|F_ADAPTIVE))) && ntransmitted > 1) {
+		int ipg = (1000000*(long long)tv.tv_sec+tv.tv_usec)/(ntransmitted-1);
+		printf("%sipg/ewma %d.%03d/%d.%03d ms",
+		       comma, ipg/1000, ipg%1000, rtt/8000, (rtt/8)%1000);
+	}
+	putchar('\n');
+	exit(!nreceived || (deadline && nreceived < npackets));
+}
+
+
+void status(void)
+{
+	int loss = 0;
+	long tavg = 0;
+
+	status_snapshot = 0;
+
+	if (ntransmitted)
+		loss = (((long long)(ntransmitted - nreceived)) * 100) / ntransmitted;
+
+	fprintf(stderr, "\r%ld/%ld packets, %d%% loss", ntransmitted, nreceived, loss);
+
+	if (nreceived && timing) {
+		tavg = tsum / (nreceived + nrepeats);
+
+		fprintf(stderr, ", min/avg/ewma/max = %ld.%03ld/%lu.%03ld/%d.%03d/%ld.%03ld ms",
+		       (long)tmin/1000, (long)tmin%1000,
+		       tavg/1000, tavg%1000,
+		       rtt/8000, (rtt/8)%1000,
+		       (long)tmax/1000, (long)tmax%1000
+		       );
+	}
+	fprintf(stderr, "\n");
+}
+
+inline int is_ours(uint16_t id) {
+	return using_ping_socket || id == ident;
+}
+
diff --git a/iputils/ping_common.h b/iputils/ping_common.h
new file mode 100644
index 0000000..7158555
--- /dev/null
+++ b/iputils/ping_common.h
@@ -0,0 +1,297 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <linux/sockios.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/signal.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <sys/uio.h>
+#include <sys/poll.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <netdb.h>
+#include <setjmp.h>
+
+#ifdef CAPABILITIES
+#include <sys/prctl.h>
+#include <sys/capability.h>
+#endif
+
+#ifdef USE_IDN
+#include <locale.h>
+#include <idna.h>
+#endif
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/types.h>
+#include <linux/errqueue.h>
+
+#ifdef ANDROID
+#include <linux/icmp.h>
+#include <sys/auxv.h>
+#endif
+
+#include "SNAPSHOT.h"
+
+#define	DEFDATALEN	(64 - 8)	/* default data length */
+
+#define	MAXWAIT		10		/* max seconds to wait for response */
+#define MININTERVAL	10		/* Minimal interpacket gap */
+#define MINUSERINTERVAL	200		/* Minimal allowed interval for non-root */
+
+#define SCHINT(a)	(((a) <= MININTERVAL) ? MININTERVAL : (a))
+
+/* various options */
+extern int options;
+#define	F_FLOOD		0x001
+#define	F_INTERVAL	0x002
+#define	F_NUMERIC	0x004
+#define	F_PINGFILLED	0x008
+#define	F_QUIET		0x010
+#define	F_RROUTE	0x020
+#define	F_SO_DEBUG	0x040
+#define	F_SO_DONTROUTE	0x080
+#define	F_VERBOSE	0x100
+#define	F_TIMESTAMP	0x200
+#define	F_FLOWINFO	0x200
+#define	F_SOURCEROUTE	0x400
+#define	F_TCLASS	0x400
+#define	F_FLOOD_POLL	0x800
+#define	F_LATENCY	0x1000
+#define	F_AUDIBLE	0x2000
+#define	F_ADAPTIVE	0x4000
+#define	F_STRICTSOURCE	0x8000
+#define F_NOLOOP	0x10000
+#define F_TTL		0x20000
+#define F_MARK		0x40000
+#define F_PTIMEOFDAY	0x80000
+#define F_OUTSTANDING	0x100000
+
+/*
+ * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
+ * number of received sequence numbers we can keep track of.
+ */
+#define	MAX_DUP_CHK	0x10000
+
+#if defined(__WORDSIZE) && __WORDSIZE == 64
+# define USE_BITMAP64
+#endif
+
+#ifdef USE_BITMAP64
+typedef __u64	bitmap_t;
+# define BITMAP_SHIFT	6
+#else
+typedef __u32	bitmap_t;
+# define BITMAP_SHIFT	5
+#endif
+
+#if ((MAX_DUP_CHK >> (BITMAP_SHIFT + 3)) << (BITMAP_SHIFT + 3)) != MAX_DUP_CHK
+# error Please MAX_DUP_CHK and/or BITMAP_SHIFT
+#endif
+
+struct rcvd_table {
+	bitmap_t bitmap[MAX_DUP_CHK / (sizeof(bitmap_t) * 8)];
+};
+
+extern struct rcvd_table rcvd_tbl;
+extern int using_ping_socket;
+
+#define	A(bit)	(rcvd_tbl.bitmap[(bit) >> BITMAP_SHIFT])	/* identify word in array */
+#define	B(bit)	(((bitmap_t)1) << ((bit) & ((1 << BITMAP_SHIFT) - 1)))	/* identify bit in word */
+
+static inline void rcvd_set(__u16 seq)
+{
+	unsigned bit = seq % MAX_DUP_CHK;
+	A(bit) |= B(bit);
+}
+
+static inline void rcvd_clear(__u16 seq)
+{
+	unsigned bit = seq % MAX_DUP_CHK;
+	A(bit) &= ~B(bit);
+}
+
+static inline bitmap_t rcvd_test(__u16 seq)
+{
+	unsigned bit = seq % MAX_DUP_CHK;
+	return A(bit) & B(bit);
+}
+
+extern u_char outpack[];
+extern int maxpacket;
+
+extern int datalen;
+extern char *hostname;
+extern int uid;
+extern int ident;			/* process id to identify our packets */
+
+extern int sndbuf;
+extern int ttl;
+
+extern long npackets;			/* max packets to transmit */
+extern long nreceived;			/* # of packets we got back */
+extern long nrepeats;			/* number of duplicates */
+extern long ntransmitted;		/* sequence # for outbound packets = #sent */
+extern long nchecksum;			/* replies with bad checksum */
+extern long nerrors;			/* icmp errors */
+extern int interval;			/* interval between packets (msec) */
+extern int preload;
+extern int deadline;			/* time to die */
+extern int lingertime;
+extern struct timeval start_time, cur_time;
+extern volatile int exiting;
+extern volatile int status_snapshot;
+extern int confirm;
+extern int confirm_flag;
+extern int working_recverr;
+
+extern volatile int in_pr_addr;		/* pr_addr() is executing */
+extern jmp_buf pr_addr_jmp;
+
+#ifndef MSG_CONFIRM
+#define MSG_CONFIRM 0
+#endif
+
+
+/* timing */
+extern int timing;			/* flag to do timing */
+extern long tmin;			/* minimum round trip time */
+extern long tmax;			/* maximum round trip time */
+extern long long tsum;			/* sum of all times, for doing average */
+extern long long tsum2;
+extern int rtt;
+extern __u16 acked;
+extern int pipesize;
+
+#define COMMON_OPTIONS \
+case 'a': case 'U': case 'c': case 'd': \
+case 'f': case 'i': case 'w': case 'l': \
+case 'S': case 'n': case 'p': case 'q': \
+case 'r': case 's': case 'v': case 'L': \
+case 't': case 'A': case 'W': case 'B': case 'm': \
+case 'D': case 'O':
+
+#define COMMON_OPTSTR "h?VQ:I:M:aUc:dfi:w:l:S:np:qrs:vLt:AW:Bm:DO"
+
+/*
+ * Write to stdout
+ */
+static inline void write_stdout(const char *str, size_t len)
+{
+	size_t o = 0;
+	ssize_t cc;
+	do {
+		cc = write(STDOUT_FILENO, str + o, len - o);
+		o += cc;
+	} while (len > o || cc < 0);
+}
+
+/*
+ * tvsub --
+ *	Subtract 2 timeval structs:  out = out - in.  Out is assumed to
+ * be >= in.
+ */
+static inline void tvsub(struct timeval *out, struct timeval *in)
+{
+	if ((out->tv_usec -= in->tv_usec) < 0) {
+		--out->tv_sec;
+		out->tv_usec += 1000000;
+	}
+	out->tv_sec -= in->tv_sec;
+}
+
+static inline void set_signal(int signo, void (*handler)(int))
+{
+	struct sigaction sa;
+
+	memset(&sa, 0, sizeof(sa));
+
+	sa.sa_handler = (void (*)(int))handler;
+#ifdef SA_INTERRUPT
+	sa.sa_flags = SA_INTERRUPT;
+#endif
+	sigaction(signo, &sa, NULL);
+}
+
+extern int __schedule_exit(int next);
+
+static inline int schedule_exit(int next)
+{
+	if (npackets && ntransmitted >= npackets && !deadline)
+		next = __schedule_exit(next);
+	return next;
+}
+
+static inline int in_flight(void)
+{
+	__u16 diff = (__u16)ntransmitted - acked;
+	return (diff<=0x7FFF) ? diff : ntransmitted-nreceived-nerrors;
+}
+
+static inline void acknowledge(__u16 seq)
+{
+	__u16 diff = (__u16)ntransmitted - seq;
+	if (diff <= 0x7FFF) {
+		if ((int)diff+1 > pipesize)
+			pipesize = (int)diff+1;
+		if ((__s16)(seq - acked) > 0 ||
+		    (__u16)ntransmitted - acked > 0x7FFF)
+			acked = seq;
+	}
+}
+
+static inline void advance_ntransmitted(void)
+{
+	ntransmitted++;
+	/* Invalidate acked, if 16 bit seq overflows. */
+	if ((__u16)ntransmitted - acked > 0x7FFF)
+		acked = (__u16)ntransmitted + 1;
+}
+
+extern void limit_capabilities(void);
+static int enable_capability_raw(void);
+static int disable_capability_raw(void);
+static int enable_capability_admin(void);
+static int disable_capability_admin(void);
+#ifdef CAPABILITIES
+extern int modify_capability(cap_value_t, cap_flag_value_t);
+static inline int enable_capability_raw(void)		{ return modify_capability(CAP_NET_RAW,   CAP_SET);   };
+static inline int disable_capability_raw(void)		{ return modify_capability(CAP_NET_RAW,   CAP_CLEAR); };
+static inline int enable_capability_admin(void)		{ return modify_capability(CAP_NET_ADMIN, CAP_SET);   };
+static inline int disable_capability_admin(void)	{ return modify_capability(CAP_NET_ADMIN, CAP_CLEAR); };
+#else
+extern int modify_capability(int);
+static inline int enable_capability_raw(void)		{ return modify_capability(1); };
+static inline int disable_capability_raw(void)		{ return modify_capability(0); };
+static inline int enable_capability_admin(void)		{ return modify_capability(1); };
+static inline int disable_capability_admin(void)	{ return modify_capability(0); };
+#endif
+extern void drop_capabilities(void);
+extern void android_check_security(void);
+
+extern int send_probe(void);
+extern int receive_error_msg(void);
+extern int parse_reply(struct msghdr *msg, int len, void *addr, struct timeval *);
+extern void install_filter(void);
+extern int is_ours(uint16_t id);
+
+extern int pinger(void);
+extern void sock_setbufs(int icmp_sock, int alloc);
+extern void sock_setmark(int icmp_sock);
+extern void setup(int icmp_sock);
+extern void main_loop(int icmp_sock, __u8 *buf, int buflen) __attribute__((noreturn));
+extern void finish(void) __attribute__((noreturn));
+extern void status(void);
+extern void common_options(int ch);
+extern int gather_statistics(__u8 *ptr, int icmplen,
+			     int cc, __u16 seq, int hops,
+			     int csfailed, struct timeval *tv, char *from,
+			     void (*pr_reply)(__u8 *ptr, int cc));
+extern void print_timestamp(void);
diff --git a/iputils/rarpd.c b/iputils/rarpd.c
new file mode 100644
index 0000000..b740e87
--- /dev/null
+++ b/iputils/rarpd.c
@@ -0,0 +1,724 @@
+/*
+ * rarpd.c	RARP daemon.
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ */
+
+#include <stdio.h>
+#include <syslog.h>
+#include <dirent.h>
+#include <malloc.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <sys/signal.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <netinet/in.h>
+#include <linux/if_packet.h>
+#include <linux/filter.h>
+
+int do_reload = 1;
+
+int debug;
+int verbose;
+int ifidx;
+int allow_offlink;
+int only_ethers;
+int all_ifaces;
+int listen_arp;
+char *ifname;
+char *tftp_dir = "/etc/tftpboot";
+
+extern int ether_ntohost(char *name, unsigned char *ea);
+void usage(void) __attribute__((noreturn));
+
+struct iflink
+{
+	struct iflink	*next;
+	int	       	index;
+	int		hatype;
+	unsigned char	lladdr[16];
+	char		name[IFNAMSIZ];
+	struct ifaddr 	*ifa_list;
+} *ifl_list;
+
+struct ifaddr
+{
+	struct ifaddr 	*next;
+	__u32		prefix;
+	__u32		mask;
+	__u32		local;
+};
+
+struct rarp_map
+{
+	struct rarp_map *next;
+
+	int		ifindex;
+	int		arp_type;
+	int		lladdr_len;
+	unsigned char	lladdr[16];
+	__u32		ipaddr;
+} *rarp_db;
+
+void usage()
+{
+	fprintf(stderr, "Usage: rarpd [ -dveaA ] [ -b tftpdir ] [ interface]\n");
+	exit(1);
+}
+
+void load_db(void)
+{
+}
+
+void load_if(void)
+{
+	int fd;
+	struct ifreq *ifrp, *ifend;
+	struct iflink *ifl;
+	struct ifaddr *ifa;
+	struct ifconf ifc;
+	struct ifreq ibuf[256];
+
+	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+		syslog(LOG_ERR, "socket: %m");
+		return;
+	}
+
+	ifc.ifc_len = sizeof ibuf;
+	ifc.ifc_buf = (caddr_t)ibuf;
+	if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
+	    ifc.ifc_len < (int)sizeof(struct ifreq)) {
+		syslog(LOG_ERR, "SIOCGIFCONF: %m");
+		close(fd);
+		return;
+	}
+
+	while ((ifl = ifl_list) != NULL) {
+		while ((ifa = ifl->ifa_list) != NULL) {
+			ifl->ifa_list = ifa->next;
+			free(ifa);
+		}
+		ifl_list = ifl->next;
+		free(ifl);
+	}
+
+	ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
+	for (ifrp = ibuf; ifrp < ifend; ifrp++) {
+		__u32 addr;
+		__u32 mask;
+		__u32 prefix;
+
+		if (ifrp->ifr_addr.sa_family != AF_INET)
+			continue;
+		addr = ((struct sockaddr_in*)&ifrp->ifr_addr)->sin_addr.s_addr;
+		if (addr == 0)
+			continue;
+		if (ioctl(fd, SIOCGIFINDEX, ifrp)) {
+			syslog(LOG_ERR, "ioctl(SIOCGIFNAME): %m");
+			continue;
+		}
+		if (ifidx && ifrp->ifr_ifindex != ifidx)
+			continue;
+		for (ifl = ifl_list; ifl; ifl = ifl->next)
+			if (ifl->index == ifrp->ifr_ifindex)
+				break;
+		if (ifl == NULL) {
+			char *p;
+			int index = ifrp->ifr_ifindex;
+
+			if (ioctl(fd, SIOCGIFHWADDR, ifrp)) {
+				syslog(LOG_ERR, "ioctl(SIOCGIFHWADDR): %m");
+				continue;
+			}
+
+			ifl = (struct iflink*)malloc(sizeof(*ifl));
+			if (ifl == NULL)
+				continue;
+			memset(ifl, 0, sizeof(*ifl));
+			ifl->next = ifl_list;
+			ifl_list = ifl;
+			ifl->index = index;
+			ifl->hatype = ifrp->ifr_hwaddr.sa_family;
+			memcpy(ifl->lladdr, ifrp->ifr_hwaddr.sa_data, 14);
+			strncpy(ifl->name, ifrp->ifr_name, IFNAMSIZ);
+			p = strchr(ifl->name, ':');
+			if (p)
+				*p = 0;
+			if (verbose)
+				syslog(LOG_INFO, "link %s", ifl->name);
+		}
+		if (ioctl(fd, SIOCGIFNETMASK, ifrp)) {
+			syslog(LOG_ERR, "ioctl(SIOCGIFMASK): %m");
+			continue;
+		}
+		mask = ((struct sockaddr_in*)&ifrp->ifr_netmask)->sin_addr.s_addr;
+		if (ioctl(fd, SIOCGIFDSTADDR, ifrp)) {
+			syslog(LOG_ERR, "ioctl(SIOCGIFDSTADDR): %m");
+			continue;
+		}
+		prefix = ((struct sockaddr_in*)&ifrp->ifr_dstaddr)->sin_addr.s_addr;
+		for (ifa = ifl->ifa_list; ifa; ifa = ifa->next) {
+			if (ifa->local == addr &&
+			    ifa->prefix == prefix &&
+			    ifa->mask == mask)
+				break;
+		}
+		if (ifa == NULL) {
+			if (mask == 0 || prefix == 0)
+				continue;
+			ifa = (struct ifaddr*)malloc(sizeof(*ifa));
+			memset(ifa, 0, sizeof(*ifa));
+			ifa->local = addr;
+			ifa->prefix = prefix;
+			ifa->mask = mask;
+			ifa->next = ifl->ifa_list;
+			ifl->ifa_list = ifa;
+
+			if (verbose) {
+				int i;
+				__u32 m = ~0U;
+				for (i=32; i>=0; i--) {
+					if (htonl(m) == mask)
+						break;
+					m <<= 1;
+				}
+				if (addr == prefix) {
+					syslog(LOG_INFO, "  addr %s/%d on %s\n",
+					       inet_ntoa(*(struct in_addr*)&addr), i, ifl->name);
+				} else {
+					char tmpa[64];
+					sprintf(tmpa, "%s", inet_ntoa(*(struct in_addr*)&addr));
+					syslog(LOG_INFO, "  addr %s %s/%d on %s\n", tmpa,
+					       inet_ntoa(*(struct in_addr*)&prefix), i, ifl->name);
+				}
+			}
+		}
+	}
+}
+
+void configure(void)
+{
+	load_if();
+	load_db();
+}
+
+int bootable(__u32 addr)
+{
+	struct dirent *dent;
+	DIR *d;
+	char name[9];
+
+	sprintf(name, "%08X", (__u32)ntohl(addr));
+	d = opendir(tftp_dir);
+	if (d == NULL) {
+		syslog(LOG_ERR, "opendir: %m");
+		return 0;
+	}
+	while ((dent = readdir(d)) != NULL) {
+		if (strncmp(dent->d_name, name, 8) == 0)
+			break;
+	}
+	closedir(d);
+	return dent != NULL;
+}
+
+struct ifaddr *select_ipaddr(int ifindex, __u32 *sel_addr, __u32 **alist)
+{
+	struct iflink *ifl;
+	struct ifaddr *ifa;
+	int retry = 0;
+	int i;
+
+retry:
+	for (ifl=ifl_list; ifl; ifl=ifl->next)
+		if (ifl->index == ifindex)
+			break;
+	if (ifl == NULL && !retry) {
+		retry++;
+		load_if();
+		goto retry;
+	}
+	if (ifl == NULL)
+		return NULL;
+
+	for (i=0; alist[i]; i++) {
+		__u32 addr = *(alist[i]);
+		for (ifa=ifl->ifa_list; ifa; ifa=ifa->next) {
+			if (!((ifa->prefix^addr)&ifa->mask)) {
+				*sel_addr = addr;
+				return ifa;
+			}
+		}
+		if (ifa == NULL && retry==0) {
+			retry++;
+			load_if();
+			goto retry;
+		}
+	}
+	if (i==1 && allow_offlink) {
+		*sel_addr = *(alist[0]);
+		return ifl->ifa_list;
+	}
+	syslog(LOG_ERR, "Off-link request on %s", ifl->name);
+	return NULL;
+}
+
+struct rarp_map *rarp_lookup(int ifindex, int hatype,
+			     int halen, unsigned char *lladdr)
+{
+	struct rarp_map *r;
+
+	for (r=rarp_db; r; r=r->next) {
+		if (r->arp_type != hatype && r->arp_type != -1)
+			continue;
+		if (r->lladdr_len != halen)
+			continue;
+		if (r->ifindex != ifindex && r->ifindex != 0)
+			continue;
+		if (memcmp(r->lladdr, lladdr, halen) == 0)
+			break;
+	}
+
+	if (r == NULL) {
+		if (hatype == ARPHRD_ETHER && halen == 6) {
+			struct ifaddr *ifa;
+			struct hostent *hp;
+			char ename[256];
+			static struct rarp_map emap = {
+				NULL,
+				0,
+				ARPHRD_ETHER,
+				6,
+			};
+
+			if (ether_ntohost(ename, lladdr) != 0 ||
+			    (hp = gethostbyname(ename)) == NULL) {
+				if (verbose)
+					syslog(LOG_INFO, "not found in /etc/ethers");
+				return NULL;
+			}
+			if (hp->h_addrtype != AF_INET) {
+				syslog(LOG_ERR, "no IP address");
+				return NULL;
+			}
+			ifa = select_ipaddr(ifindex, &emap.ipaddr, (__u32 **)hp->h_addr_list);
+			if (ifa) {
+				memcpy(emap.lladdr, lladdr, 6);
+				if (only_ethers || bootable(emap.ipaddr))
+					return &emap;
+				if (verbose)
+					syslog(LOG_INFO, "not bootable");
+			}
+		}
+	}
+	return r;
+}
+
+static int load_arp_bpflet(int fd)
+{
+	static struct sock_filter insns[] = {
+		BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
+		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ARPOP_RREQUEST, 0, 1),
+		BPF_STMT(BPF_RET|BPF_K, 1024),
+		BPF_STMT(BPF_RET|BPF_K, 0),
+	};
+	static struct sock_fprog filter = {
+		sizeof insns / sizeof(insns[0]),
+		insns
+	};
+
+	return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
+}
+
+int put_mylladdr(unsigned char **ptr_p, int ifindex, int alen)
+{
+	struct iflink *ifl;
+
+	for (ifl=ifl_list; ifl; ifl = ifl->next)
+		if (ifl->index == ifindex)
+			break;
+
+	if (ifl==NULL)
+		return -1;
+
+	memcpy(*ptr_p, ifl->lladdr, alen);
+	*ptr_p += alen;
+	return 0;
+}
+
+int put_myipaddr(unsigned char **ptr_p, int ifindex, __u32 hisipaddr)
+{
+	__u32 laddr = 0;
+	struct iflink *ifl;
+	struct ifaddr *ifa;
+
+	for (ifl=ifl_list; ifl; ifl = ifl->next)
+		if (ifl->index == ifindex)
+			break;
+
+	if (ifl==NULL)
+		return -1;
+
+	for (ifa=ifl->ifa_list; ifa; ifa=ifa->next) {
+		if (!((ifa->prefix^hisipaddr)&ifa->mask)) {
+			laddr = ifa->local;
+			break;
+		}
+	}
+	memcpy(*ptr_p, &laddr, 4);
+	*ptr_p += 4;
+	return 0;
+}
+
+void arp_advise(int ifindex, unsigned char *lladdr, int lllen, __u32 ipaddr)
+{
+	int fd;
+	struct arpreq req;
+	struct sockaddr_in *sin;
+	struct iflink *ifl;
+
+	for (ifl=ifl_list; ifl; ifl = ifl->next)
+		if (ifl->index == ifindex)
+			break;
+
+	if (ifl == NULL)
+		return;
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	memset(&req, 0, sizeof(req));
+	req.arp_flags = ATF_COM;
+	sin = (struct sockaddr_in *)&req.arp_pa;
+	sin->sin_family = AF_INET;
+	sin->sin_addr.s_addr = ipaddr;
+	req.arp_ha.sa_family = ifl->hatype;
+	memcpy(req.arp_ha.sa_data, lladdr, lllen);
+	memcpy(req.arp_dev, ifl->name, IFNAMSIZ);
+
+	if (ioctl(fd, SIOCSARP, &req))
+		syslog(LOG_ERR, "SIOCSARP: %m");
+	close(fd);
+}
+
+void serve_it(int fd)
+{
+	unsigned char buf[1024];
+	struct sockaddr_ll sll;
+	socklen_t sll_len = sizeof(sll);
+	struct arphdr *a = (struct arphdr*)buf;
+	struct rarp_map *rmap;
+	unsigned char *ptr;
+	int n;
+
+	n = recvfrom(fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sll, &sll_len);
+	if (n<0) {
+		if (errno != EINTR && errno != EAGAIN)
+			syslog(LOG_ERR, "recvfrom: %m");
+		return;
+	}
+
+	/* Do not accept packets for other hosts and our own ones */
+	if (sll.sll_pkttype != PACKET_BROADCAST &&
+	    sll.sll_pkttype != PACKET_MULTICAST &&
+	    sll.sll_pkttype != PACKET_HOST)
+		return;
+
+	if (ifidx && sll.sll_ifindex != ifidx)
+		return;
+
+	if (n<sizeof(*a)) {
+		syslog(LOG_ERR, "truncated arp packet; len=%d", n);
+		return;
+	}
+
+	/* Accept only RARP requests */
+	if (a->ar_op != htons(ARPOP_RREQUEST))
+		return;
+
+	if (verbose) {
+		int i;
+		char tmpbuf[16*3];
+		char *ptr = tmpbuf;
+		for (i=0; i<sll.sll_halen; i++) {
+			if (i) {
+				sprintf(ptr, ":%02x", sll.sll_addr[i]);
+				ptr++;
+			} else
+				sprintf(ptr, "%02x", sll.sll_addr[i]);
+			ptr += 2;
+		}
+		syslog(LOG_INFO, "RARP request from %s on if%d", tmpbuf, sll.sll_ifindex);
+	}
+
+	/* Sanity checks */
+
+	/* 1. IP only -> pln==4 */
+	if (a->ar_pln != 4) {
+		syslog(LOG_ERR, "interesting rarp_req plen=%d", a->ar_pln);
+		return;
+	}
+	/* 2. ARP protocol must be IP */
+	if (a->ar_pro != htons(ETH_P_IP)) {
+		syslog(LOG_ERR, "rarp protocol is not IP %04x", ntohs(a->ar_pro));
+		return;
+	}
+	/* 3. ARP types must match */
+	if (htons(sll.sll_hatype) != a->ar_hrd) {
+		switch (sll.sll_hatype) {
+		case ARPHRD_FDDI:
+			if (a->ar_hrd == htons(ARPHRD_ETHER) ||
+			    a->ar_hrd == htons(ARPHRD_IEEE802))
+				break;
+		default:
+			syslog(LOG_ERR, "rarp htype mismatch");
+			return;
+		}
+	}
+	/* 3. LL address lengths must be equal */
+	if (a->ar_hln != sll.sll_halen) {
+		syslog(LOG_ERR, "rarp hlen mismatch");
+		return;
+	}
+	/* 4. Check packet length */
+	if (sizeof(*a) + 2*4 + 2*a->ar_hln > n) {
+		syslog(LOG_ERR, "truncated rarp request; len=%d", n);
+		return;
+	}
+	/* 5. Silly check: if this guy set different source
+	      addresses in MAC header and in ARP, he is insane
+	 */
+	if (memcmp(sll.sll_addr, a+1, sll.sll_halen)) {
+		syslog(LOG_ERR, "this guy set different his lladdrs in arp and header");
+		return;
+	}
+	/* End of sanity checks */
+
+	/* Lookup requested target in our database */
+	rmap = rarp_lookup(sll.sll_ifindex, sll.sll_hatype,
+			   sll.sll_halen, (unsigned char*)(a+1) + sll.sll_halen + 4);
+	if (rmap == NULL)
+		return;
+
+	/* Prepare reply. It is almost ready, we only
+	   replace ARP packet type, put our lladdr and
+	   IP address to source fileds,
+	   and fill target IP address.
+	 */
+	a->ar_op = htons(ARPOP_RREPLY);
+	ptr = (unsigned char*)(a+1);
+	if (put_mylladdr(&ptr, sll.sll_ifindex, rmap->lladdr_len))
+		return;
+	if (put_myipaddr(&ptr, sll.sll_ifindex, rmap->ipaddr))
+		return;
+	/* It is already filled */
+	ptr += rmap->lladdr_len;
+	memcpy(ptr, &rmap->ipaddr, 4);
+	ptr += 4;
+
+	/* Update our ARP cache. Probably, this guy
+	   will not able to make ARP (if it is broken)
+	 */
+	arp_advise(sll.sll_ifindex, rmap->lladdr, rmap->lladdr_len, rmap->ipaddr);
+
+	/* Sendto is blocking, but with 5sec timeout */
+	alarm(5);
+	sendto(fd, buf, ptr - buf, 0, (struct sockaddr*)&sll, sizeof(sll));
+	alarm(0);
+}
+
+void catch_signal(int sig, void (*handler)(int))
+{
+	struct sigaction sa;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = handler;
+#ifdef SA_INTERRUPT
+	sa.sa_flags = SA_INTERRUPT;
+#endif
+	sigaction(sig, &sa, NULL);
+}
+
+void sig_alarm(int signo)
+{
+}
+
+void sig_hup(int signo)
+{
+	do_reload = 1;
+}
+
+int main(int argc, char **argv)
+{
+	struct pollfd pset[2];
+	int psize;
+	int opt;
+
+
+	opterr = 0;
+	while ((opt = getopt(argc, argv, "aAb:dvoe")) != EOF) {
+		switch (opt) {
+		case 'a':
+			++all_ifaces;
+			break;
+
+		case 'A':
+			++listen_arp;
+			break;
+
+		case 'd':
+			++debug;
+			break;
+
+		case 'v':
+			++verbose;
+			break;
+
+		case 'o':
+			++allow_offlink;
+			break;
+
+		case 'e':
+			++only_ethers;
+			break;
+
+		case 'b':
+			tftp_dir = optarg;
+			break;
+
+		default:
+			usage();
+		}
+	}
+	if (argc > optind) {
+		if (argc > optind+1)
+			usage();
+		ifname = argv[optind];
+	}
+
+	psize = 1;
+	pset[0].fd = socket(PF_PACKET, SOCK_DGRAM, 0);
+
+	if (ifname) {
+		struct ifreq ifr;
+		memset(&ifr, 0, sizeof(ifr));
+		strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+		if (ioctl(pset[0].fd, SIOCGIFINDEX, &ifr)) {
+			perror("ioctl(SIOCGIFINDEX)");
+			usage();
+		}
+		ifidx = ifr.ifr_ifindex;
+	}
+
+	pset[1].fd = -1;
+	if (listen_arp) {
+		pset[1].fd = socket(PF_PACKET, SOCK_DGRAM, 0);
+		if (pset[1].fd >= 0) {
+			load_arp_bpflet(pset[1].fd);
+			psize = 1;
+		}
+	}
+
+	if (pset[1].fd >= 0) {
+		struct sockaddr_ll sll;
+		memset(&sll, 0, sizeof(sll));
+		sll.sll_family = AF_PACKET;
+		sll.sll_protocol = htons(ETH_P_ARP);
+		sll.sll_ifindex = all_ifaces ? 0 : ifidx;
+		if (bind(pset[1].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) {
+			close(pset[1].fd);
+			pset[1].fd = -1;
+			psize = 1;
+		}
+	}
+	if (pset[0].fd >= 0) {
+		struct sockaddr_ll sll;
+		memset(&sll, 0, sizeof(sll));
+		sll.sll_family = AF_PACKET;
+		sll.sll_protocol = htons(ETH_P_RARP);
+		sll.sll_ifindex = all_ifaces ? 0 : ifidx;
+		if (bind(pset[0].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) {
+			close(pset[0].fd);
+			pset[0].fd = -1;
+		}
+	}
+	if (pset[0].fd < 0) {
+		pset[0] = pset[1];
+		psize--;
+	}
+	if (psize == 0) {
+		fprintf(stderr, "failed to bind any socket. Aborting.\n");
+		exit(1);
+	}
+
+	if (!debug) {
+		int fd;
+		pid_t pid = fork();
+
+		if (pid > 0)
+			exit(0);
+		else if (pid == -1) {
+			perror("rarpd: fork");
+			exit(1);
+		}
+
+		if (chdir("/") < 0) {
+			perror("rarpd: chdir");
+			exit(1);
+		}
+
+		fd = open("/dev/null", O_RDWR);
+		if (fd >= 0) {
+			dup2(fd, 0);
+			dup2(fd, 1);
+			dup2(fd, 2);
+			if (fd > 2)
+				close(fd);
+		}
+		setsid();
+	}
+
+	openlog("rarpd", LOG_PID | LOG_CONS, LOG_DAEMON);
+	catch_signal(SIGALRM, sig_alarm);
+	catch_signal(SIGHUP, sig_hup);
+
+	for (;;) {
+		int i;
+
+		if (do_reload) {
+			configure();
+			do_reload = 0;
+		}
+
+#define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP)
+		pset[0].events = EVENTS;
+		pset[0].revents = 0;
+		pset[1].events = EVENTS;
+		pset[1].revents = 0;
+
+		i = poll(pset, psize, -1);
+		if (i <= 0) {
+			if (errno != EINTR && i<0) {
+				syslog(LOG_ERR, "poll returned some crap: %m\n");
+				sleep(10);
+			}
+			continue;
+		}
+		for (i=0; i<psize; i++) {
+			if (pset[i].revents&EVENTS)
+				serve_it(pset[i].fd);
+		}
+	}
+}
diff --git a/iputils/rdisc.c b/iputils/rdisc.c
new file mode 100644
index 0000000..c142773
--- /dev/null
+++ b/iputils/rdisc.c
@@ -0,0 +1,1534 @@
+/*
+ * Rdisc (this program) was developed by Sun Microsystems, Inc. and is
+ * provided for unrestricted use provided that this legend is included on
+ * all tape media and as a part of the software program in whole or part.
+ * Users may copy or modify Rdisc without charge, and they may freely
+ * distribute it.
+ *
+ * RDISC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Rdisc is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY RDISC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/time.h>
+/* Do not use "improved" glibc version! */
+#include <linux/limits.h>
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <malloc.h>
+
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/route.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+
+/*
+ * The next include contains all defs and structures for multicast
+ * that are not in SunOS 4.1.x. On a SunOS 4.1.x system none of this code
+ * is ever used because it does not support multicast
+ * Fraser Gardiner - Sun Microsystems Australia
+ */
+
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#include <string.h>
+#include <syslog.h>
+
+#include "SNAPSHOT.h"
+
+struct interface
+{
+	struct in_addr 	address;	/* Used to identify the interface */
+	struct in_addr	localaddr;	/* Actual address if the interface */
+	int 		preference;
+	int		flags;
+	struct in_addr	bcastaddr;
+	struct in_addr	remoteaddr;
+	struct in_addr	netmask;
+	int		ifindex;
+	char		name[IFNAMSIZ];
+};
+
+/*
+ * TBD
+ *	Use 255.255.255.255 for broadcasts - not the interface broadcast
+ *	address.
+ */
+
+#define ALLIGN(ptr)	(ptr)
+
+static int join(int sock, struct sockaddr_in *sin);
+static void solicitor(struct sockaddr_in *);
+#ifdef RDISC_SERVER
+static void advertise(struct sockaddr_in *, int lft);
+#endif
+static char *pr_name(struct in_addr addr);
+static void pr_pack(char *buf, int cc, struct sockaddr_in *from);
+static void age_table(int time);
+static void record_router(struct in_addr router, int preference, int ttl);
+static void add_route(struct in_addr addr);
+static void del_route(struct in_addr addr);
+static void rtioctl(struct in_addr addr, int op);
+static int support_multicast(void);
+static int sendbcast(int s, char *packet, int packetlen);
+static int sendmcast(int s, char *packet, int packetlen, struct sockaddr_in *);
+static int sendbcastif(int s, char *packet, int packetlen, struct interface *ifp);
+static int sendmcastif(int s, char *packet, int packetlen, struct sockaddr_in *sin, struct interface *ifp);
+static int is_directly_connected(struct in_addr in);
+static void initlog(void);
+static void discard_table(void);
+static void init(void);
+
+#define ICMP_ROUTER_ADVERTISEMENT	9
+#define ICMP_ROUTER_SOLICITATION	10
+
+#define ALL_HOSTS_ADDRESS		"224.0.0.1"
+#define ALL_ROUTERS_ADDRESS		"224.0.0.2"
+
+#define MAXIFS 32
+
+#if !defined(__GLIBC__) || __GLIBC__ < 2
+/* For router advertisement */
+struct icmp_ra
+{
+	u_char	icmp_type;		/* type of message, see below */
+	u_char	icmp_code;		/* type sub code */
+	u_short	icmp_cksum;		/* ones complement cksum of struct */
+	u_char	icmp_num_addrs;
+	u_char	icmp_wpa;		/* Words per address */
+	short 	icmp_lifetime;
+};
+
+struct icmp_ra_addr
+{
+	__u32	ira_addr;
+	__u32	ira_preference;
+};
+#else
+#define icmp_ra icmp
+#endif
+
+/* Router constants */
+#define	MAX_INITIAL_ADVERT_INTERVAL	16
+#define	MAX_INITIAL_ADVERTISEMENTS  	3
+#define	MAX_RESPONSE_DELAY		2	/* Not used */
+
+/* Host constants */
+#define MAX_SOLICITATIONS 		3
+#define SOLICITATION_INTERVAL 		3
+#define MAX_SOLICITATION_DELAY		1	/* Not used */
+
+#define INELIGIBLE_PREF			0x80000000	/* Maximum negative */
+
+#define MAX_ADV_INT 600
+
+/* Statics */
+static int num_interfaces;
+
+static struct interface *interfaces;
+static int interfaces_size;			/* Number of elements in interfaces */
+
+
+#define	MAXPACKET	4096	/* max packet size */
+
+/* fraser */
+int debugfile;
+
+const char usage[] =
+"Usage:	rdisc [-b] [-d] [-s] [-v] [-f] [-a] [-V] [send_address] [receive_address]\n"
+#ifdef RDISC_SERVER
+"       rdisc -r [-b] [-d] [-s] [-v] [-f] [-a] [-V] [-p <preference>] [-T <secs>]\n"
+"		 [send_address] [receive_address]\n"
+#endif
+;
+
+
+int s;			/* Socket file descriptor */
+struct sockaddr_in whereto;/* Address to send to */
+
+/* Common variables */
+int verbose = 0;
+int debug = 0;
+int trace = 0;
+int solicit = 0;
+int ntransmitted = 0;
+int nreceived = 0;
+int forever = 0;	/* Never give up on host. If 0 defer fork until
+			 * first response.
+			 */
+
+#ifdef RDISC_SERVER
+/* Router variables */
+int responder;
+int max_adv_int = MAX_ADV_INT;
+int min_adv_int;
+int lifetime;
+int initial_advert_interval = MAX_INITIAL_ADVERT_INTERVAL;
+int initial_advertisements = MAX_INITIAL_ADVERTISEMENTS;
+int preference = 0;		/* Setable with -p option */
+#endif
+
+/* Host variables */
+int max_solicitations = MAX_SOLICITATIONS;
+unsigned int solicitation_interval = SOLICITATION_INTERVAL;
+int best_preference = 1;  	/* Set to record only the router(s) with the
+				   best preference in the kernel. Not set
+				   puts all routes in the kernel. */
+
+
+static void graceful_finish(void);
+static void finish(void);
+static void timer(void);
+static void initifs(void);
+static u_short in_cksum(u_short *addr, int len);
+
+static int logging = 0;
+
+#define logerr(fmt...) ({ if (logging) syslog(LOG_ERR, fmt); \
+			  else fprintf(stderr, fmt); })
+#define logtrace(fmt...) ({ if (logging) syslog(LOG_INFO, fmt); \
+			  else fprintf(stderr, fmt); })
+#define logdebug(fmt...) ({ if (logging) syslog(LOG_DEBUG, fmt); \
+			  else fprintf(stderr, fmt); })
+static void logperror(char *str);
+
+static __inline__ int isbroadcast(struct sockaddr_in *sin)
+{
+	return (sin->sin_addr.s_addr == INADDR_BROADCAST);
+}
+
+static __inline__ int ismulticast(struct sockaddr_in *sin)
+{
+	return IN_CLASSD(ntohl(sin->sin_addr.s_addr));
+}
+
+static void prusage(void)
+{
+	fputs(usage, stderr);
+	exit(1);
+}
+
+void do_fork(void)
+{
+	int t;
+	pid_t pid;
+	long open_max;
+
+	if (trace)
+		return;
+	if ((open_max = sysconf(_SC_OPEN_MAX)) == -1) {
+		if (errno == 0) {
+			(void) fprintf(stderr, "OPEN_MAX is not supported\n");
+		} 
+		else {
+			(void) fprintf(stderr, "sysconf() error\n");
+		}
+		exit(1);
+	}
+
+
+	if ((pid=fork()) != 0)
+		exit(0);
+
+	for (t = 0; t < open_max; t++)
+		if (t != s)
+			close(t);
+
+	setsid();
+	initlog();
+}
+
+void signal_setup(int signo, void (*handler)(void))
+{
+	struct sigaction sa;
+
+	memset(&sa, 0, sizeof(sa));
+
+	sa.sa_handler = (void (*)(int))handler;
+#ifdef SA_INTERRUPT
+	sa.sa_flags = SA_INTERRUPT;
+#endif
+	sigaction(signo, &sa, NULL);
+}
+
+/*
+ * 			M A I N
+ */
+char    *sendaddress, *recvaddress;
+
+int main(int argc, char **argv)
+{
+	struct sockaddr_in from;
+	char **av = argv;
+	struct sockaddr_in *to = &whereto;
+	struct sockaddr_in joinaddr;
+	sigset_t sset, sset_empty;
+#ifdef RDISC_SERVER
+	int val;
+
+	min_adv_int =( max_adv_int * 3 / 4);
+	lifetime = (3*max_adv_int);
+#endif
+
+	argc--, av++;
+	while (argc > 0 && *av[0] == '-') {
+		while (*++av[0]) {
+			switch (*av[0]) {
+			case 'd':
+				debug = 1;
+				break;
+			case 't':
+				trace = 1;
+				break;
+			case 'v':
+				verbose++;
+				break;
+			case 's':
+				solicit = 1;
+				break;
+#ifdef RDISC_SERVER
+			case 'r':
+				responder = 1;
+				break;
+#endif
+			case 'a':
+				best_preference = 0;
+				break;
+			case 'b':
+				best_preference = 1;
+				break;
+			case 'f':
+				forever = 1;
+				break;
+			case 'V':
+				printf("rdisc utility, iputils-%s\n", SNAPSHOT);
+				exit(0);
+#ifdef RDISC_SERVER
+			case 'T':
+				argc--, av++;
+				if (argc != 0) {
+					val = strtol(av[0], (char **)NULL, 0);
+					if (val < 4 || val > 1800) {
+						(void) fprintf(stderr,
+							       "Bad Max Advertizement Interval\n");
+						exit(1);
+					}
+					max_adv_int = val;
+					min_adv_int =( max_adv_int * 3 / 4);
+					lifetime = (3*max_adv_int);
+				} else {
+					prusage();
+					/* NOTREACHED*/
+				}
+				goto next;
+			case 'p':
+				argc--, av++;
+				if (argc != 0) {
+					val = strtol(av[0], (char **)NULL, 0);
+					preference = val;
+				} else {
+					prusage();
+					/* NOTREACHED*/
+				}
+				goto next;
+#endif
+			default:
+				prusage();
+				/* NOTREACHED*/
+			}
+		}
+#ifdef RDISC_SERVER
+next:
+#endif
+		argc--, av++;
+	}
+	if( argc < 1)  {
+		if (support_multicast()) {
+			sendaddress = ALL_ROUTERS_ADDRESS;
+#ifdef RDISC_SERVER
+			if (responder)
+				sendaddress = ALL_HOSTS_ADDRESS;
+#endif
+		} else
+			sendaddress = "255.255.255.255";
+	} else {
+		sendaddress = av[0];
+		argc--;
+	}
+
+	if (argc < 1) {
+		if (support_multicast()) {
+			recvaddress = ALL_HOSTS_ADDRESS;
+#ifdef RDISC_SERVER
+			if (responder)
+				recvaddress = ALL_ROUTERS_ADDRESS;
+#endif
+		} else
+			recvaddress = "255.255.255.255";
+	} else {
+		recvaddress = av[0];
+		argc--;
+	}
+	if (argc != 0) {
+		(void) fprintf(stderr, "Extra parameters\n");
+		prusage();
+		/* NOTREACHED */
+	}
+
+#ifdef RDISC_SERVER
+	if (solicit && responder) {
+		prusage();
+		/* NOTREACHED */
+	}
+#endif
+
+	if (!(solicit && !forever)) {
+		do_fork();
+/*
+ * Added the next line to stop forking a second time
+ * Fraser Gardiner - Sun Microsystems Australia
+ */
+		forever = 1;
+	}
+
+	memset( (char *)&whereto, 0, sizeof(struct sockaddr_in) );
+	to->sin_family = AF_INET;
+	to->sin_addr.s_addr = inet_addr(sendaddress);
+
+	memset( (char *)&joinaddr, 0, sizeof(struct sockaddr_in) );
+	joinaddr.sin_family = AF_INET;
+	joinaddr.sin_addr.s_addr = inet_addr(recvaddress);
+
+#ifdef RDISC_SERVER
+	if (responder)
+		srandom((int)gethostid());
+#endif
+
+	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
+		logperror("socket");
+		exit(5);
+	}
+
+	setlinebuf( stdout );
+
+	signal_setup(SIGINT, finish );
+	signal_setup(SIGTERM, graceful_finish );
+	signal_setup(SIGHUP, initifs );
+	signal_setup(SIGALRM, timer );
+
+	sigemptyset(&sset);
+	sigemptyset(&sset_empty);
+	sigaddset(&sset, SIGALRM);
+	sigaddset(&sset, SIGHUP);
+	sigaddset(&sset, SIGTERM);
+	sigaddset(&sset, SIGINT);
+
+	init();
+	if (join(s, &joinaddr) < 0) {
+		logerr("Failed joining addresses\n");
+		exit (2);
+	}
+
+	timer();	/* start things going */
+
+	for (;;) {
+		u_char	packet[MAXPACKET];
+		int len = sizeof (packet);
+		socklen_t fromlen = sizeof (from);
+		int cc;
+
+		cc=recvfrom(s, (char *)packet, len, 0,
+			    (struct sockaddr *)&from, &fromlen);
+		if (cc<0) {
+			if (errno == EINTR)
+				continue;
+			logperror("recvfrom");
+			continue;
+		}
+
+		sigprocmask(SIG_SETMASK, &sset, NULL);
+		pr_pack( (char *)packet, cc, &from );
+		sigprocmask(SIG_SETMASK, &sset_empty, NULL);
+	}
+	/*NOTREACHED*/
+}
+
+#define TIMER_INTERVAL 	3
+#define GETIFCONF_TIMER	30
+
+static int left_until_advertise;
+
+/* Called every TIMER_INTERVAL */
+void timer()
+{
+	static int time;
+	static int left_until_getifconf;
+	static int left_until_solicit;
+
+
+	time += TIMER_INTERVAL;
+
+	left_until_getifconf -= TIMER_INTERVAL;
+	left_until_advertise -= TIMER_INTERVAL;
+	left_until_solicit -= TIMER_INTERVAL;
+
+	if (left_until_getifconf < 0) {
+		initifs();
+		left_until_getifconf = GETIFCONF_TIMER;
+	}
+#ifdef RDISC_SERVER
+	if (responder && left_until_advertise <= 0) {
+		ntransmitted++;
+		advertise(&whereto, lifetime);
+		if (ntransmitted < initial_advertisements)
+			left_until_advertise = initial_advert_interval;
+		else
+			left_until_advertise = min_adv_int +
+				((max_adv_int - min_adv_int) *
+				 (random() % 1000)/1000);
+	} else
+#endif
+	if (solicit && left_until_solicit <= 0) {
+		ntransmitted++;
+		solicitor(&whereto);
+		if (ntransmitted < max_solicitations)
+			left_until_solicit = solicitation_interval;
+		else {
+			solicit = 0;
+			if (!forever && nreceived == 0)
+				exit(5);
+		}
+	}
+	age_table(TIMER_INTERVAL);
+	alarm(TIMER_INTERVAL);
+}
+
+/*
+ * 			S O L I C I T O R
+ *
+ * Compose and transmit an ICMP ROUTER SOLICITATION REQUEST packet.
+ * The IP packet will be added on by the kernel.
+ */
+void
+solicitor(struct sockaddr_in *sin)
+{
+	static u_char outpack[MAXPACKET];
+	struct icmphdr *icp = (struct icmphdr *) ALLIGN(outpack);
+	int packetlen, i;
+
+	if (verbose) {
+		logtrace("Sending solicitation to %s\n",
+			 pr_name(sin->sin_addr));
+	}
+	icp->type = ICMP_ROUTER_SOLICITATION;
+	icp->code = 0;
+	icp->checksum = 0;
+	icp->un.gateway = 0; /* Reserved */
+	packetlen = 8;
+
+	/* Compute ICMP checksum here */
+	icp->checksum = in_cksum( (u_short *)icp, packetlen );
+
+	if (isbroadcast(sin))
+		i = sendbcast(s, (char *)outpack, packetlen);
+	else if (ismulticast(sin))
+		i = sendmcast(s, (char *)outpack, packetlen, sin);
+	else
+		i = sendto( s, (char *)outpack, packetlen, 0,
+			   (struct sockaddr *)sin, sizeof(struct sockaddr));
+
+	if( i < 0 || i != packetlen )  {
+		if( i<0 ) {
+		    logperror("solicitor:sendto");
+		}
+		logerr("wrote %s %d chars, ret=%d\n",
+			sendaddress, packetlen, i );
+	}
+}
+
+#ifdef RDISC_SERVER
+/*
+ * 			A V E R T I S E
+ *
+ * Compose and transmit an ICMP ROUTER ADVERTISEMENT packet.
+ * The IP packet will be added on by the kernel.
+ */
+void
+advertise(struct sockaddr_in *sin, int lft)
+{
+	static u_char outpack[MAXPACKET];
+	struct icmp_ra *rap = (struct icmp_ra *) ALLIGN(outpack);
+	struct icmp_ra_addr *ap;
+	int packetlen, i, cc;
+
+	if (verbose) {
+		logtrace("Sending advertisement to %s\n",
+			 pr_name(sin->sin_addr));
+	}
+
+	for (i = 0; i < num_interfaces; i++) {
+		rap->icmp_type = ICMP_ROUTER_ADVERTISEMENT;
+		rap->icmp_code = 0;
+		rap->icmp_cksum = 0;
+		rap->icmp_num_addrs = 0;
+		rap->icmp_wpa = 2;
+		rap->icmp_lifetime = htons(lft);
+		packetlen = 8;
+
+		/*
+		 * TODO handle multiple logical interfaces per
+		 * physical interface. (increment with rap->icmp_wpa * 4 for
+		 * each address.)
+		 */
+		ap = (struct icmp_ra_addr *)ALLIGN(outpack + ICMP_MINLEN);
+		ap->ira_addr = interfaces[i].localaddr.s_addr;
+		ap->ira_preference = htonl(interfaces[i].preference);
+		packetlen += rap->icmp_wpa * 4;
+		rap->icmp_num_addrs++;
+
+		/* Compute ICMP checksum here */
+		rap->icmp_cksum = in_cksum( (u_short *)rap, packetlen );
+
+		if (isbroadcast(sin))
+			cc = sendbcastif(s, (char *)outpack, packetlen,
+					&interfaces[i]);
+		else if (ismulticast(sin))
+			cc = sendmcastif( s, (char *)outpack, packetlen, sin,
+					&interfaces[i]);
+		else {
+			struct interface *ifp = &interfaces[i];
+			/*
+			 * Verify that the interface matches the destination
+			 * address.
+			 */
+			if ((sin->sin_addr.s_addr & ifp->netmask.s_addr) ==
+			    (ifp->address.s_addr & ifp->netmask.s_addr)) {
+				if (debug) {
+					logdebug("Unicast to %s ",
+						 pr_name(sin->sin_addr));
+					logdebug("on interface %s, %s\n",
+						 ifp->name,
+						 pr_name(ifp->address));
+				}
+				cc = sendto( s, (char *)outpack, packetlen, 0,
+					    (struct sockaddr *)sin,
+					    sizeof(struct sockaddr));
+			} else
+				cc = packetlen;
+		}
+		if( cc < 0 || cc != packetlen )  {
+			if (cc < 0) {
+				logperror("sendto");
+			} else {
+				logerr("wrote %s %d chars, ret=%d\n",
+				       sendaddress, packetlen, cc );
+			}
+		}
+	}
+}
+#endif
+
+/*
+ * 			P R _ T Y P E
+ *
+ * Convert an ICMP "type" field to a printable string.
+ */
+char *
+pr_type(int t)
+{
+	static char *ttab[] = {
+		"Echo Reply",
+		"ICMP 1",
+		"ICMP 2",
+		"Dest Unreachable",
+		"Source Quench",
+		"Redirect",
+		"ICMP 6",
+		"ICMP 7",
+		"Echo",
+		"Router Advertise",
+		"Router Solicitation",
+		"Time Exceeded",
+		"Parameter Problem",
+		"Timestamp",
+		"Timestamp Reply",
+		"Info Request",
+		"Info Reply",
+		"Netmask Request",
+		"Netmask Reply"
+	};
+
+	if ( t < 0 || t > 16 )
+		return("OUT-OF-RANGE");
+
+	return(ttab[t]);
+}
+
+/*
+ *			P R _ N A M E
+ *
+ * Return a string name for the given IP address.
+ */
+char *pr_name(struct in_addr addr)
+{
+	struct hostent *phe;
+	static char buf[80];
+
+	phe = gethostbyaddr((char *)&addr.s_addr, 4, AF_INET);
+	if (phe == NULL)
+		return( inet_ntoa(addr));
+	snprintf(buf, sizeof(buf), "%s (%s)", phe->h_name, inet_ntoa(addr));
+	return(buf);
+}
+
+/*
+ *			P R _ P A C K
+ *
+ * Print out the packet, if it came from us.  This logic is necessary
+ * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
+ * which arrive ('tis only fair).  This permits multiple copies of this
+ * program to be run without having intermingled output (or statistics!).
+ */
+void
+pr_pack(char *buf, int cc, struct sockaddr_in *from)
+{
+	struct iphdr *ip;
+	struct icmphdr *icp;
+	int i;
+	int hlen;
+
+	ip = (struct iphdr *) ALLIGN(buf);
+	hlen = ip->ihl << 2;
+	if (cc < hlen + 8) {
+		if (verbose)
+			logtrace("packet too short (%d bytes) from %s\n", cc,
+				 pr_name(from->sin_addr));
+		return;
+	}
+	cc -= hlen;
+	icp = (struct icmphdr *)ALLIGN(buf + hlen);
+
+	switch (icp->type) {
+	case ICMP_ROUTER_ADVERTISEMENT:
+	{
+		struct icmp_ra *rap = (struct icmp_ra *)ALLIGN(icp);
+		struct icmp_ra_addr *ap;
+
+#ifdef RDISC_SERVER
+		if (responder)
+			break;
+#endif
+
+		/* TBD verify that the link is multicast or broadcast */
+		/* XXX Find out the link it came in over? */
+		if (in_cksum((u_short *)ALLIGN(buf+hlen), cc)) {
+			if (verbose)
+				logtrace("ICMP %s from %s: Bad checksum\n",
+					 pr_type((int)rap->icmp_type),
+					 pr_name(from->sin_addr));
+			return;
+		}
+		if (rap->icmp_code != 0) {
+			if (verbose)
+				logtrace("ICMP %s from %s: Code = %d\n",
+					 pr_type((int)rap->icmp_type),
+					 pr_name(from->sin_addr),
+					 rap->icmp_code);
+			return;
+		}
+		if (rap->icmp_num_addrs < 1) {
+			if (verbose)
+				logtrace("ICMP %s from %s: No addresses\n",
+					 pr_type((int)rap->icmp_type),
+					 pr_name(from->sin_addr));
+			return;
+		}
+		if (rap->icmp_wpa < 2) {
+			if (verbose)
+				logtrace("ICMP %s from %s: Words/addr = %d\n",
+					 pr_type((int)rap->icmp_type),
+					 pr_name(from->sin_addr),
+					 rap->icmp_wpa);
+			return;
+		}
+		if ((unsigned)cc <
+		    8 + rap->icmp_num_addrs * rap->icmp_wpa * 4) {
+			if (verbose)
+				logtrace("ICMP %s from %s: Too short %d, %d\n",
+					      pr_type((int)rap->icmp_type),
+					      pr_name(from->sin_addr),
+					      cc,
+					      8 + rap->icmp_num_addrs * rap->icmp_wpa * 4);
+			return;
+		}
+
+		if (verbose)
+			logtrace("ICMP %s from %s, lifetime %d\n",
+				      pr_type((int)rap->icmp_type),
+				      pr_name(from->sin_addr),
+				      ntohs(rap->icmp_lifetime));
+
+		/* Check that at least one router address is a neighboor
+		 * on the arriving link.
+		 */
+		for (i = 0; (unsigned)i < rap->icmp_num_addrs; i++) {
+			struct in_addr ina;
+			ap = (struct icmp_ra_addr *)
+				ALLIGN(buf + hlen + 8 +
+				       i * rap->icmp_wpa * 4);
+			ina.s_addr = ap->ira_addr;
+			if (verbose)
+				logtrace("\taddress %s, preference 0x%x\n",
+					      pr_name(ina),
+					      (unsigned int)ntohl(ap->ira_preference));
+			if (is_directly_connected(ina))
+				record_router(ina,
+					      ntohl(ap->ira_preference),
+					      ntohs(rap->icmp_lifetime));
+		}
+		nreceived++;
+		if (!forever) {
+			do_fork();
+			forever = 1;
+/*
+ * The next line was added so that the alarm is set for the new procces
+ * Fraser Gardiner Sun Microsystems Australia
+ */
+			(void) alarm(TIMER_INTERVAL);
+		}
+		break;
+	}
+
+#ifdef RDISC_SERVER
+	case ICMP_ROUTER_SOLICITATION:
+	{
+		struct sockaddr_in sin;
+
+		if (!responder)
+			break;
+
+		/* TBD verify that the link is multicast or broadcast */
+		/* XXX Find out the link it came in over? */
+
+		if (in_cksum((u_short *)ALLIGN(buf+hlen), cc)) {
+			if (verbose)
+				logtrace("ICMP %s from %s: Bad checksum\n",
+					      pr_type((int)icp->type),
+					      pr_name(from->sin_addr));
+			return;
+		}
+		if (icp->code != 0) {
+			if (verbose)
+				logtrace("ICMP %s from %s: Code = %d\n",
+					      pr_type((int)icp->type),
+					      pr_name(from->sin_addr),
+					      icp->code);
+			return;
+		}
+
+		if (cc < ICMP_MINLEN) {
+			if (verbose)
+				logtrace("ICMP %s from %s: Too short %d, %d\n",
+					      pr_type((int)icp->type),
+					      pr_name(from->sin_addr),
+					      cc,
+					      ICMP_MINLEN);
+			return;
+		}
+
+		if (verbose)
+			logtrace("ICMP %s from %s\n",
+				      pr_type((int)icp->type),
+				      pr_name(from->sin_addr));
+
+		/* Check that ip_src is either a neighboor
+		 * on the arriving link or 0.
+		 */
+		sin.sin_family = AF_INET;
+		if (ip->saddr == 0) {
+			/* If it was sent to the broadcast address we respond
+			 * to the broadcast address.
+			 */
+			if (IN_CLASSD(ntohl(ip->daddr)))
+				sin.sin_addr.s_addr = htonl(0xe0000001);
+			else
+				sin.sin_addr.s_addr = INADDR_BROADCAST;
+			/* Restart the timer when we broadcast */
+			left_until_advertise = min_adv_int +
+				((max_adv_int - min_adv_int)
+				 * (random() % 1000)/1000);
+		} else {
+			sin.sin_addr.s_addr = ip->saddr;
+			if (!is_directly_connected(sin.sin_addr)) {
+				if (verbose)
+					logtrace("ICMP %s from %s: source not directly connected\n",
+						      pr_type((int)icp->type),
+						      pr_name(from->sin_addr));
+				break;
+			}
+		}
+		nreceived++;
+		ntransmitted++;
+		advertise(&sin, lifetime);
+		break;
+	}
+#endif
+	}
+}
+
+
+/*
+ *			I N _ C K S U M
+ *
+ * Checksum routine for Internet Protocol family headers (C Version)
+ *
+ */
+#if BYTE_ORDER == LITTLE_ENDIAN
+# define ODDBYTE(v)	(v)
+#elif BYTE_ORDER == BIG_ENDIAN
+# define ODDBYTE(v)	((u_short)(v) << 8)
+#else
+# define ODDBYTE(v)	htons((u_short)(v) << 8)
+#endif
+
+u_short in_cksum(u_short *addr, int len)
+{
+	register int nleft = len;
+	register u_short *w = addr;
+	register u_short answer;
+	register int sum = 0;
+
+	/*
+	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
+	 *  we add sequential 16 bit words to it, and at the end, fold
+	 *  back all the carry bits from the top 16 bits into the lower
+	 *  16 bits.
+	 */
+	while( nleft > 1 )  {
+		sum += *w++;
+		nleft -= 2;
+	}
+
+	/* mop up an odd byte, if necessary */
+	if( nleft == 1 )
+		sum += ODDBYTE(*(u_char *)w);	/* le16toh() may be unavailable on old systems */
+
+	/*
+	 * add back carry outs from top 16 bits to low 16 bits
+	 */
+	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
+	sum += (sum >> 16);			/* add carry */
+	answer = ~sum;				/* truncate to 16 bits */
+	return (answer);
+}
+
+/*
+ *			F I N I S H
+ *
+ * Print out statistics, and give up.
+ * Heavily buffered STDIO is used here, so that all the statistics
+ * will be written with 1 sys-write call.  This is nice when more
+ * than one copy of the program is running on a terminal;  it prevents
+ * the statistics output from becomming intermingled.
+ */
+void
+finish()
+{
+#ifdef RDISC_SERVER
+	if (responder) {
+		/* Send out a packet with a preference so that all
+		 * hosts will know that we are dead.
+		 *
+		 * Wrong comment, wrong code.
+		 *	ttl must be set to 0 instead. --ANK
+		 */
+		logerr("terminated\n");
+		ntransmitted++;
+		advertise(&whereto, 0);
+	}
+#endif
+	logtrace("\n----%s rdisc Statistics----\n", sendaddress );
+	logtrace("%d packets transmitted, ", ntransmitted );
+	logtrace("%d packets received, ", nreceived );
+	logtrace("\n");
+	(void) fflush(stdout);
+	exit(0);
+}
+
+void
+graceful_finish()
+{
+	discard_table();
+	finish();
+	exit(0);
+}
+
+
+/* From libc/rpc/pmap_rmt.c */
+
+int
+sendbcast(int s, char *packet, int packetlen)
+{
+	int i, cc;
+
+	for (i = 0; i < num_interfaces; i++) {
+		if ((interfaces[i].flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0)
+			continue;
+		cc = sendbcastif(s, packet, packetlen, &interfaces[i]);
+		if (cc!= packetlen) {
+			return (cc);
+		}
+	}
+	return (packetlen);
+}
+
+int
+sendbcastif(int s, char *packet, int packetlen, struct interface *ifp)
+{
+	int on;
+	int cc;
+	struct sockaddr_in baddr;
+
+	baddr.sin_family = AF_INET;
+	baddr.sin_addr = ifp->bcastaddr;
+	if (debug)
+		logdebug("Broadcast to %s\n",
+			 pr_name(baddr.sin_addr));
+	on = 1;
+	setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on));
+	cc = sendto(s, packet, packetlen, 0,
+		    (struct sockaddr *)&baddr, sizeof (struct sockaddr));
+	if (cc!= packetlen) {
+		logperror("sendbcast: sendto");
+		logerr("Cannot send broadcast packet to %s\n",
+		       pr_name(baddr.sin_addr));
+	}
+	on = 0;
+	setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on));
+	return (cc);
+}
+
+int
+sendmcast(int s, char *packet, int packetlen, struct sockaddr_in *sin)
+{
+	int i, cc;
+
+	for (i = 0; i < num_interfaces; i++) {
+		if ((interfaces[i].flags & (IFF_BROADCAST|IFF_POINTOPOINT|IFF_MULTICAST)) == 0)
+			continue;
+		cc = sendmcastif(s, packet, packetlen, sin, &interfaces[i]);
+		if (cc!= packetlen) {
+			return (cc);
+		}
+	}
+	return (packetlen);
+}
+
+int
+sendmcastif(int s, char *packet, int packetlen,	struct sockaddr_in *sin,
+	    struct interface *ifp)
+{
+	int cc;
+	struct ip_mreqn mreq;
+
+	memset(&mreq, 0, sizeof(mreq));
+	mreq.imr_ifindex = ifp->ifindex;
+	mreq.imr_address = ifp->localaddr;
+	if (debug)
+		logdebug("Multicast to interface %s, %s\n",
+			 ifp->name,
+			 pr_name(mreq.imr_address));
+	if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
+		       (char *)&mreq,
+		       sizeof(mreq)) < 0) {
+		logperror("setsockopt (IP_MULTICAST_IF)");
+		logerr("Cannot send multicast packet over interface %s, %s\n",
+		       ifp->name,
+		       pr_name(mreq.imr_address));
+		return (-1);
+	}
+	cc = sendto(s, packet, packetlen, 0,
+		    (struct sockaddr *)sin, sizeof (struct sockaddr));
+	if (cc!= packetlen) {
+		logperror("sendmcast: sendto");
+		logerr("Cannot send multicast packet over interface %s, %s\n",
+		       ifp->name, pr_name(mreq.imr_address));
+	}
+	return (cc);
+}
+
+void
+init()
+{
+	initifs();
+#ifdef RDISC_SERVER
+	{
+		int i;
+		for (i = 0; i < interfaces_size; i++)
+			interfaces[i].preference = preference;
+	}
+#endif
+}
+
+void
+initifs()
+{
+	int	sock;
+	struct ifconf ifc;
+	struct ifreq ifreq, *ifr;
+	struct sockaddr_in *sin;
+	int n, i;
+	char *buf;
+	int numifs;
+	unsigned bufsize;
+
+	sock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sock < 0) {
+		logperror("initifs: socket");
+		return;
+	}
+#ifdef SIOCGIFNUM
+	if (ioctl(sock, SIOCGIFNUM, (char *)&numifs) < 0) {
+		numifs = MAXIFS;
+	}
+#else
+	numifs = MAXIFS;
+#endif
+	bufsize = numifs * sizeof(struct ifreq);
+	buf = (char *)malloc(bufsize);
+	if (buf == NULL) {
+		logerr("out of memory\n");
+		(void) close(sock);
+		return;
+	}
+	if (interfaces != NULL)
+		(void) free(interfaces);
+	interfaces = (struct interface *)ALLIGN(malloc(numifs *
+					sizeof(struct interface)));
+	if (interfaces == NULL) {
+		logerr("out of memory\n");
+		(void) close(sock);
+		(void) free(buf);
+		return;
+	}
+	interfaces_size = numifs;
+
+	ifc.ifc_len = bufsize;
+	ifc.ifc_buf = buf;
+	if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
+		logperror("initifs: ioctl (get interface configuration)");
+		(void) close(sock);
+		(void) free(buf);
+		return;
+	}
+	ifr = ifc.ifc_req;
+	for (i = 0, n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) {
+		ifreq = *ifr;
+		if (strlen(ifreq.ifr_name) >= IFNAMSIZ)
+			continue;
+		if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
+			logperror("initifs: ioctl (get interface flags)");
+			continue;
+		}
+		if (ifr->ifr_addr.sa_family != AF_INET)
+			continue;
+		if ((ifreq.ifr_flags & IFF_UP) == 0)
+			continue;
+		if (ifreq.ifr_flags & IFF_LOOPBACK)
+			continue;
+		if ((ifreq.ifr_flags & (IFF_MULTICAST|IFF_BROADCAST|IFF_POINTOPOINT)) == 0)
+			continue;
+		strncpy(interfaces[i].name, ifr->ifr_name, IFNAMSIZ-1);
+
+		sin = (struct sockaddr_in *)ALLIGN(&ifr->ifr_addr);
+		interfaces[i].localaddr = sin->sin_addr;
+		interfaces[i].flags = ifreq.ifr_flags;
+		interfaces[i].netmask.s_addr = (__u32)0xffffffff;
+		if (ioctl(sock, SIOCGIFINDEX, (char *)&ifreq) < 0) {
+			logperror("initifs: ioctl (get ifindex)");
+			continue;
+		}
+		interfaces[i].ifindex = ifreq.ifr_ifindex;
+		if (ifreq.ifr_flags & IFF_POINTOPOINT) {
+			if (ioctl(sock, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
+				logperror("initifs: ioctl (get destination addr)");
+				continue;
+			}
+			sin = (struct sockaddr_in *)ALLIGN(&ifreq.ifr_addr);
+			/* A pt-pt link is identified by the remote address */
+			interfaces[i].address = sin->sin_addr;
+			interfaces[i].remoteaddr = sin->sin_addr;
+			/* Simulate broadcast for pt-pt */
+			interfaces[i].bcastaddr = sin->sin_addr;
+			interfaces[i].flags |= IFF_BROADCAST;
+		} else {
+			/* Non pt-pt links are identified by the local address */
+			interfaces[i].address = interfaces[i].localaddr;
+			interfaces[i].remoteaddr = interfaces[i].address;
+			if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
+				logperror("initifs: ioctl (get netmask)");
+				continue;
+			}
+			sin = (struct sockaddr_in *)ALLIGN(&ifreq.ifr_addr);
+			interfaces[i].netmask = sin->sin_addr;
+			if (ifreq.ifr_flags & IFF_BROADCAST) {
+				if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
+					logperror("initifs: ioctl (get broadcast address)");
+					continue;
+				}
+				sin = (struct sockaddr_in *)ALLIGN(&ifreq.ifr_addr);
+				interfaces[i].bcastaddr = sin->sin_addr;
+			}
+		}
+#ifdef notdef
+		if (debug)
+			logdebug("Found interface %s, flags 0x%x\n",
+				 pr_name(interfaces[i].localaddr),
+				 interfaces[i].flags);
+#endif
+		i++;
+	}
+	num_interfaces = i;
+#ifdef notdef
+	if (debug)
+		logdebug("Found %d interfaces\n", num_interfaces);
+#endif
+	(void) close(sock);
+	(void) free(buf);
+}
+
+int
+join(int sock, struct sockaddr_in *sin)
+{
+	int i, j;
+	struct ip_mreqn mreq;
+	int joined[num_interfaces];
+
+	memset(joined, 0, sizeof(joined));
+
+	if (isbroadcast(sin))
+		return (0);
+
+	mreq.imr_multiaddr = sin->sin_addr;
+	for (i = 0; i < num_interfaces; i++) {
+		for (j = 0; j < i; j++) {
+			if (joined[j] == interfaces[i].ifindex)
+				break;
+		}
+		if (j != i)
+			continue;
+
+		mreq.imr_ifindex = interfaces[i].ifindex;
+		mreq.imr_address.s_addr = 0;
+
+		if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+			       (char *)&mreq, sizeof(mreq)) < 0) {
+			logperror("setsockopt (IP_ADD_MEMBERSHIP)");
+			return (-1);
+		}
+
+		joined[i] = interfaces[i].ifindex;
+	}
+	return (0);
+}
+
+int support_multicast()
+{
+	int sock;
+	u_char ttl = 1;
+
+	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (sock < 0) {
+		logperror("support_multicast: socket");
+		return (0);
+	}
+
+	if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,
+		       (char *)&ttl, sizeof(ttl)) < 0) {
+		(void) close(sock);
+		return (0);
+	}
+	(void) close(sock);
+	return (1);
+}
+
+int
+is_directly_connected(struct in_addr in)
+{
+	int i;
+
+	for (i = 0; i < num_interfaces; i++) {
+		/* Check that the subnetwork numbers match */
+
+		if ((in.s_addr & interfaces[i].netmask.s_addr ) ==
+		    (interfaces[i].remoteaddr.s_addr & interfaces[i].netmask.s_addr))
+			return (1);
+	}
+	return (0);
+}
+
+/*
+ * TABLES
+ */
+struct table {
+	struct in_addr	router;
+	int		preference;
+	int		remaining_time;
+	int		in_kernel;
+	struct table	*next;
+};
+
+struct table *table;
+
+struct table *
+find_router(struct in_addr addr)
+{
+	struct table *tp;
+
+	tp = table;
+	while (tp) {
+		if (tp->router.s_addr == addr.s_addr)
+			return (tp);
+		tp = tp->next;
+	}
+	return (NULL);
+}
+
+int max_preference(void)
+{
+	struct table *tp;
+	int max = (int)INELIGIBLE_PREF;
+
+	tp = table;
+	while (tp) {
+		if (tp->preference > max)
+			max = tp->preference;
+		tp = tp->next;
+	}
+	return (max);
+}
+
+
+/* Note: this might leave the kernel with no default route for a short time. */
+void
+age_table(int time)
+{
+	struct table **tpp, *tp;
+	int recalculate_max = 0;
+	int max = max_preference();
+
+	tpp = &table;
+	while (*tpp != NULL) {
+		tp = *tpp;
+		tp->remaining_time -= time;
+		if (tp->remaining_time <= 0) {
+			*tpp = tp->next;
+			if (tp->in_kernel)
+				del_route(tp->router);
+			if (best_preference &&
+			    tp->preference == max)
+				recalculate_max++;
+			free((char *)tp);
+		} else {
+			tpp = &tp->next;
+		}
+	}
+	if (recalculate_max) {
+		int max = max_preference();
+
+		if (max != INELIGIBLE_PREF) {
+			tp = table;
+			while (tp) {
+				if (tp->preference == max && !tp->in_kernel) {
+					add_route(tp->router);
+					tp->in_kernel++;
+				}
+				tp = tp->next;
+			}
+		}
+	}
+}
+
+void discard_table(void)
+{
+	struct table **tpp, *tp;
+
+	tpp = &table;
+	while (*tpp != NULL) {
+		tp = *tpp;
+		*tpp = tp->next;
+		if (tp->in_kernel)
+			del_route(tp->router);
+		free((char *)tp);
+	}
+}
+
+
+void
+record_router(struct in_addr router, int preference, int ttl)
+{
+	struct table *tp;
+	int old_max = max_preference();
+	int changed_up = 0;	/* max preference could have increased */
+	int changed_down = 0;	/* max preference could have decreased */
+
+	if (ttl < 4)
+		preference = INELIGIBLE_PREF;
+
+	if (debug)
+		logdebug("Recording %s, ttl %d, preference 0x%x\n",
+			 pr_name(router),
+			 ttl,
+			 preference);
+	tp = find_router(router);
+	if (tp) {
+		if (tp->preference > preference &&
+		    tp->preference == old_max)
+			changed_down++;
+		else if (preference > tp->preference)
+			changed_up++;
+		tp->preference = preference;
+		tp->remaining_time = ttl;
+	} else {
+		if (preference > old_max)
+			changed_up++;
+		tp = (struct table *)ALLIGN(malloc(sizeof(struct table)));
+		if (tp == NULL) {
+			logerr("Out of memory\n");
+			return;
+		}
+		tp->router = router;
+		tp->preference = preference;
+		tp->remaining_time = ttl;
+		tp->in_kernel = 0;
+		tp->next = table;
+		table = tp;
+	}
+	if (!tp->in_kernel &&
+	    (!best_preference || tp->preference == max_preference()) &&
+	    tp->preference != INELIGIBLE_PREF) {
+		add_route(tp->router);
+		tp->in_kernel++;
+	}
+	if (tp->preference == INELIGIBLE_PREF && tp->in_kernel) {
+		del_route(tp->router);
+		tp->in_kernel = 0;
+	}
+	if (best_preference && changed_down) {
+		/* Check if we should add routes */
+		int new_max = max_preference();
+		if (new_max != INELIGIBLE_PREF) {
+			tp = table;
+			while (tp) {
+				if (tp->preference == new_max &&
+				    !tp->in_kernel) {
+					add_route(tp->router);
+					tp->in_kernel++;
+				}
+				tp = tp->next;
+			}
+		}
+	}
+	if (best_preference && (changed_up || changed_down)) {
+		/* Check if we should remove routes already in the kernel */
+		int new_max = max_preference();
+		tp = table;
+		while (tp) {
+			if (tp->preference < new_max && tp->in_kernel) {
+				del_route(tp->router);
+				tp->in_kernel = 0;
+			}
+			tp = tp->next;
+		}
+	}
+}
+
+void
+add_route(struct in_addr addr)
+{
+	if (debug)
+		logdebug("Add default route to %s\n", pr_name(addr));
+	rtioctl(addr, SIOCADDRT);
+}
+
+void
+del_route(struct in_addr addr)
+{
+	if (debug)
+		logdebug("Delete default route to %s\n", pr_name(addr));
+	rtioctl(addr, SIOCDELRT);
+}
+
+void
+rtioctl(struct in_addr addr, int op)
+{
+	int sock;
+	struct rtentry rt;
+	struct sockaddr_in *sin;
+
+	memset((char *)&rt, 0, sizeof(struct rtentry));
+	rt.rt_dst.sa_family = AF_INET;
+	rt.rt_gateway.sa_family = AF_INET;
+	rt.rt_genmask.sa_family = AF_INET;
+	sin = (struct sockaddr_in *)ALLIGN(&rt.rt_gateway);
+	sin->sin_addr = addr;
+	rt.rt_flags = RTF_UP | RTF_GATEWAY;
+
+	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (sock < 0) {
+		logperror("rtioctl: socket");
+		return;
+	}
+	if (ioctl(sock, op, (char *)&rt) < 0) {
+		if (!(op == SIOCADDRT && errno == EEXIST))
+			logperror("ioctl (add/delete route)");
+	}
+	(void) close(sock);
+}
+
+/*
+ * LOGGER
+ */
+
+void initlog(void)
+{
+	logging++;
+	openlog("in.rdiscd", LOG_PID | LOG_CONS, LOG_DAEMON);
+}
+
+
+void
+logperror(char *str)
+{
+	if (logging)
+		syslog(LOG_ERR, "%s: %m", str);
+	else
+		(void) fprintf(stderr, "%s: %s\n", str, strerror(errno));
+}
diff --git a/iputils/tftp.h b/iputils/tftp.h
new file mode 100644
index 0000000..baed7a9
--- /dev/null
+++ b/iputils/tftp.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)tftp.h	8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _ARPA_TFTP_H
+#define _ARPA_TFTP_H
+/*
+ * Trivial File Transfer Protocol (IEN-133)
+ */
+#define	SEGSIZE		512		/* data segment size */
+
+/*
+ * Packet types.
+ */
+#define	RRQ	01			/* read request */
+#define	WRQ	02			/* write request */
+#define	DATA	03			/* data packet */
+#define	ACK	04			/* acknowledgement */
+#define	ERROR	05			/* error code */
+
+struct	tftphdr {
+	short	th_opcode;		/* packet type */
+	union {
+		short	tu_block;	/* block # */
+		short	tu_code;	/* error code */
+		char	tu_stuff[1];	/* request packet stuff */
+	} th_u;
+	char	th_data[1];		/* data or error string */
+};
+
+#define	th_block	th_u.tu_block
+#define	th_code		th_u.tu_code
+#define	th_stuff	th_u.tu_stuff
+#define	th_msg		th_data
+
+/*
+ * Error codes.
+ */
+#define	EUNDEF		0		/* not defined */
+#define	ENOTFOUND	1		/* file not found */
+#define	EACCESS		2		/* access violation */
+#define	ENOSPACE	3		/* disk full or allocation exceeded */
+#define	EBADOP		4		/* illegal TFTP operation */
+#define	EBADID		5		/* unknown transfer ID */
+#define	EEXISTS		6		/* file already exists */
+#define	ENOUSER		7		/* no such user */
+
+
+extern int readit(FILE * file, struct tftphdr **dpp, int convert);
+extern void read_ahead(FILE *file, int convert);
+extern int writeit(FILE *file, struct tftphdr **dpp, int ct, int convert);
+extern int write_behind(FILE *file, int convert);
+extern int synchnet(int f);
+extern struct tftphdr *w_init(void);
+extern struct tftphdr *r_init(void);
+
+
+#endif /* _ARPA_TFTP_H */
diff --git a/iputils/tftpd.c b/iputils/tftpd.c
new file mode 100644
index 0000000..2a39ec4
--- /dev/null
+++ b/iputils/tftpd.c
@@ -0,0 +1,537 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)tftpd.c	5.13 (Berkeley) 2/26/91";*/
+/*static char rcsid[] = "$Id: tftpd.c,v 1.3 1993/08/01 18:28:53 mycroft Exp $";*/
+#endif /* not lint */
+
+/*
+ * Trivial file transfer protocol server.
+ *
+ * This version includes many modifications by Jim Guyton <guyton@rand-unix>
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <setjmp.h>
+#include <syslog.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "tftp.h"
+
+#ifndef MSG_CONFIRM
+#define MSG_CONFIRM 0
+#warning Please, upgrade kernel, otherwise this tftpd has no advantages.
+#endif
+
+#define	TIMEOUT		5
+
+int	peer;
+int	rexmtval = TIMEOUT;
+int	maxtimeout = 5*TIMEOUT;
+
+#define	PKTSIZE	SEGSIZE+4
+char	buf[PKTSIZE];
+char	ackbuf[PKTSIZE];
+union {
+	struct	sockaddr     sa;
+	struct	sockaddr_in  sin;
+	struct	sockaddr_in6 sin6;
+} from;
+socklen_t	fromlen;
+
+#define MAXARG	1
+char	*dirs[MAXARG+1];
+
+void tftp(struct tftphdr *tp, int size) __attribute__((noreturn));
+void nak(int error);
+int validate_access(char *filename, int mode);
+
+struct formats;
+
+void sendfile(struct formats *pf);
+void recvfile(struct formats *pf);
+
+
+int main(int ac, char **av)
+{
+	register struct tftphdr *tp;
+	register int n = 0;
+	int on = 1;
+
+	/* Sanity. If parent forgot to setuid() on us. */
+	if (geteuid() == 0) {
+		setgid(65534);
+		setuid(65534);
+	}
+
+	ac--; av++;
+	while (ac-- > 0 && n < MAXARG)
+		dirs[n++] = *av++;
+
+	openlog("tftpd", LOG_PID, LOG_DAEMON);
+	if (ioctl(0, FIONBIO, &on) < 0) {
+		syslog(LOG_ERR, "ioctl(FIONBIO): %m\n");
+		exit(1);
+	}
+	fromlen = sizeof (from);
+	n = recvfrom(0, buf, sizeof (buf), 0,
+	    (struct sockaddr *)&from, &fromlen);
+	if (n < 0) {
+		if (errno != EAGAIN)
+			syslog(LOG_ERR, "recvfrom: %m\n");
+		exit(1);
+	}
+	/*
+	 * Now that we have read the message out of the UDP
+	 * socket, we fork and exit.  Thus, inetd will go back
+	 * to listening to the tftp port, and the next request
+	 * to come in will start up a new instance of tftpd.
+	 *
+	 * We do this so that inetd can run tftpd in "wait" mode.
+	 * The problem with tftpd running in "nowait" mode is that
+	 * inetd may get one or more successful "selects" on the
+	 * tftp port before we do our receive, so more than one
+	 * instance of tftpd may be started up.  Worse, if tftpd
+	 * break before doing the above "recvfrom", inetd would
+	 * spawn endless instances, clogging the system.
+	 */
+	{
+		int pid;
+		int i;
+		socklen_t j;
+
+		for (i = 1; i < 20; i++) {
+		    pid = fork();
+		    if (pid < 0) {
+				sleep(i);
+				/*
+				 * flush out to most recently sent request.
+				 *
+				 * This may drop some request, but those
+				 * will be resent by the clients when
+				 * they timeout.  The positive effect of
+				 * this flush is to (try to) prevent more
+				 * than one tftpd being started up to service
+				 * a single request from a single client.
+				 */
+				j = sizeof from;
+				i = recvfrom(0, buf, sizeof (buf), 0,
+				    (struct sockaddr *)&from, &j);
+				if (i > 0) {
+					n = i;
+					fromlen = j;
+				}
+		    } else {
+				break;
+		    }
+		}
+		if (pid < 0) {
+			syslog(LOG_ERR, "fork: %m\n");
+			exit(1);
+		} else if (pid != 0) {
+			exit(0);
+		}
+	}
+	alarm(0);
+	close(0);
+	close(1);
+	peer = socket(from.sa.sa_family, SOCK_DGRAM, 0);
+	if (peer < 0) {
+		syslog(LOG_ERR, "socket: %m\n");
+		exit(1);
+	}
+	if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
+		syslog(LOG_ERR, "connect: %m\n");
+		exit(1);
+	}
+	tp = (struct tftphdr *)buf;
+	tp->th_opcode = ntohs(tp->th_opcode);
+	if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
+		tftp(tp, n);
+	exit(1);
+}
+
+struct formats {
+	char	*f_mode;
+	int	(*f_validate)(char *filename, int mode);
+	void	(*f_send)(struct formats*);
+	void	(*f_recv)(struct formats*);
+	int	f_convert;
+} formats[] = {
+	{ "netascii",	validate_access,	sendfile,	recvfile, 1 },
+	{ "octet",	validate_access,	sendfile,	recvfile, 0 },
+#ifdef notdef
+	{ "mail",	validate_user,		sendmail,	recvmail, 1 },
+#endif
+	{ 0 }
+};
+
+/*
+ * Handle initial connection protocol.
+ */
+void tftp(struct tftphdr *tp, int size)
+{
+	register char *cp;
+	int first = 1, ecode;
+	register struct formats *pf;
+	char *filename, *mode = NULL;
+
+	filename = cp = tp->th_stuff;
+again:
+	while (cp < buf + size) {
+		if (*cp == '\0')
+			break;
+		cp++;
+	}
+	if (*cp != '\0') {
+		nak(EBADOP);
+		exit(1);
+	}
+	if (first) {
+		mode = ++cp;
+		first = 0;
+		goto again;
+	}
+	for (cp = mode; *cp; cp++)
+		if (isupper(*cp))
+			*cp = tolower(*cp);
+	for (pf = formats; pf->f_mode; pf++)
+		if (strcmp(pf->f_mode, mode) == 0)
+			break;
+	if (pf->f_mode == 0) {
+		nak(EBADOP);
+		exit(1);
+	}
+	ecode = (*pf->f_validate)(filename, tp->th_opcode);
+	if (ecode) {
+		nak(ecode);
+		exit(1);
+	}
+	if (tp->th_opcode == WRQ)
+		(*pf->f_recv)(pf);
+	else
+		(*pf->f_send)(pf);
+	exit(0);
+}
+
+
+FILE *file;
+
+/*
+ * Validate file access.  Since we
+ * have no uid or gid, for now require
+ * file to exist and be publicly
+ * readable/writable.
+ * If we were invoked with arguments
+ * from inetd then the file must also be
+ * in one of the given directory prefixes.
+ * Note also, full path name must be
+ * given as we have no login directory.
+ */
+int validate_access(char *filename, int mode)
+{
+	struct stat stbuf;
+	int    fd;
+	char  *cp;
+	char   fnamebuf[1024+512];
+
+	for (cp = filename; *cp; cp++) {
+		if(*cp == '.' && (cp == filename || strncmp(cp-1, "/../", 4) == 0)) {
+			syslog(LOG_ERR, "bad path %s", filename);
+			return(EACCESS);
+		}
+	}
+
+	if (*filename == '/')
+		filename++;
+
+	if (!*dirs) {
+		syslog(LOG_ERR, "no dirs");
+		return EACCESS;
+	}
+	snprintf(fnamebuf, sizeof(fnamebuf)-1, "%s/%s", *dirs, filename);
+	filename = fnamebuf;
+
+	if (stat(filename, &stbuf) < 0) {
+		syslog(LOG_ERR, "stat %s : %m", filename);
+		return (errno == ENOENT ? ENOTFOUND : EACCESS);
+	}
+	if (mode == RRQ) {
+		if ((stbuf.st_mode&(S_IREAD >> 6)) == 0) {
+			syslog(LOG_ERR, "not readable %s", filename);
+			return (EACCESS);
+		}
+	} else {
+		if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0) {
+			syslog(LOG_ERR, "not writable %s", filename);
+			return (EACCESS);
+		}
+	}
+	fd = open(filename, mode == RRQ ? 0 : 1);
+	if (fd < 0) {
+		syslog(LOG_ERR, "cannot open %s: %m", filename);
+		return (errno + 100);
+	}
+	file = fdopen(fd, (mode == RRQ)? "r":"w");
+	if (file == NULL) {
+		return errno+100;
+	}
+	return (0);
+}
+
+int	confirmed;
+int	timeout;
+jmp_buf	timeoutbuf;
+
+void timer(int signo)
+{
+	confirmed = 0;
+	timeout += rexmtval;
+	if (timeout >= maxtimeout)
+		exit(1);
+	longjmp(timeoutbuf, 1);
+}
+
+/*
+ * Send the requested file.
+ */
+void sendfile(struct formats *pf)
+{
+	struct tftphdr *dp;
+	register struct tftphdr *ap;    /* ack packet */
+	volatile int block = 1;
+	int size, n;
+
+	confirmed = 0;
+	signal(SIGALRM, timer);
+	dp = r_init();
+	ap = (struct tftphdr *)ackbuf;
+	do {
+		size = readit(file, &dp, pf->f_convert);
+		if (size < 0) {
+			nak(errno + 100);
+			goto abort;
+		}
+		dp->th_opcode = htons((u_short)DATA);
+		dp->th_block = htons((u_short)block);
+		timeout = 0;
+		(void) setjmp(timeoutbuf);
+
+send_data:
+		if (send(peer, dp, size + 4, confirmed) != size + 4) {
+			syslog(LOG_ERR, "tftpd: write: %m\n");
+			goto abort;
+		}
+		confirmed = 0;
+		read_ahead(file, pf->f_convert);
+		for ( ; ; ) {
+			alarm(rexmtval);        /* read the ack */
+			n = recv(peer, ackbuf, sizeof (ackbuf), 0);
+			alarm(0);
+			if (n < 0) {
+				syslog(LOG_ERR, "tftpd: read: %m\n");
+				goto abort;
+			}
+			ap->th_opcode = ntohs((u_short)ap->th_opcode);
+			ap->th_block = ntohs((u_short)ap->th_block);
+
+			if (ap->th_opcode == ERROR)
+				goto abort;
+
+			if (ap->th_opcode == ACK) {
+				if (ap->th_block == block) {
+					confirmed = MSG_CONFIRM;
+					break;
+				}
+				/* Re-synchronize with the other side */
+				synchnet(peer);
+				if (ap->th_block == (block -1)) {
+					goto send_data;
+				}
+			}
+
+		}
+		block++;
+	} while (size == SEGSIZE);
+abort:
+	(void) fclose(file);
+}
+
+void justquit(int signo)
+{
+	exit(0);
+}
+
+
+/*
+ * Receive a file.
+ */
+void recvfile(struct formats *pf)
+{
+	struct tftphdr *dp;
+	register struct tftphdr *ap;    /* ack buffer */
+	volatile int block = 0, n, size;
+
+	confirmed = 0;
+	signal(SIGALRM, timer);
+	dp = w_init();
+	ap = (struct tftphdr *)ackbuf;
+	do {
+		timeout = 0;
+		ap->th_opcode = htons((u_short)ACK);
+		ap->th_block = htons((u_short)block);
+		block++;
+		(void) setjmp(timeoutbuf);
+send_ack:
+		if (send(peer, ackbuf, 4, confirmed) != 4) {
+			syslog(LOG_ERR, "tftpd: write: %m\n");
+			goto abort;
+		}
+		confirmed = 0;
+		write_behind(file, pf->f_convert);
+		for ( ; ; ) {
+			alarm(rexmtval);
+			n = recv(peer, dp, PKTSIZE, 0);
+			alarm(0);
+			if (n < 0) {            /* really? */
+				syslog(LOG_ERR, "tftpd: read: %m\n");
+				goto abort;
+			}
+			dp->th_opcode = ntohs((u_short)dp->th_opcode);
+			dp->th_block = ntohs((u_short)dp->th_block);
+			if (dp->th_opcode == ERROR)
+				goto abort;
+			if (dp->th_opcode == DATA) {
+				if (dp->th_block == block) {
+					confirmed = MSG_CONFIRM;
+					break;   /* normal */
+				}
+				/* Re-synchronize with the other side */
+				(void) synchnet(peer);
+				if (dp->th_block == (block-1))
+					goto send_ack;          /* rexmit */
+			}
+		}
+		/*  size = write(file, dp->th_data, n - 4); */
+		size = writeit(file, &dp, n - 4, pf->f_convert);
+		if (size != (n-4)) {                    /* ahem */
+			if (size < 0) nak(errno + 100);
+			else nak(ENOSPACE);
+			goto abort;
+		}
+	} while (size == SEGSIZE);
+	write_behind(file, pf->f_convert);
+	(void) fclose(file);            /* close data file */
+
+	ap->th_opcode = htons((u_short)ACK);    /* send the "final" ack */
+	ap->th_block = htons((u_short)(block));
+	(void) send(peer, ackbuf, 4, confirmed);
+
+	signal(SIGALRM, justquit);      /* just quit on timeout */
+	alarm(rexmtval);
+	n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
+	alarm(0);
+	if (n >= 4 &&                   /* if read some data */
+	    dp->th_opcode == DATA &&    /* and got a data block */
+	    block == dp->th_block) {	/* then my last ack was lost */
+		(void) send(peer, ackbuf, 4, 0);     /* resend final ack */
+	}
+abort:
+	return;
+}
+
+struct errmsg {
+	int	e_code;
+	char	*e_msg;
+} errmsgs[] = {
+	{ EUNDEF,	"Undefined error code" },
+	{ ENOTFOUND,	"File not found" },
+	{ EACCESS,	"Access violation" },
+	{ ENOSPACE,	"Disk full or allocation exceeded" },
+	{ EBADOP,	"Illegal TFTP operation" },
+	{ EBADID,	"Unknown transfer ID" },
+	{ EEXISTS,	"File already exists" },
+	{ ENOUSER,	"No such user" },
+	{ -1,		0 }
+};
+
+/*
+ * Send a nak packet (error message).
+ * Error code passed in is one of the
+ * standard TFTP codes, or a UNIX errno
+ * offset by 100.
+ */
+void nak(int error)
+{
+	register struct tftphdr *tp;
+	int length;
+	register struct errmsg *pe;
+
+	tp = (struct tftphdr *)buf;
+	tp->th_opcode = htons((u_short)ERROR);
+	tp->th_code = htons((u_short)error);
+	for (pe = errmsgs; pe->e_code >= 0; pe++)
+		if (pe->e_code == error)
+			break;
+	if (pe->e_code < 0) {
+		pe->e_msg = strerror(error - 100);
+		tp->th_code = EUNDEF;   /* set 'undef' errorcode */
+	}
+	strcpy(tp->th_msg, pe->e_msg);
+	length = strlen(pe->e_msg);
+	tp->th_msg[length] = '\0';
+	length += 5;
+	if (send(peer, buf, length, 0) != length)
+		syslog(LOG_ERR, "nak: %m\n");
+}
diff --git a/iputils/tftpsubs.c b/iputils/tftpsubs.c
new file mode 100644
index 0000000..d362797
--- /dev/null
+++ b/iputils/tftpsubs.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)tftpsubs.c	5.6 (Berkeley) 2/28/91";*/
+/* static char rcsid[] = "$Id: tftpsubs.c,v 1.2 1993/08/01 18:07:04 mycroft Exp $"; */
+#endif /* not lint */
+
+/* Simple minded read-ahead/write-behind subroutines for tftp user and
+   server.  Written originally with multiple buffers in mind, but current
+   implementation has two buffer logic wired in.
+
+   Todo:  add some sort of final error check so when the write-buffer
+   is finally flushed, the caller can detect if the disk filled up
+   (or had an i/o error) and return a nak to the other side.
+
+			Jim Guyton 10/85
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include "tftp.h"
+
+#define PKTSIZE SEGSIZE+4       /* should be moved to tftp.h */
+
+struct bf {
+	int counter;            /* size of data in buffer, or flag */
+	char buf[PKTSIZE];      /* room for data packet */
+} bfs[2];
+
+				/* Values for bf.counter  */
+#define BF_ALLOC -3             /* alloc'd but not yet filled */
+#define BF_FREE  -2             /* free */
+/* [-1 .. SEGSIZE] = size of data in the data buffer */
+
+static int nextone;     /* index of next buffer to use */
+static int current;     /* index of buffer in use */
+
+			/* control flags for crlf conversions */
+int newline = 0;        /* fillbuf: in middle of newline expansion */
+int prevchar = -1;      /* putbuf: previous char (cr check) */
+
+struct tftphdr *rw_init(int);
+
+struct tftphdr *w_init() { return rw_init(0); }         /* write-behind */
+struct tftphdr *r_init() { return rw_init(1); }         /* read-ahead */
+
+/* init for either read-ahead or write-behind */
+/* x is zero for write-behind, one for read-head */
+struct tftphdr *rw_init(int x)
+{
+	newline = 0;            /* init crlf flag */
+	prevchar = -1;
+	bfs[0].counter =  BF_ALLOC;     /* pass out the first buffer */
+	current = 0;
+	bfs[1].counter = BF_FREE;
+	nextone = x;                    /* ahead or behind? */
+	return (struct tftphdr *)bfs[0].buf;
+}
+
+
+/* Have emptied current buffer by sending to net and getting ack.
+   Free it and return next buffer filled with data.
+ */
+int readit(FILE * file, struct tftphdr **dpp, int convert)
+{
+	struct bf *b;
+
+	bfs[current].counter = BF_FREE; /* free old one */
+	current = !current;             /* "incr" current */
+
+	b = &bfs[current];              /* look at new buffer */
+	if (b->counter == BF_FREE)      /* if it's empty */
+		read_ahead(file, convert);      /* fill it */
+#if 0
+	assert(b->counter != BF_FREE);  /* check */
+#endif
+	*dpp = (struct tftphdr *)b->buf;        /* set caller's ptr */
+	return b->counter;
+}
+
+/*
+ * fill the input buffer, doing ascii conversions if requested
+ * conversions are  lf -> cr,lf  and cr -> cr, nul
+ */
+void read_ahead(FILE *file, int convert)
+{
+	register int i;
+	register char *p;
+	register int c;
+	struct bf *b;
+	struct tftphdr *dp;
+
+	b = &bfs[nextone];              /* look at "next" buffer */
+	if (b->counter != BF_FREE)      /* nop if not free */
+		return;
+	nextone = !nextone;             /* "incr" next buffer ptr */
+
+	dp = (struct tftphdr *)b->buf;
+
+	if (convert == 0) {
+		b->counter = read(fileno(file), dp->th_data, SEGSIZE);
+		return;
+	}
+
+	p = dp->th_data;
+	for (i = 0 ; i < SEGSIZE; i++) {
+		if (newline) {
+			if (prevchar == '\n')
+				c = '\n';       /* lf to cr,lf */
+			else    c = '\0';       /* cr to cr,nul */
+			newline = 0;
+		}
+		else {
+			c = getc(file);
+			if (c == EOF) break;
+			if (c == '\n' || c == '\r') {
+				prevchar = c;
+				c = '\r';
+				newline = 1;
+			}
+		}
+	       *p++ = c;
+	}
+	b->counter = (int)(p - dp->th_data);
+}
+
+/* Update count associated with the buffer, get new buffer
+   from the queue.  Calls write_behind only if next buffer not
+   available.
+ */
+int writeit(FILE *file, struct tftphdr **dpp, int ct, int convert)
+{
+	bfs[current].counter = ct;      /* set size of data to write */
+	current = !current;             /* switch to other buffer */
+	if (bfs[current].counter != BF_FREE)     /* if not free */
+		write_behind(file, convert);     /* flush it */
+	bfs[current].counter = BF_ALLOC;        /* mark as alloc'd */
+	*dpp =  (struct tftphdr *)bfs[current].buf;
+	return ct;                      /* this is a lie of course */
+}
+
+/*
+ * Output a buffer to a file, converting from netascii if requested.
+ * CR,NUL -> CR  and CR,LF => LF.
+ * Note spec is undefined if we get CR as last byte of file or a
+ * CR followed by anything else.  In this case we leave it alone.
+ */
+int write_behind(FILE *file, int convert)
+{
+	char *buf;
+	int count;
+	register int ct;
+	register char *p;
+	register int c;                 /* current character */
+	struct bf *b;
+	struct tftphdr *dp;
+
+	b = &bfs[nextone];
+	if (b->counter < -1)            /* anything to flush? */
+		return 0;               /* just nop if nothing to do */
+
+	count = b->counter;             /* remember byte count */
+	b->counter = BF_FREE;           /* reset flag */
+	dp = (struct tftphdr *)b->buf;
+	nextone = !nextone;             /* incr for next time */
+	buf = dp->th_data;
+
+	if (count <= 0) return -1;      /* nak logic? */
+
+	if (convert == 0)
+		return write(fileno(file), buf, count);
+
+	p = buf;
+	ct = count;
+	while (ct--) {                  /* loop over the buffer */
+	    c = *p++;                   /* pick up a character */
+	    if (prevchar == '\r') {     /* if prev char was cr */
+		if (c == '\n')          /* if have cr,lf then just */
+		   fseek(file, -1, 1);  /* smash lf on top of the cr */
+		else
+		   if (c == '\0')       /* if have cr,nul then */
+			goto skipit;    /* just skip over the putc */
+		/* else just fall through and allow it */
+	    }
+	    putc(c, file);
+skipit:
+	    prevchar = c;
+	}
+	return count;
+}
+
+
+/* When an error has occurred, it is possible that the two sides
+ * are out of synch.  Ie: that what I think is the other side's
+ * response to packet N is really their response to packet N-1.
+ *
+ * So, to try to prevent that, we flush all the input queued up
+ * for us on the network connection on our host.
+ *
+ * We return the number of packets we flushed (mostly for reporting
+ * when trace is active).
+ */
+
+int synchnet(int f)
+{
+	int j = 0;
+	char dummy;
+
+	while (1) {
+		if (recv(f, &dummy, 1, MSG_DONTWAIT) < 0)
+			break;
+		j++;
+	}
+	return j;
+}
diff --git a/iputils/tracepath.c b/iputils/tracepath.c
new file mode 100644
index 0000000..be90231
--- /dev/null
+++ b/iputils/tracepath.c
@@ -0,0 +1,453 @@
+/*
+ * tracepath.c
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <linux/types.h>
+#include <linux/errqueue.h>
+#include <errno.h>
+#include <string.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <arpa/inet.h>
+#ifdef USE_IDN
+#include <idna.h>
+#include <locale.h>
+#endif
+
+#ifndef IP_PMTUDISC_PROBE
+#define IP_PMTUDISC_PROBE	3
+#endif
+
+#define MAX_HOPS_LIMIT		255
+#define MAX_HOPS_DEFAULT	30
+
+struct hhistory
+{
+	int	hops;
+	struct timeval sendtime;
+};
+
+struct hhistory his[64];
+int hisptr;
+
+struct sockaddr_in target;
+__u16 base_port;
+int max_hops = MAX_HOPS_DEFAULT;
+
+const int overhead = 28;
+int mtu = 65535;
+void *pktbuf;
+int hops_to = -1;
+int hops_from = -1;
+int no_resolve = 0;
+int show_both = 0;
+
+#define HOST_COLUMN_SIZE	52
+
+struct probehdr
+{
+	__u32 ttl;
+	struct timeval tv;
+};
+
+void data_wait(int fd)
+{
+	fd_set fds;
+	struct timeval tv;
+	FD_ZERO(&fds);
+	FD_SET(fd, &fds);
+	tv.tv_sec = 1;
+	tv.tv_usec = 0;
+	select(fd+1, &fds, NULL, NULL, &tv);
+}
+
+void print_host(const char *a, const char *b, int both)
+{
+	int plen;
+	plen = printf("%s", a);
+	if (both)
+		plen += printf(" (%s)", b);
+	if (plen >= HOST_COLUMN_SIZE)
+		plen = HOST_COLUMN_SIZE - 1;
+	printf("%*s", HOST_COLUMN_SIZE - plen, "");
+}
+
+int recverr(int fd, int ttl)
+{
+	int res;
+	struct probehdr rcvbuf;
+	char cbuf[512];
+	struct iovec  iov;
+	struct msghdr msg;
+	struct cmsghdr *cmsg;
+	struct sock_extended_err *e;
+	struct sockaddr_in addr;
+	struct timeval tv;
+	struct timeval *rettv;
+	int slot;
+	int rethops;
+	int sndhops;
+	int progress = -1;
+	int broken_router;
+
+restart:
+	memset(&rcvbuf, -1, sizeof(rcvbuf));
+	iov.iov_base = &rcvbuf;
+	iov.iov_len = sizeof(rcvbuf);
+	msg.msg_name = (__u8*)&addr;
+	msg.msg_namelen = sizeof(addr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_flags = 0;
+	msg.msg_control = cbuf;
+	msg.msg_controllen = sizeof(cbuf);
+
+	gettimeofday(&tv, NULL);
+	res = recvmsg(fd, &msg, MSG_ERRQUEUE);
+	if (res < 0) {
+		if (errno == EAGAIN)
+			return progress;
+		goto restart;
+	}
+
+	progress = mtu;
+
+	rethops = -1;
+	sndhops = -1;
+	e = NULL;
+	rettv = NULL;
+	slot = ntohs(addr.sin_port) - base_port;
+	if (slot>=0 && slot < 63 && his[slot].hops) {
+		sndhops = his[slot].hops;
+		rettv = &his[slot].sendtime;
+		his[slot].hops = 0;
+	}
+	broken_router = 0;
+	if (res == sizeof(rcvbuf)) {
+		if (rcvbuf.ttl == 0 || rcvbuf.tv.tv_sec == 0) {
+			broken_router = 1;
+		} else {
+			sndhops = rcvbuf.ttl;
+			rettv = &rcvbuf.tv;
+		}
+	}
+
+	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+		if (cmsg->cmsg_level == SOL_IP) {
+			if (cmsg->cmsg_type == IP_RECVERR) {
+				e = (struct sock_extended_err *) CMSG_DATA(cmsg);
+			} else if (cmsg->cmsg_type == IP_TTL) {
+				memcpy(&rethops, CMSG_DATA(cmsg), sizeof(rethops));
+			} else {
+				printf("cmsg:%d\n ", cmsg->cmsg_type);
+			}
+		}
+	}
+	if (e == NULL) {
+		printf("no info\n");
+		return 0;
+	}
+	if (e->ee_origin == SO_EE_ORIGIN_LOCAL) {
+		printf("%2d?: %*s ", ttl, -(HOST_COLUMN_SIZE - 1), "[LOCALHOST]");
+	} else if (e->ee_origin == SO_EE_ORIGIN_ICMP) {
+		char abuf[128];
+		struct sockaddr_in *sin = (struct sockaddr_in*)(e+1);
+		struct hostent *h = NULL;
+		char *idn = NULL;
+
+		inet_ntop(AF_INET, &sin->sin_addr, abuf, sizeof(abuf));
+
+		if (sndhops>0)
+			printf("%2d:  ", sndhops);
+		else
+			printf("%2d?: ", ttl);
+
+		if (!no_resolve || show_both) {
+			fflush(stdout);
+			h = gethostbyaddr((char *) &sin->sin_addr, sizeof(sin->sin_addr), AF_INET);
+		}
+
+#ifdef USE_IDN
+		if (h && idna_to_unicode_lzlz(h->h_name, &idn, 0) != IDNA_SUCCESS)
+			idn = NULL;
+#endif
+		if (no_resolve)
+			print_host(abuf, h ? (idn ? idn : h->h_name) : abuf, show_both);
+		else
+			print_host(h ? (idn ? idn : h->h_name) : abuf, abuf, show_both);
+
+#ifdef USE_IDN
+		free(idn);
+#endif
+	}
+
+	if (rettv) {
+		int diff = (tv.tv_sec-rettv->tv_sec)*1000000+(tv.tv_usec-rettv->tv_usec);
+		printf("%3d.%03dms ", diff/1000, diff%1000);
+		if (broken_router)
+			printf("(This broken router returned corrupted payload) ");
+	}
+
+	switch (e->ee_errno) {
+	case ETIMEDOUT:
+		printf("\n");
+		break;
+	case EMSGSIZE:
+		printf("pmtu %d\n", e->ee_info);
+		mtu = e->ee_info;
+		progress = mtu;
+		break;
+	case ECONNREFUSED:
+		printf("reached\n");
+		hops_to = sndhops<0 ? ttl : sndhops;
+		hops_from = rethops;
+		return 0;
+	case EPROTO:
+		printf("!P\n");
+		return 0;
+	case EHOSTUNREACH:
+		if (e->ee_origin == SO_EE_ORIGIN_ICMP &&
+		    e->ee_type == 11 &&
+		    e->ee_code == 0) {
+			if (rethops>=0) {
+				if (rethops<=64)
+					rethops = 65-rethops;
+				else if (rethops<=128)
+					rethops = 129-rethops;
+				else
+					rethops = 256-rethops;
+				if (sndhops>=0 && rethops != sndhops)
+					printf("asymm %2d ", rethops);
+				else if (sndhops<0 && rethops != ttl)
+					printf("asymm %2d ", rethops);
+			}
+			printf("\n");
+			break;
+		}
+		printf("!H\n");
+		return 0;
+	case ENETUNREACH:
+		printf("!N\n");
+		return 0;
+	case EACCES:
+		printf("!A\n");
+		return 0;
+	default:
+		printf("\n");
+		errno = e->ee_errno;
+		perror("NET ERROR");
+		return 0;
+	}
+	goto restart;
+}
+
+int probe_ttl(int fd, int ttl)
+{
+	int i;
+	struct probehdr *hdr = pktbuf;
+
+	memset(pktbuf, 0, mtu);
+restart:
+	for (i=0; i<10; i++) {
+		int res;
+
+		hdr->ttl = ttl;
+		target.sin_port = htons(base_port + hisptr);
+		gettimeofday(&hdr->tv, NULL);
+		his[hisptr].hops = ttl;
+		his[hisptr].sendtime = hdr->tv;
+		if (sendto(fd, pktbuf, mtu-overhead, 0, (struct sockaddr*)&target, sizeof(target)) > 0)
+			break;
+		res = recverr(fd, ttl);
+		his[hisptr].hops = 0;
+		if (res==0)
+			return 0;
+		if (res > 0)
+			goto restart;
+	}
+	hisptr = (hisptr + 1)&63;
+
+	if (i<10) {
+		data_wait(fd);
+		if (recv(fd, pktbuf, mtu, MSG_DONTWAIT) > 0) {
+			printf("%2d?: reply received 8)\n", ttl);
+			return 0;
+		}
+		return recverr(fd, ttl);
+	}
+
+	printf("%2d:  send failed\n", ttl);
+	return 0;
+}
+
+static void usage(void) __attribute((noreturn));
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: tracepath [-n] [-b] [-l <len>] [-p port] <destination>\n");
+	exit(-1);
+}
+
+int
+main(int argc, char **argv)
+{
+	struct hostent *he;
+	int fd;
+	int on;
+	int ttl;
+	char *p;
+	int ch;
+#ifdef USE_IDN
+	int rc;
+	setlocale(LC_ALL, "");
+#endif
+
+	while ((ch = getopt(argc, argv, "nbh?l:m:p:")) != EOF) {
+		switch(ch) {
+		case 'n':
+			no_resolve = 1;
+			break;
+		case 'b':
+			show_both = 1;
+			break;
+		case 'l':
+			if ((mtu = atoi(optarg)) <= overhead) {
+				fprintf(stderr, "Error: pktlen must be > %d and <= %d.\n",
+					overhead, INT_MAX);
+				exit(1);
+			}
+			break;
+		case 'm':
+			max_hops = atoi(optarg);
+			if (max_hops < 0 || max_hops > MAX_HOPS_LIMIT) {
+				fprintf(stderr,
+					"Error: max hops must be 0 .. %d (inclusive).\n",
+					MAX_HOPS_LIMIT);
+			}
+			break;
+		case 'p':
+			base_port = atoi(optarg);
+			break;
+		default:
+			usage();
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 1)
+		usage();
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd < 0) {
+		perror("socket");
+		exit(1);
+	}
+	target.sin_family = AF_INET;
+
+	/* Backward compatiblity */
+	if (!base_port) {
+		p = strchr(argv[0], '/');
+		if (p) {
+			*p = 0;
+			base_port = atoi(p+1);
+		} else
+			base_port = 44444;
+	}
+
+	p = argv[0];
+#ifdef USE_IDN
+	rc = idna_to_ascii_lz(argv[0], &p, 0);
+	if (rc != IDNA_SUCCESS) {
+		fprintf(stderr, "IDNA encoding failed: %s\n", idna_strerror(rc));
+		exit(2);
+	}
+#endif
+
+	he = gethostbyname(p);
+	if (he == NULL) {
+		herror("gethostbyname");
+		exit(1);
+	}
+
+#ifdef USE_IDN
+	free(p);
+#endif
+
+	memcpy(&target.sin_addr, he->h_addr, 4);
+
+	on = IP_PMTUDISC_PROBE;
+	if (setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &on, sizeof(on)) &&
+	    (on = IP_PMTUDISC_DO,
+	     setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &on, sizeof(on)))) {
+		perror("IP_MTU_DISCOVER");
+		exit(1);
+	}
+	on = 1;
+	if (setsockopt(fd, SOL_IP, IP_RECVERR, &on, sizeof(on))) {
+		perror("IP_RECVERR");
+		exit(1);
+	}
+	if (setsockopt(fd, SOL_IP, IP_RECVTTL, &on, sizeof(on))) {
+		perror("IP_RECVTTL");
+		exit(1);
+	}
+
+	pktbuf = malloc(mtu);
+	if (!pktbuf) {
+		perror("malloc");
+		exit(1);
+	}
+
+	for (ttl = 1; ttl <= max_hops; ttl++) {
+		int res;
+		int i;
+
+		on = ttl;
+		if (setsockopt(fd, SOL_IP, IP_TTL, &on, sizeof(on))) {
+			perror("IP_TTL");
+			exit(1);
+		}
+
+restart:
+		for (i=0; i<3; i++) {
+			int old_mtu;
+
+			old_mtu = mtu;
+			res = probe_ttl(fd, ttl);
+			if (mtu != old_mtu)
+				goto restart;
+			if (res == 0)
+				goto done;
+			if (res > 0)
+				break;
+		}
+
+		if (res < 0)
+			printf("%2d:  no reply\n", ttl);
+	}
+	printf("     Too many hops: pmtu %d\n", mtu);
+done:
+	printf("     Resume: pmtu %d ", mtu);
+	if (hops_to>=0)
+		printf("hops %d ", hops_to);
+	if (hops_from>=0)
+		printf("back %d ", hops_from);
+	printf("\n");
+	exit(0);
+}
diff --git a/iputils/tracepath6.c b/iputils/tracepath6.c
new file mode 100644
index 0000000..67a5a98
--- /dev/null
+++ b/iputils/tracepath6.c
@@ -0,0 +1,588 @@
+/*
+ * tracepath6.c
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+
+#include <linux/types.h>
+#include <linux/errqueue.h>
+#include <errno.h>
+#include <string.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <arpa/inet.h>
+
+#ifdef USE_IDN
+#include <idna.h>
+#include <locale.h>
+#endif
+
+#ifndef SOL_IPV6
+#define SOL_IPV6 IPPROTO_IPV6
+#endif
+
+#ifndef IP_PMTUDISC_DO
+#define IP_PMTUDISC_DO		3
+#endif
+#ifndef IPV6_PMTUDISC_DO
+#define IPV6_PMTUDISC_DO	3
+#endif
+
+#define MAX_HOPS_LIMIT		255
+#define MAX_HOPS_DEFAULT	30
+
+struct hhistory
+{
+	int	hops;
+	struct timeval sendtime;
+};
+
+struct hhistory his[64];
+int hisptr;
+
+sa_family_t family = AF_INET6;
+struct sockaddr_storage target;
+socklen_t targetlen;
+__u16 base_port;
+int max_hops = MAX_HOPS_DEFAULT;
+
+int overhead;
+int mtu;
+void *pktbuf;
+int hops_to = -1;
+int hops_from = -1;
+int no_resolve = 0;
+int show_both = 0;
+int mapped;
+
+#define HOST_COLUMN_SIZE	52
+
+struct probehdr
+{
+	__u32 ttl;
+	struct timeval tv;
+};
+
+void data_wait(int fd)
+{
+	fd_set fds;
+	struct timeval tv;
+	FD_ZERO(&fds);
+	FD_SET(fd, &fds);
+	tv.tv_sec = 1;
+	tv.tv_usec = 0;
+	select(fd+1, &fds, NULL, NULL, &tv);
+}
+
+void print_host(const char *a, const char *b, int both)
+{
+	int plen;
+	plen = printf("%s", a);
+	if (both)
+		plen += printf(" (%s)", b);
+	if (plen >= HOST_COLUMN_SIZE)
+		plen = HOST_COLUMN_SIZE - 1;
+	printf("%*s", HOST_COLUMN_SIZE - plen, "");
+}
+
+int recverr(int fd, int ttl)
+{
+	int res;
+	struct probehdr rcvbuf;
+	char cbuf[512];
+	struct iovec  iov;
+	struct msghdr msg;
+	struct cmsghdr *cmsg;
+	struct sock_extended_err *e;
+	struct sockaddr_storage addr;
+	struct timeval tv;
+	struct timeval *rettv;
+	int slot = 0;
+	int rethops;
+	int sndhops;
+	int progress = -1;
+	int broken_router;
+
+restart:
+	memset(&rcvbuf, -1, sizeof(rcvbuf));
+	iov.iov_base = &rcvbuf;
+	iov.iov_len = sizeof(rcvbuf);
+	msg.msg_name = (caddr_t)&addr;
+	msg.msg_namelen = sizeof(addr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_flags = 0;
+	msg.msg_control = cbuf;
+	msg.msg_controllen = sizeof(cbuf);
+
+	gettimeofday(&tv, NULL);
+	res = recvmsg(fd, &msg, MSG_ERRQUEUE);
+	if (res < 0) {
+		if (errno == EAGAIN)
+			return progress;
+		goto restart;
+	}
+
+	progress = mtu;
+
+	rethops = -1;
+	sndhops = -1;
+	e = NULL;
+	rettv = NULL;
+
+	slot = -base_port;
+	switch (family) {
+	case AF_INET6:
+		slot += ntohs(((struct sockaddr_in6 *)&addr)->sin6_port);
+		break;
+	case AF_INET:
+		slot += ntohs(((struct sockaddr_in *)&addr)->sin_port);
+		break;
+	}
+
+	if (slot >= 0 && slot < 63 && his[slot].hops) {
+		sndhops = his[slot].hops;
+		rettv = &his[slot].sendtime;
+		his[slot].hops = 0;
+	}
+	broken_router = 0;
+	if (res == sizeof(rcvbuf)) {
+		if (rcvbuf.ttl == 0 || rcvbuf.tv.tv_sec == 0)
+			broken_router = 1;
+		else {
+			sndhops = rcvbuf.ttl;
+			rettv = &rcvbuf.tv;
+		}
+	}
+
+	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+		switch (cmsg->cmsg_level) {
+		case SOL_IPV6:
+			switch(cmsg->cmsg_type) {
+			case IPV6_RECVERR:
+				e = (struct sock_extended_err *)CMSG_DATA(cmsg);
+				break;
+			case IPV6_HOPLIMIT:
+#ifdef IPV6_2292HOPLIMIT
+			case IPV6_2292HOPLIMIT:
+#endif
+				memcpy(&rethops, CMSG_DATA(cmsg), sizeof(rethops));
+				break;
+			default:
+				printf("cmsg6:%d\n ", cmsg->cmsg_type);
+			}
+			break;
+		case SOL_IP:
+			switch(cmsg->cmsg_type) {
+			case IP_RECVERR:
+				e = (struct sock_extended_err *)CMSG_DATA(cmsg);
+				break;
+			case IP_TTL:
+				rethops = *(__u8*)CMSG_DATA(cmsg);
+				break;
+			default:
+				printf("cmsg4:%d\n ", cmsg->cmsg_type);
+			}
+		}
+	}
+	if (e == NULL) {
+		printf("no info\n");
+		return 0;
+	}
+	if (e->ee_origin == SO_EE_ORIGIN_LOCAL)
+		printf("%2d?: %-32s ", ttl, "[LOCALHOST]");
+	else if (e->ee_origin == SO_EE_ORIGIN_ICMP6 ||
+		 e->ee_origin == SO_EE_ORIGIN_ICMP) {
+		char abuf[NI_MAXHOST], hbuf[NI_MAXHOST];
+		struct sockaddr *sa = (struct sockaddr *)(e + 1);
+		socklen_t salen;
+
+		if (sndhops>0)
+			printf("%2d:  ", sndhops);
+		else
+			printf("%2d?: ", ttl);
+
+		switch (sa->sa_family) {
+		case AF_INET6:
+			salen = sizeof(struct sockaddr_in6);
+			break;
+		case AF_INET:
+			salen = sizeof(struct sockaddr_in);
+			break;
+		default:
+			salen = 0;
+		}
+
+		if (no_resolve || show_both) {
+			if (getnameinfo(sa, salen,
+					abuf, sizeof(abuf), NULL, 0,
+					NI_NUMERICHOST))
+				strcpy(abuf, "???");
+		} else
+			abuf[0] = 0;
+
+		if (!no_resolve || show_both) {
+			fflush(stdout);
+			if (getnameinfo(sa, salen,
+					hbuf, sizeof(hbuf), NULL, 0,
+					0
+#ifdef USE_IDN
+					| NI_IDN
+#endif
+				        ))
+				strcpy(hbuf, "???");
+		} else
+			hbuf[0] = 0;
+
+		if (no_resolve)
+			print_host(abuf, hbuf, show_both);
+		else
+			print_host(hbuf, abuf, show_both);
+	}
+
+	if (rettv) {
+		int diff = (tv.tv_sec-rettv->tv_sec)*1000000+(tv.tv_usec-rettv->tv_usec);
+		printf("%3d.%03dms ", diff/1000, diff%1000);
+		if (broken_router)
+			printf("(This broken router returned corrupted payload) ");
+	}
+
+	switch (e->ee_errno) {
+	case ETIMEDOUT:
+		printf("\n");
+		break;
+	case EMSGSIZE:
+		printf("pmtu %d\n", e->ee_info);
+		mtu = e->ee_info;
+		progress = mtu;
+		break;
+	case ECONNREFUSED:
+		printf("reached\n");
+		hops_to = sndhops<0 ? ttl : sndhops;
+		hops_from = rethops;
+		return 0;
+	case EPROTO:
+		printf("!P\n");
+		return 0;
+	case EHOSTUNREACH:
+		if ((e->ee_origin == SO_EE_ORIGIN_ICMP &&
+		     e->ee_type == 11 &&
+		     e->ee_code == 0) ||
+		    (e->ee_origin == SO_EE_ORIGIN_ICMP6 &&
+		     e->ee_type == 3 &&
+		     e->ee_code == 0)) {
+			if (rethops>=0) {
+				if (rethops<=64)
+					rethops = 65-rethops;
+				else if (rethops<=128)
+					rethops = 129-rethops;
+				else
+					rethops = 256-rethops;
+				if (sndhops>=0 && rethops != sndhops)
+					printf("asymm %2d ", rethops);
+				else if (sndhops<0 && rethops != ttl)
+					printf("asymm %2d ", rethops);
+			}
+			printf("\n");
+			break;
+		}
+		printf("!H\n");
+		return 0;
+	case ENETUNREACH:
+		printf("!N\n");
+		return 0;
+	case EACCES:
+		printf("!A\n");
+		return 0;
+	default:
+		printf("\n");
+		errno = e->ee_errno;
+		perror("NET ERROR");
+		return 0;
+	}
+	goto restart;
+}
+
+int probe_ttl(int fd, int ttl)
+{
+	int i;
+	struct probehdr *hdr = pktbuf;
+
+	memset(pktbuf, 0, mtu);
+restart:
+
+	for (i=0; i<10; i++) {
+		int res;
+
+		hdr->ttl = ttl;
+		switch (family) {
+		case AF_INET6:
+			((struct sockaddr_in6 *)&target)->sin6_port = htons(base_port + hisptr);
+			break;
+		case AF_INET:
+			((struct sockaddr_in *)&target)->sin_port = htons(base_port + hisptr);
+			break;
+		}
+		gettimeofday(&hdr->tv, NULL);
+		his[hisptr].hops = ttl;
+		his[hisptr].sendtime = hdr->tv;
+		if (sendto(fd, pktbuf, mtu-overhead, 0, (struct sockaddr *)&target, targetlen) > 0)
+			break;
+		res = recverr(fd, ttl);
+		his[hisptr].hops = 0;
+		if (res==0)
+			return 0;
+		if (res > 0)
+			goto restart;
+	}
+	hisptr = (hisptr + 1) & 63;
+
+	if (i<10) {
+		data_wait(fd);
+		if (recv(fd, pktbuf, mtu, MSG_DONTWAIT) > 0) {
+			printf("%2d?: reply received 8)\n", ttl);
+			return 0;
+		}
+		return recverr(fd, ttl);
+	}
+
+	printf("%2d:  send failed\n", ttl);
+	return 0;
+}
+
+static void usage(void) __attribute((noreturn));
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: tracepath6 [-n] [-b] [-l <len>] [-p port] <destination>\n");
+	exit(-1);
+}
+
+
+int main(int argc, char **argv)
+{
+	int fd;
+	int on;
+	int ttl;
+	char *p;
+	struct addrinfo hints, *ai, *ai0;
+	int ch;
+	int gai;
+	char pbuf[NI_MAXSERV];
+
+#ifdef USE_IDN
+	setlocale(LC_ALL, "");
+#endif
+
+	while ((ch = getopt(argc, argv, "nbh?l:m:p:")) != EOF) {
+		switch(ch) {
+		case 'n':
+			no_resolve = 1;
+			break;
+		case 'b':
+			show_both = 1;
+			break;
+		case 'l':
+			mtu = atoi(optarg);
+			break;
+		case 'm':
+			max_hops = atoi(optarg);
+			if (max_hops < 0 || max_hops > MAX_HOPS_LIMIT) {
+				fprintf(stderr,
+					"Error: max hops must be 0 .. %d (inclusive).\n",
+					MAX_HOPS_LIMIT);
+			}
+			break;
+		case 'p':
+			base_port = atoi(optarg);
+			break;
+		default:
+			usage();
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 1)
+		usage();
+
+	/* Backward compatiblity */
+	if (!base_port) {
+		p = strchr(argv[0], '/');
+		if (p) {
+			*p = 0;
+			base_port = (unsigned)atoi(p+1);
+		} else {
+			base_port = 44444;
+		}
+	}
+	sprintf(pbuf, "%u", base_port);
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = family;
+	hints.ai_socktype = SOCK_DGRAM;
+	hints.ai_protocol = IPPROTO_UDP;
+#ifdef USE_IDN
+	hints.ai_flags = AI_IDN;
+#endif
+	gai = getaddrinfo(argv[0], pbuf, &hints, &ai0);
+	if (gai) {
+		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(gai));
+		exit(1);
+	}
+
+	fd = -1;
+	for (ai = ai0; ai; ai = ai->ai_next) {
+		/* sanity check */
+		if (family && ai->ai_family != family)
+			continue;
+		if (ai->ai_family != AF_INET6 &&
+		    ai->ai_family != AF_INET)
+			continue;
+		family = ai->ai_family;
+		fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+		if (fd < 0)
+			continue;
+		memcpy(&target, ai->ai_addr, sizeof(target));
+		targetlen = ai->ai_addrlen;
+		break;
+	}
+	if (fd < 0) {
+		perror("socket/connect");
+		exit(1);
+	}
+	freeaddrinfo(ai0);
+
+	switch (family) {
+	case AF_INET6:
+		overhead = 48;
+		if (!mtu)
+			mtu = 128000;
+		if (mtu <= overhead)
+			goto pktlen_error;
+
+		on = IPV6_PMTUDISC_DO;
+		if (setsockopt(fd, SOL_IPV6, IPV6_MTU_DISCOVER, &on, sizeof(on)) &&
+		    (on = IPV6_PMTUDISC_DO,
+		     setsockopt(fd, SOL_IPV6, IPV6_MTU_DISCOVER, &on, sizeof(on)))) {
+			perror("IPV6_MTU_DISCOVER");
+			exit(1);
+		}
+		on = 1;
+		if (setsockopt(fd, SOL_IPV6, IPV6_RECVERR, &on, sizeof(on))) {
+			perror("IPV6_RECVERR");
+			exit(1);
+		}
+		if (
+#ifdef IPV6_RECVHOPLIMIT
+		    setsockopt(fd, SOL_IPV6, IPV6_HOPLIMIT, &on, sizeof(on)) &&
+		    setsockopt(fd, SOL_IPV6, IPV6_2292HOPLIMIT, &on, sizeof(on))
+#else
+		    setsockopt(fd, SOL_IPV6, IPV6_HOPLIMIT, &on, sizeof(on))
+#endif
+		    ) {
+			perror("IPV6_HOPLIMIT");
+			exit(1);
+		}
+		if (!IN6_IS_ADDR_V4MAPPED(&(((struct sockaddr_in6 *)&target)->sin6_addr)))
+			break;
+		mapped = 1;
+		/*FALLTHROUGH*/
+	case AF_INET:
+		overhead = 28;
+		if (!mtu)
+			mtu = 65535;
+		if (mtu <= overhead)
+			goto pktlen_error;
+
+		on = IP_PMTUDISC_DO;
+		if (setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &on, sizeof(on))) {
+			perror("IP_MTU_DISCOVER");
+			exit(1);
+		}
+		on = 1;
+		if (setsockopt(fd, SOL_IP, IP_RECVERR, &on, sizeof(on))) {
+			perror("IP_RECVERR");
+			exit(1);
+		}
+		if (setsockopt(fd, SOL_IP, IP_RECVTTL, &on, sizeof(on))) {
+			perror("IP_RECVTTL");
+			exit(1);
+		}
+	}
+
+	pktbuf = malloc(mtu);
+	if (!pktbuf) {
+		perror("malloc");
+		exit(1);
+	}
+
+	for (ttl = 1; ttl <= max_hops; ttl++) {
+		int res;
+		int i;
+
+		on = ttl;
+		switch (family) {
+		case AF_INET6:
+			if (setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &on, sizeof(on))) {
+				perror("IPV6_UNICAST_HOPS");
+				exit(1);
+			}
+			if (!mapped)
+				break;
+			/*FALLTHROUGH*/
+		case AF_INET:
+			if (setsockopt(fd, SOL_IP, IP_TTL, &on, sizeof(on))) {
+				perror("IP_TTL");
+				exit(1);
+			}
+		}
+
+restart:
+		for (i=0; i<3; i++) {
+			int old_mtu;
+
+			old_mtu = mtu;
+			res = probe_ttl(fd, ttl);
+			if (mtu != old_mtu)
+				goto restart;
+			if (res == 0)
+				goto done;
+			if (res > 0)
+				break;
+		}
+
+		if (res < 0)
+			printf("%2d:  no reply\n", ttl);
+	}
+	printf("     Too many hops: pmtu %d\n", mtu);
+
+done:
+	printf("     Resume: pmtu %d ", mtu);
+	if (hops_to>=0)
+		printf("hops %d ", hops_to);
+	if (hops_from>=0)
+		printf("back %d ", hops_from);
+	printf("\n");
+	exit(0);
+
+pktlen_error:
+	fprintf(stderr, "Error: pktlen must be > %d and <= %d\n",
+		overhead, INT_MAX);
+	exit(1);
+}
diff --git a/iputils/traceroute6.c b/iputils/traceroute6.c
new file mode 100644
index 0000000..0538d4b
--- /dev/null
+++ b/iputils/traceroute6.c
@@ -0,0 +1,950 @@
+/*
+ *      Modified for NRL 4.4BSD IPv6 release.
+ *      07/31/96 bgp
+ *
+ *      Search for "#ifdef NRL" to find the changes.
+ */
+
+/*
+ *	Modified for Linux IPv6 by Pedro Roque <roque@di.fc.ul.pt>
+ *	31/07/1996
+ *
+ *	As ICMP error messages for IPv6 now include more than 8 bytes
+ *	UDP datagrams are now sent via an UDP socket instead of magic
+ *	RAW socket tricks.
+ *
+ *	Original copyright and comments left intact. They might not
+ *	match the code anymore.
+ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1990, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * traceroute host  - trace the route ip packets follow going to "host".
+ *
+ * Attempt to trace the route an ip packet would follow to some
+ * internet host.  We find out intermediate hops by launching probe
+ * packets with a small ttl (time to live) then listening for an
+ * icmp "time exceeded" reply from a gateway.  We start our probes
+ * with a ttl of one and increase by one until we get an icmp "port
+ * unreachable" (which means we got to "host") or hit a max (which
+ * defaults to 30 hops & can be changed with the -m flag).  Three
+ * probes (change with -q flag) are sent at each ttl setting and a
+ * line is printed showing the ttl, address of the gateway and
+ * round trip time of each probe.  If the probe answers come from
+ * different gateways, the address of each responding system will
+ * be printed.  If there is no response within a 5 sec. timeout
+ * interval (changed with the -w flag), a "*" is printed for that
+ * probe.
+ *
+ * Probe packets are UDP format.  We don't want the destination
+ * host to process them so the destination port is set to an
+ * unlikely value (if some clod on the destination is using that
+ * value, it can be changed with the -p flag).
+ *
+ * A sample use might be:
+ *
+ *     [yak 71]% traceroute nis.nsf.net.
+ *     traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
+ *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
+ *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
+ *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
+ *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
+ *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
+ *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
+ *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
+ *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
+ *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
+ *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
+ *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
+ *
+ * Note that lines 2 & 3 are the same.  This is due to a buggy
+ * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
+ * packets with a zero ttl.
+ *
+ * A more interesting example is:
+ *
+ *     [yak 72]% traceroute allspice.lcs.mit.edu.
+ *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
+ *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
+ *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
+ *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
+ *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
+ *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
+ *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
+ *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
+ *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
+ *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
+ *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
+ *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
+ *     12  * * *
+ *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
+ *     14  * * *
+ *     15  * * *
+ *     16  * * *
+ *     17  * * *
+ *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
+ *
+ * (I start to see why I'm having so much trouble with mail to
+ * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
+ * either don't send ICMP "time exceeded" messages or send them
+ * with a ttl too small to reach us.  14 - 17 are running the
+ * MIT C Gateway code that doesn't send "time exceeded"s.  God
+ * only knows what's going on with 12.
+ *
+ * The silent gateway 12 in the above may be the result of a bug in
+ * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
+ * sends an unreachable message using whatever ttl remains in the
+ * original datagram.  Since, for gateways, the remaining ttl is
+ * zero, the icmp "time exceeded" is guaranteed to not make it back
+ * to us.  The behavior of this bug is slightly more interesting
+ * when it appears on the destination system:
+ *
+ *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
+ *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
+ *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
+ *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
+ *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
+ *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
+ *      7  * * *
+ *      8  * * *
+ *      9  * * *
+ *     10  * * *
+ *     11  * * *
+ *     12  * * *
+ *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
+ *
+ * Notice that there are 12 "gateways" (13 is the final
+ * destination) and exactly the last half of them are "missing".
+ * What's really happening is that rip (a Sun-3 running Sun OS3.5)
+ * is using the ttl from our arriving datagram as the ttl in its
+ * icmp reply.  So, the reply will time out on the return path
+ * (with no notice sent to anyone since icmp's aren't sent for
+ * icmp's) until we probe with a ttl that's at least twice the path
+ * length.  I.e., rip is really only 7 hops away.  A reply that
+ * returns with a ttl of 1 is a clue this problem exists.
+ * Traceroute prints a "!" after the time if the ttl is <= 1.
+ * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
+ * non-standard (HPUX) software, expect to see this problem
+ * frequently and/or take care picking the target host of your
+ * probes.
+ *
+ * Other possible annotations after the time are !H, !N, !P (got a host,
+ * network or protocol unreachable, respectively), !S or !F (source
+ * route failed or fragmentation needed -- neither of these should
+ * ever occur and the associated gateway is busted if you see one).  If
+ * almost all the probes result in some kind of unreachable, traceroute
+ * will give up and exit.
+ *
+ * Notes
+ * -----
+ * This program must be run by root or be setuid.  (I suggest that
+ * you *don't* make it setuid -- casual use could result in a lot
+ * of unnecessary traffic on our poor, congested nets.)
+ *
+ * This program requires a kernel mod that does not appear in any
+ * system available from Berkeley:  A raw ip socket using proto
+ * IPPROTO_RAW must interpret the data sent as an ip datagram (as
+ * opposed to data to be wrapped in a ip datagram).  See the README
+ * file that came with the source to this program for a description
+ * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
+ * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
+ * MODIFIED TO RUN THIS PROGRAM.
+ *
+ * The udp port usage may appear bizarre (well, ok, it is bizarre).
+ * The problem is that an icmp message only contains 8 bytes of
+ * data from the original datagram.  8 bytes is the size of a udp
+ * header so, if we want to associate replies with the original
+ * datagram, the necessary information must be encoded into the
+ * udp header (the ip id could be used but there's no way to
+ * interlock with the kernel's assignment of ip id's and, anyway,
+ * it would have taken a lot more kernel hacking to allow this
+ * code to set the ip id).  So, to allow two or more users to
+ * use traceroute simultaneously, we use this task's pid as the
+ * source port (the high bit is set to move the port number out
+ * of the "likely" range).  To keep track of which probe is being
+ * replied to (so times and/or hop counts don't get confused by a
+ * reply that was delayed in transit), we increment the destination
+ * port number before each probe.
+ *
+ * Don't use this as a coding example.  I was trying to find a
+ * routing problem and this code sort-of popped out after 48 hours
+ * without sleep.  I was amazed it ever compiled, much less ran.
+ *
+ * I stole the idea for this program from Steve Deering.  Since
+ * the first release, I've learned that had I attended the right
+ * IETF working group meetings, I also could have stolen it from Guy
+ * Almes or Matt Mathis.  I don't know (or care) who came up with
+ * the idea first.  I envy the originators' perspicacity and I'm
+ * glad they didn't keep the idea a secret.
+ *
+ * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
+ * enhancements to the original distribution.
+ *
+ * I've hacked up a round-trip-route version of this that works by
+ * sending a loose-source-routed udp datagram through the destination
+ * back to yourself.  Unfortunately, SO many gateways botch source
+ * routing, the thing is almost worthless.  Maybe one day...
+ *
+ *  -- Van Jacobson (van@helios.ee.lbl.gov)
+ *     Tue Dec 20 03:50:13 PST 1988
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+#if __linux__
+#include <endian.h>
+#endif
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/udp.h>
+
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <linux/types.h>
+#ifdef CAPABILITIES
+#include <sys/capability.h>
+#endif
+
+#ifdef USE_IDN
+#include <idna.h>
+#include <locale.h>
+#endif
+
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "SNAPSHOT.h"
+
+#ifndef SOL_IPV6
+#define SOL_IPV6 IPPROTO_IPV6
+#endif
+
+#define	MAXPACKET	65535
+#define MAX_HOSTNAMELEN	NI_MAXHOST
+
+#ifndef FD_SET
+#define NFDBITS         (8*sizeof(fd_set))
+#define FD_SETSIZE      NFDBITS
+#define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_ZERO(p)      memset((char *)(p), 0, sizeof(*(p)))
+#endif
+
+#define Fprintf (void)fprintf
+#define Printf (void)printf
+
+u_char	packet[512];		/* last inbound (icmp) packet */
+
+int	wait_for_reply(int, struct sockaddr_in6 *, struct in6_addr *, int);
+int	packet_ok(u_char *buf, int cc, struct sockaddr_in6 *from,
+		  struct in6_addr *to, int seq, struct timeval *);
+void	send_probe(int seq, int ttl);
+double	deltaT (struct timeval *, struct timeval *);
+void	print(unsigned char *buf, int cc, struct sockaddr_in6 *from);
+void	tvsub (struct timeval *, struct timeval *);
+void	usage(void);
+
+int icmp_sock;			/* receive (icmp) socket file descriptor */
+int sndsock;			/* send (udp) socket file descriptor */
+struct timezone tz;		/* leftover */
+
+struct sockaddr_in6 whereto;	/* Who to try to reach */
+
+struct sockaddr_in6 saddr;
+struct sockaddr_in6 firsthop;
+char *source = NULL;
+char *device = NULL;
+char *hostname;
+
+int nprobes = 3;
+int max_ttl = 30;
+pid_t ident;
+u_short port = 32768+666;	/* start udp dest port # for probe packets */
+int options;			/* socket options */
+int verbose;
+int waittime = 5;		/* time to wait for response (in seconds) */
+int nflag;			/* print addresses numerically */
+
+
+struct pkt_format
+{
+	__u32 ident;
+	__u32 seq;
+	struct timeval tv;
+};
+
+char *sendbuff;
+int datalen = sizeof(struct pkt_format);
+
+
+
+int main(int argc, char *argv[])
+{
+	char pa[MAX_HOSTNAMELEN];
+	extern char *optarg;
+	extern int optind;
+	struct hostent *hp;
+	struct sockaddr_in6 from, *to;
+	int ch, i, on, probe, seq, tos, ttl;
+	int socket_errno;
+
+	icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+	socket_errno = errno;
+
+	if (setuid(getuid())) {
+		perror("traceroute6: setuid");
+		exit(-1);
+	}
+#ifdef CAPABILITIES
+	{
+		cap_t caps = cap_init();
+		if (cap_set_proc(caps)) {
+			perror("traceroute6: cap_set_proc");
+			exit(-1);
+		}
+		cap_free(caps);
+	}
+#endif
+
+#ifdef USE_IDN
+	setlocale(LC_ALL, "");
+#endif
+
+	on = 1;
+	seq = tos = 0;
+	to = (struct sockaddr_in6 *)&whereto;
+	while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:vi:g:V")) != EOF) {
+		switch(ch) {
+		case 'd':
+			options |= SO_DEBUG;
+			break;
+		case 'm':
+			max_ttl = atoi(optarg);
+			if (max_ttl <= 1) {
+				Fprintf(stderr,
+				    "traceroute: max ttl must be >1.\n");
+				exit(1);
+			}
+			break;
+		case 'n':
+			nflag++;
+			break;
+		case 'p':
+			port = atoi(optarg);
+			if (port < 1) {
+				Fprintf(stderr,
+				    "traceroute: port must be >0.\n");
+				exit(1);
+			}
+			break;
+		case 'q':
+			nprobes = atoi(optarg);
+			if (nprobes < 1) {
+				Fprintf(stderr,
+				    "traceroute: nprobes must be >0.\n");
+				exit(1);
+			}
+			break;
+		case 'r':
+			options |= SO_DONTROUTE;
+			break;
+		case 's':
+			/*
+			 * set the ip source address of the outbound
+			 * probe (e.g., on a multi-homed host).
+			 */
+			source = optarg;
+			break;
+		case 'i':
+			device = optarg;
+			break;
+		case 'g':
+			Fprintf(stderr, "Sorry, rthdr is not yet supported\n");
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case 'w':
+			waittime = atoi(optarg);
+			if (waittime <= 1) {
+				Fprintf(stderr,
+				    "traceroute: wait must be >1 sec.\n");
+				exit(1);
+			}
+			break;
+		case 'V':
+			printf("traceroute6 utility, iputils-%s\n", SNAPSHOT);
+			exit(0);
+		default:
+			usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 1)
+		usage();
+
+	setlinebuf (stdout);
+
+	(void) memset((char *)&whereto, 0, sizeof(whereto));
+
+	to->sin6_family = AF_INET6;
+	to->sin6_port = htons(port);
+
+	if (inet_pton(AF_INET6, *argv, &to->sin6_addr) > 0) {
+		hostname = *argv;
+	} else {
+		char *idn = NULL;
+#ifdef USE_IDN
+		if (idna_to_ascii_lz(*argv, &idn, 0) != IDNA_SUCCESS)
+			idn = NULL;
+#endif
+		hp = gethostbyname2(idn ? idn : *argv, AF_INET6);
+		if (hp) {
+			memmove((caddr_t)&to->sin6_addr, hp->h_addr, sizeof(to->sin6_addr));
+			hostname = (char *)hp->h_name;
+		} else {
+			(void)fprintf(stderr,
+			    "traceroute: unknown host %s\n", *argv);
+			exit(1);
+		}
+	}
+	firsthop = *to;
+	if (*++argv) {
+		datalen = atoi(*argv);
+		/* Message for rpm maintainers: have _shame_. If you want
+		 * to fix something send the patch to me for sanity checking.
+		 * "datalen" patch is a shit. */
+		if (datalen == 0)
+			datalen = sizeof(struct pkt_format);
+		else if (datalen < (int)sizeof(struct pkt_format) ||
+			 datalen >= MAXPACKET) {
+			Fprintf(stderr,
+			    "traceroute: packet size must be %d <= s < %d.\n",
+				(int)sizeof(struct pkt_format), MAXPACKET);
+			exit(1);
+		}
+	}
+
+	ident = getpid();
+
+	sendbuff = malloc(datalen);
+	if (sendbuff == NULL) {
+		fprintf(stderr, "malloc failed\n");
+		exit(1);
+	}
+
+	if (icmp_sock < 0) {
+		errno = socket_errno;
+		perror("traceroute6: icmp socket");
+		exit(1);
+	}
+
+#ifdef IPV6_RECVPKTINFO
+	setsockopt(icmp_sock, SOL_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
+	setsockopt(icmp_sock, SOL_IPV6, IPV6_2292PKTINFO, &on, sizeof(on));
+#else
+	setsockopt(icmp_sock, SOL_IPV6, IPV6_PKTINFO, &on, sizeof(on));
+#endif
+
+	if (options & SO_DEBUG)
+		setsockopt(icmp_sock, SOL_SOCKET, SO_DEBUG,
+			   (char *)&on, sizeof(on));
+	if (options & SO_DONTROUTE)
+		setsockopt(icmp_sock, SOL_SOCKET, SO_DONTROUTE,
+			   (char *)&on, sizeof(on));
+
+#ifdef __linux__
+	on = 2;
+	if (setsockopt(icmp_sock, SOL_RAW, IPV6_CHECKSUM, &on, sizeof(on)) < 0) {
+		/* checksum should be enabled by default and setting this
+		 * option might fail anyway.
+		 */
+		fprintf(stderr, "setsockopt(RAW_CHECKSUM) failed - try to continue.");
+	}
+#endif
+
+	if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+		perror("traceroute: UDP socket");
+		exit(5);
+	}
+#ifdef SO_SNDBUF
+	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
+		       sizeof(datalen)) < 0) {
+		perror("traceroute: SO_SNDBUF");
+		exit(6);
+	}
+#endif /* SO_SNDBUF */
+
+	if (options & SO_DEBUG)
+		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
+				  (char *)&on, sizeof(on));
+	if (options & SO_DONTROUTE)
+		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
+				  (char *)&on, sizeof(on));
+
+	if (source == NULL) {
+		socklen_t alen;
+		int probe_fd = socket(AF_INET6, SOCK_DGRAM, 0);
+
+		if (probe_fd < 0) {
+			perror("socket");
+			exit(1);
+		}
+		if (device) {
+			if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1)
+				perror("WARNING: interface is ignored");
+		}
+		firsthop.sin6_port = htons(1025);
+		if (connect(probe_fd, (struct sockaddr*)&firsthop, sizeof(firsthop)) == -1) {
+			perror("connect");
+			exit(1);
+		}
+		alen = sizeof(saddr);
+		if (getsockname(probe_fd, (struct sockaddr*)&saddr, &alen) == -1) {
+			perror("getsockname");
+			exit(1);
+		}
+		saddr.sin6_port = 0;
+		close(probe_fd);
+	} else {
+		(void) memset((char *)&saddr, 0, sizeof(saddr));
+		saddr.sin6_family = AF_INET6;
+		if (inet_pton(AF_INET6, source, &saddr.sin6_addr) <= 0)
+		{
+			Printf("traceroute: unknown addr %s\n", source);
+			exit(1);
+		}
+	}
+
+	if (bind(sndsock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
+		perror ("traceroute: bind sending socket");
+		exit (1);
+	}
+	if (bind(icmp_sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
+		perror ("traceroute: bind icmp6 socket");
+		exit (1);
+	}
+
+	Fprintf(stderr, "traceroute to %s (%s)", hostname,
+		inet_ntop(AF_INET6, &to->sin6_addr, pa, sizeof(pa)));
+
+	Fprintf(stderr, " from %s",
+		inet_ntop(AF_INET6, &saddr.sin6_addr, pa, sizeof(pa)));
+	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
+	(void) fflush(stderr);
+
+	for (ttl = 1; ttl <= max_ttl; ++ttl) {
+		struct in6_addr lastaddr = {{{0,}}};
+		int got_there = 0;
+		int unreachable = 0;
+
+		Printf("%2d ", ttl);
+		for (probe = 0; probe < nprobes; ++probe) {
+			int cc, reset_timer;
+			struct timeval t1, t2;
+			struct timezone tz;
+			struct in6_addr to;
+
+			gettimeofday(&t1, &tz);
+			send_probe(++seq, ttl);
+			reset_timer = 1;
+
+			while ((cc = wait_for_reply(icmp_sock, &from, &to, reset_timer)) != 0) {
+				gettimeofday(&t2, &tz);
+				if ((i = packet_ok(packet, cc, &from, &to, seq, &t1))) {
+					reset_timer = 1;
+					if (memcmp(&from.sin6_addr, &lastaddr, sizeof(from.sin6_addr))) {
+						print(packet, cc, &from);
+						memcpy(&lastaddr,
+						       &from.sin6_addr,
+						       sizeof(lastaddr));
+					}
+					Printf("  %g ms", deltaT(&t1, &t2));
+					switch(i - 1) {
+					case ICMP6_DST_UNREACH_NOPORT:
+						++got_there;
+						break;
+
+					case ICMP6_DST_UNREACH_NOROUTE:
+						++unreachable;
+						Printf(" !N");
+						break;
+					case ICMP6_DST_UNREACH_ADDR:
+						++unreachable;
+						Printf(" !H");
+						break;
+
+					case ICMP6_DST_UNREACH_ADMIN:
+						++unreachable;
+						Printf(" !S");
+						break;
+					}
+					break;
+				} else
+					reset_timer = 0;
+			}
+			if (cc <= 0)
+				Printf(" *");
+			(void) fflush(stdout);
+		}
+		putchar('\n');
+		if (got_there ||
+		    (unreachable > 0 && unreachable >= nprobes-1))
+			exit(0);
+	}
+
+	return 0;
+}
+
+int
+wait_for_reply(sock, from, to, reset_timer)
+	int sock;
+	struct sockaddr_in6 *from;
+	struct in6_addr *to;
+	int reset_timer;
+{
+	fd_set fds;
+	static struct timeval wait;
+	int cc = 0;
+	char cbuf[512];
+
+	FD_ZERO(&fds);
+	FD_SET(sock, &fds);
+	if (reset_timer) {
+		/*
+		 * traceroute could hang if someone else has a ping
+		 * running and our ICMP reply gets dropped but we don't
+		 * realize it because we keep waking up to handle those
+		 * other ICMP packets that keep coming in.  To fix this,
+		 * "reset_timer" will only be true if the last packet that
+		 * came in was for us or if this is the first time we're
+		 * waiting for a reply since sending out a probe.  Note
+		 * that this takes advantage of the select() feature on
+		 * Linux where the remaining timeout is written to the
+		 * struct timeval area.
+		 */
+		wait.tv_sec = waittime;
+		wait.tv_usec = 0;
+	}
+
+	if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0) {
+		struct iovec iov;
+		struct msghdr msg;
+		iov.iov_base = packet;
+		iov.iov_len = sizeof(packet);
+		msg.msg_name = (void *)from;
+		msg.msg_namelen = sizeof(*from);
+		msg.msg_iov = &iov;
+		msg.msg_iovlen = 1;
+		msg.msg_flags = 0;
+		msg.msg_control = cbuf;
+		msg.msg_controllen = sizeof(cbuf);
+
+		cc = recvmsg(icmp_sock, &msg, 0);
+		if (cc >= 0) {
+			struct cmsghdr *cmsg;
+			struct in6_pktinfo *ipi;
+
+			for (cmsg = CMSG_FIRSTHDR(&msg);
+			     cmsg;
+			     cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+				if (cmsg->cmsg_level != SOL_IPV6)
+					continue;
+				switch (cmsg->cmsg_type) {
+				case IPV6_PKTINFO:
+#ifdef IPV6_2292PKTINFO
+				case IPV6_2292PKTINFO:
+#endif
+					ipi = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+					memcpy(to, ipi, sizeof(*to));
+				}
+			}
+		}
+	}
+
+	return(cc);
+}
+
+
+void send_probe(int seq, int ttl)
+{
+	struct pkt_format *pkt = (struct pkt_format *) sendbuff;
+	int i;
+
+	pkt->ident = htonl(ident);
+	pkt->seq = htonl(seq);
+	gettimeofday(&pkt->tv, &tz);
+
+	i = setsockopt(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
+	if (i < 0)
+	{
+		perror("setsockopt");
+		exit(1);
+	}
+
+	do {
+		i = sendto(sndsock, sendbuff, datalen, 0,
+			   (struct sockaddr *)&whereto, sizeof(whereto));
+	} while (i<0 && errno == ECONNREFUSED);
+
+	if (i < 0 || i != datalen)  {
+		if (i<0)
+			perror("sendto");
+		Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
+			datalen, i);
+		(void) fflush(stdout);
+	}
+}
+
+
+double deltaT(struct timeval *t1p, struct timeval *t2p)
+{
+	register double dt;
+
+	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
+	     (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
+	return (dt);
+}
+
+
+/*
+ * Convert an ICMP "type" field to a printable string.
+ */
+char * pr_type(unsigned char t)
+{
+	switch(t) {
+	/* Unknown */
+	case 0:
+		return "Error";
+	case 1:
+		/* ICMP6_DST_UNREACH: */
+		return "Destination Unreachable";
+	case 2:
+		/* ICMP6_PACKET_TOO_BIG: */
+		return "Packet Too Big";
+	case 3:
+		/* ICMP6_TIME_EXCEEDED */
+		return "Time Exceeded in Transit";
+	case 4:
+		/* ICMP6_PARAM_PROB */
+		return "Parameter Problem";
+	case 128:
+		/* ICMP6_ECHO_REQUEST */
+		return "Echo Request";
+	case 129:
+		/* ICMP6_ECHO_REPLY */
+		return "Echo Reply";
+	case 130:
+		/* ICMP6_MEMBERSHIP_QUERY */
+		return "Membership Query";
+	case 131:
+		/* ICMP6_MEMBERSHIP_REPORT */
+		return "Membership Report";
+	case 132:
+		/* ICMP6_MEMBERSHIP_REDUCTION */
+		return "Membership Reduction";
+	case 133:
+		/* ND_ROUTER_SOLICIT */
+		return "Router Solicitation";
+	case 134:
+		/* ND_ROUTER_ADVERT */
+		return "Router Advertisement";
+	case 135:
+		/* ND_NEIGHBOR_SOLICIT */
+		return "Neighbor Solicitation";
+	case 136:
+		/* ND_NEIGHBOR_ADVERT */
+		return "Neighbor Advertisement";
+	case 137:
+		/* ND_REDIRECT */
+		return "Redirect";
+	}
+
+	return("OUT-OF-RANGE");
+}
+
+
+int packet_ok(u_char *buf, int cc, struct sockaddr_in6 *from,
+	      struct in6_addr *to, int seq,
+	      struct timeval *tv)
+{
+	struct icmp6_hdr *icp;
+	u_char type, code;
+
+	icp = (struct icmp6_hdr *) buf;
+
+	type = icp->icmp6_type;
+	code = icp->icmp6_code;
+
+	if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) ||
+	    type == ICMP6_DST_UNREACH)
+	{
+		struct ip6_hdr *hip;
+		struct udphdr *up;
+		int nexthdr;
+
+		hip = (struct ip6_hdr *) (icp + 1);
+		up = (struct udphdr *)(hip+1);
+		nexthdr = hip->ip6_nxt;
+
+		if (nexthdr == 44) {
+			nexthdr = *(unsigned char*)up;
+			up++;
+		}
+		if (nexthdr == IPPROTO_UDP)
+		{
+			struct pkt_format *pkt;
+
+			pkt = (struct pkt_format *) (up + 1);
+
+			if (ntohl(pkt->ident) == ident &&
+			    ntohl(pkt->seq) == seq)
+			{
+				*tv = pkt->tv;
+				return (type == ICMP6_TIME_EXCEEDED ? -1 : code+1);
+			}
+		}
+
+	}
+
+	if (verbose) {
+		unsigned char *p;
+		char pa1[MAX_HOSTNAMELEN];
+		char pa2[MAX_HOSTNAMELEN];
+		int i;
+
+		p = (unsigned char *) (icp + 1);
+
+		Printf("\n%d bytes from %s to %s", cc,
+		       inet_ntop(AF_INET6, &from->sin6_addr, pa1, sizeof(pa1)),
+		       inet_ntop(AF_INET6, to, pa2, sizeof(pa2)));
+
+		Printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
+		       icp->icmp6_code);
+
+		cc -= sizeof(struct icmp6_hdr);
+		for (i = 0; i < cc ; i++) {
+			if (i % 16 == 0)
+				Printf("%04x:", i);
+			if (i % 4 == 0)
+				Printf(" ");
+			Printf("%02x", 0xff & (unsigned)p[i]);
+			if (i % 16 == 15 && i + 1 < cc)
+				Printf("\n");
+		}
+		Printf("\n");
+	}
+
+	return(0);
+}
+
+
+void print(unsigned char *buf, int cc, struct sockaddr_in6 *from)
+{
+	char pa[MAX_HOSTNAMELEN];
+
+	if (nflag)
+		Printf(" %s", inet_ntop(AF_INET6, &from->sin6_addr,
+					pa, sizeof(pa)));
+	else
+	{
+		const char *hostname;
+		struct hostent *hp;
+		char *s = NULL;
+
+		hostname = inet_ntop(AF_INET6, &from->sin6_addr, pa, sizeof(pa));
+
+		if ((hp = gethostbyaddr((char *)&from->sin6_addr,
+					sizeof(from->sin6_addr), AF_INET6))) {
+#ifdef USE_IDN
+			if (idna_to_unicode_lzlz(hp->h_name, &s, 0) != IDNA_SUCCESS)
+				s = NULL;
+#endif
+		}
+
+		Printf(" %s (%s)", hp ? (s ? s : hp->h_name) : hostname, pa);
+
+		free(s);
+	}
+}
+
+
+/*
+ * Subtract 2 timeval structs:  out = out - in.
+ * Out is assumed to be >= in.
+ */
+void
+tvsub(out, in)
+	register struct timeval *out, *in;
+{
+	if ((out->tv_usec -= in->tv_usec) < 0)   {
+		out->tv_sec--;
+		out->tv_usec += 1000000;
+	}
+	out->tv_sec -= in->tv_sec;
+}
+
+void usage(void)
+{
+	fprintf(stderr,
+"Usage: traceroute6 [-dnrvV] [-m max_ttl] [-p port#] [-q nqueries]\n\t\
+[-s src_addr] [-t tos] [-w wait] host [data size]\n");
+	exit(1);
+}