]> git.proxmox.com Git - mirror_qemu.git/commitdiff
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream-qgraph' into staging
authorPeter Maydell <peter.maydell@linaro.org>
Fri, 8 Mar 2019 14:05:17 +0000 (14:05 +0000)
committerPeter Maydell <peter.maydell@linaro.org>
Fri, 8 Mar 2019 14:05:17 +0000 (14:05 +0000)
qgraph project from GSoC 2018

# gpg: Signature made Thu 07 Mar 2019 16:29:17 GMT
# gpg:                using RSA key BFFBD25F78C7AE83
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full]
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>" [full]
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* remotes/bonzini/tags/for-upstream-qgraph: (57 commits)
  qos-test: megasas test node
  qos-test: e1000 test node
  qos-test: eepro100 test node
  qos-test: es1370 test node
  qos-test: vmxnet3 test node
  qos-test: usb-hcd-ohci test node
  qos-test: spapr-phb test node
  qos-test: pcnet test node
  qos-test: nvme test node
  qos-test: ne2k_pci test node
  qos-test: ipoctal232 test node
  qos-test: tpci200 test node
  qos-test: ac97 test node
  tests: move virtio entirely to qos-test
  tests/libqos: remove pre-qgraph QVirtioPCIDevice API
  qos-test: virtio-scsi test node
  tests/libqos: virtio-scsi driver and interface nodes
  qos-test: vhost-user test node
  vhost-user-test: always use 256 MiB of guest memory
  tests/libqos: support multiqueue for virtio-net
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
276 files changed:
.gitignore
.travis.yml
Kconfig.host [new file with mode: 0644]
MAINTAINERS
Makefile
Makefile.objs
Makefile.target
configure
default-configs/alpha-softmmu.mak
default-configs/arm-softmmu.mak
default-configs/cris-softmmu.mak
default-configs/hppa-softmmu.mak
default-configs/hyperv.mak [deleted file]
default-configs/i386-softmmu.mak
default-configs/lm32-softmmu.mak
default-configs/m68k-softmmu.mak
default-configs/microblaze-softmmu.mak
default-configs/mips-softmmu-common.mak
default-configs/mips64el-softmmu.mak
default-configs/moxie-softmmu.mak
default-configs/nios2-softmmu.mak
default-configs/or1k-softmmu.mak
default-configs/pci.mak [deleted file]
default-configs/ppc-softmmu.mak
default-configs/ppc64-softmmu.mak
default-configs/riscv32-softmmu.mak
default-configs/riscv64-softmmu.mak
default-configs/s390x-softmmu.mak
default-configs/sh4-softmmu.mak
default-configs/sh4eb-softmmu.mak
default-configs/sound.mak [deleted file]
default-configs/sparc-softmmu.mak
default-configs/sparc64-softmmu.mak
default-configs/unicore32-softmmu.mak
default-configs/usb.mak [deleted file]
default-configs/virtio.mak [deleted file]
default-configs/xtensa-softmmu.mak
default-configs/xtensaeb-softmmu.mak
docs/conf.py [new file with mode: 0644]
docs/cpu-hotplug.rst
docs/devel/build-system.txt
docs/devel/conf.py [new file with mode: 0644]
docs/devel/index.rst [new file with mode: 0644]
docs/devel/kconfig.rst [new file with mode: 0644]
docs/devel/memory.rst [new file with mode: 0644]
docs/devel/memory.txt [deleted file]
docs/devel/testing.rst
docs/index.rst [new file with mode: 0644]
docs/interop/conf.py [new file with mode: 0644]
docs/interop/index.rst [new file with mode: 0644]
hw/9pfs/Kconfig [new file with mode: 0644]
hw/9pfs/Makefile.objs
hw/Kconfig [new file with mode: 0644]
hw/Makefile.objs
hw/acpi/Kconfig [new file with mode: 0644]
hw/adc/Kconfig [new file with mode: 0644]
hw/alpha/Kconfig [new file with mode: 0644]
hw/arm/Kconfig [new file with mode: 0644]
hw/audio/Kconfig [new file with mode: 0644]
hw/block/Kconfig [new file with mode: 0644]
hw/block/Makefile.objs
hw/block/dataplane/Makefile.objs
hw/bt/Kconfig [new file with mode: 0644]
hw/char/Kconfig [new file with mode: 0644]
hw/core/Kconfig [new file with mode: 0644]
hw/cpu/Kconfig [new file with mode: 0644]
hw/cris/Kconfig [new file with mode: 0644]
hw/display/Kconfig [new file with mode: 0644]
hw/display/Makefile.objs
hw/dma/Kconfig [new file with mode: 0644]
hw/gpio/Kconfig [new file with mode: 0644]
hw/hppa/Kconfig [new file with mode: 0644]
hw/hyperv/Kconfig [new file with mode: 0644]
hw/i2c/Kconfig [new file with mode: 0644]
hw/i2c/Makefile.objs
hw/i386/Kconfig [new file with mode: 0644]
hw/i386/Makefile.objs
hw/ide/Kconfig [new file with mode: 0644]
hw/input/Kconfig [new file with mode: 0644]
hw/intc/Kconfig [new file with mode: 0644]
hw/ipack/Kconfig [new file with mode: 0644]
hw/ipmi/Kconfig [new file with mode: 0644]
hw/isa/Kconfig [new file with mode: 0644]
hw/lm32/Kconfig [new file with mode: 0644]
hw/m68k/Kconfig [new file with mode: 0644]
hw/mem/Kconfig [new file with mode: 0644]
hw/microblaze/Kconfig [new file with mode: 0644]
hw/mips/Kconfig [new file with mode: 0644]
hw/misc/Kconfig [new file with mode: 0644]
hw/misc/macio/Kconfig [new file with mode: 0644]
hw/moxie/Kconfig [new file with mode: 0644]
hw/net/Kconfig [new file with mode: 0644]
hw/nios2/Kconfig [new file with mode: 0644]
hw/nvram/Kconfig [new file with mode: 0644]
hw/openrisc/Kconfig [new file with mode: 0644]
hw/pci-bridge/Kconfig [new file with mode: 0644]
hw/pci-host/Kconfig [new file with mode: 0644]
hw/pci/Kconfig [new file with mode: 0644]
hw/pci/Makefile.objs
hw/pcmcia/Kconfig [new file with mode: 0644]
hw/ppc/Kconfig [new file with mode: 0644]
hw/riscv/Kconfig [new file with mode: 0644]
hw/s390x/Kconfig [new file with mode: 0644]
hw/s390x/Makefile.objs
hw/scsi/Kconfig [new file with mode: 0644]
hw/scsi/Makefile.objs
hw/sd/Kconfig [new file with mode: 0644]
hw/sh4/Kconfig [new file with mode: 0644]
hw/smbios/Kconfig [new file with mode: 0644]
hw/sparc/Kconfig [new file with mode: 0644]
hw/sparc64/Kconfig [new file with mode: 0644]
hw/ssi/Kconfig [new file with mode: 0644]
hw/timer/Kconfig [new file with mode: 0644]
hw/tpm/Kconfig [new file with mode: 0644]
hw/tricore/Kconfig [new file with mode: 0644]
hw/unicore32/Kconfig [new file with mode: 0644]
hw/usb/Kconfig [new file with mode: 0644]
hw/usb/Makefile.objs
hw/vfio/Kconfig [new file with mode: 0644]
hw/virtio/Kconfig [new file with mode: 0644]
hw/virtio/Makefile.objs
hw/watchdog/Kconfig [new file with mode: 0644]
hw/xtensa/Kconfig [new file with mode: 0644]
hw/xtensa/Makefile.objs
include/migration/qemu-file-types.h
linux-user/elfload.c
linux-user/fd-trans.c
linux-user/nios2/cpu_loop.c
linux-user/strace.c
linux-user/strace.list
linux-user/syscall.c
migration/qemu-file.h
net/Makefile.objs
net/slirp.c
python/qemu/__init__.py [new file with mode: 0644]
python/qemu/qmp.py [new file with mode: 0644]
python/qemu/qtest.py [new file with mode: 0644]
rules.mak
scripts/device-crash-test
scripts/make_device_config.sh [deleted file]
scripts/minikconf.py [new file with mode: 0644]
scripts/qemu.py [deleted file]
scripts/qmp/__init__.py [deleted file]
scripts/qmp/qemu-ga-client
scripts/qmp/qmp-shell
scripts/qmp/qmp.py [deleted file]
scripts/qtest.py [deleted file]
scripts/render_block_graph.py
slirp/Makefile [new file with mode: 0644]
slirp/Makefile.objs [deleted file]
slirp/arp_table.c [deleted file]
slirp/bootp.c [deleted file]
slirp/bootp.h [deleted file]
slirp/cksum.c [deleted file]
slirp/debug.h [deleted file]
slirp/dhcpv6.c [deleted file]
slirp/dhcpv6.h [deleted file]
slirp/dnssearch.c [deleted file]
slirp/if.c [deleted file]
slirp/if.h [deleted file]
slirp/ip.h [deleted file]
slirp/ip6.h [deleted file]
slirp/ip6_icmp.c [deleted file]
slirp/ip6_icmp.h [deleted file]
slirp/ip6_input.c [deleted file]
slirp/ip6_output.c [deleted file]
slirp/ip_icmp.c [deleted file]
slirp/ip_icmp.h [deleted file]
slirp/ip_input.c [deleted file]
slirp/ip_output.c [deleted file]
slirp/libslirp.h [deleted file]
slirp/main.h [deleted file]
slirp/mbuf.c [deleted file]
slirp/mbuf.h [deleted file]
slirp/misc.c [deleted file]
slirp/misc.h [deleted file]
slirp/ncsi-pkt.h [deleted file]
slirp/ncsi.c [deleted file]
slirp/ndp_table.c [deleted file]
slirp/qtailq.h [deleted file]
slirp/sbuf.c [deleted file]
slirp/sbuf.h [deleted file]
slirp/slirp.c [deleted file]
slirp/slirp.h [deleted file]
slirp/socket.c [deleted file]
slirp/socket.h [deleted file]
slirp/src/arp_table.c [new file with mode: 0644]
slirp/src/bootp.c [new file with mode: 0644]
slirp/src/bootp.h [new file with mode: 0644]
slirp/src/cksum.c [new file with mode: 0644]
slirp/src/debug.h [new file with mode: 0644]
slirp/src/dhcpv6.c [new file with mode: 0644]
slirp/src/dhcpv6.h [new file with mode: 0644]
slirp/src/dnssearch.c [new file with mode: 0644]
slirp/src/if.c [new file with mode: 0644]
slirp/src/if.h [new file with mode: 0644]
slirp/src/ip.h [new file with mode: 0644]
slirp/src/ip6.h [new file with mode: 0644]
slirp/src/ip6_icmp.c [new file with mode: 0644]
slirp/src/ip6_icmp.h [new file with mode: 0644]
slirp/src/ip6_input.c [new file with mode: 0644]
slirp/src/ip6_output.c [new file with mode: 0644]
slirp/src/ip_icmp.c [new file with mode: 0644]
slirp/src/ip_icmp.h [new file with mode: 0644]
slirp/src/ip_input.c [new file with mode: 0644]
slirp/src/ip_output.c [new file with mode: 0644]
slirp/src/libslirp.h [new file with mode: 0644]
slirp/src/main.h [new file with mode: 0644]
slirp/src/mbuf.c [new file with mode: 0644]
slirp/src/mbuf.h [new file with mode: 0644]
slirp/src/misc.c [new file with mode: 0644]
slirp/src/misc.h [new file with mode: 0644]
slirp/src/ncsi-pkt.h [new file with mode: 0644]
slirp/src/ncsi.c [new file with mode: 0644]
slirp/src/ndp_table.c [new file with mode: 0644]
slirp/src/qtailq.h [new file with mode: 0644]
slirp/src/sbuf.c [new file with mode: 0644]
slirp/src/sbuf.h [new file with mode: 0644]
slirp/src/slirp.c [new file with mode: 0644]
slirp/src/slirp.h [new file with mode: 0644]
slirp/src/socket.c [new file with mode: 0644]
slirp/src/socket.h [new file with mode: 0644]
slirp/src/state.c [new file with mode: 0644]
slirp/src/state.h [new file with mode: 0644]
slirp/src/stream.c [new file with mode: 0644]
slirp/src/stream.h [new file with mode: 0644]
slirp/src/tcp.h [new file with mode: 0644]
slirp/src/tcp_input.c [new file with mode: 0644]
slirp/src/tcp_output.c [new file with mode: 0644]
slirp/src/tcp_subr.c [new file with mode: 0644]
slirp/src/tcp_timer.c [new file with mode: 0644]
slirp/src/tcp_timer.h [new file with mode: 0644]
slirp/src/tcp_var.h [new file with mode: 0644]
slirp/src/tcpip.h [new file with mode: 0644]
slirp/src/tftp.c [new file with mode: 0644]
slirp/src/tftp.h [new file with mode: 0644]
slirp/src/udp.c [new file with mode: 0644]
slirp/src/udp.h [new file with mode: 0644]
slirp/src/udp6.c [new file with mode: 0644]
slirp/src/util.c [new file with mode: 0644]
slirp/src/util.h [new file with mode: 0644]
slirp/src/vmstate.c [new file with mode: 0644]
slirp/src/vmstate.h [new file with mode: 0644]
slirp/state.c [deleted file]
slirp/state.h [deleted file]
slirp/tcp.h [deleted file]
slirp/tcp_input.c [deleted file]
slirp/tcp_output.c [deleted file]
slirp/tcp_subr.c [deleted file]
slirp/tcp_timer.c [deleted file]
slirp/tcp_timer.h [deleted file]
slirp/tcp_var.h [deleted file]
slirp/tcpip.h [deleted file]
slirp/tftp.c [deleted file]
slirp/tftp.h [deleted file]
slirp/udp.c [deleted file]
slirp/udp.h [deleted file]
slirp/udp6.c [deleted file]
slirp/util.c [deleted file]
slirp/util.h [deleted file]
tests/acceptance/avocado_qemu/__init__.py
tests/acceptance/boot_linux_console.py
tests/acceptance/linux_initrd.py
tests/acceptance/migration.py [new file with mode: 0644]
tests/acceptance/version.py
tests/acceptance/virtio_version.py
tests/acceptance/vnc.py
tests/migration/guestperf/engine.py
tests/qemu-iotests/235
tests/qemu-iotests/238
tests/qemu-iotests/iotests.py
tests/requirements.txt
tests/vm/basevm.py
util/Makefile.objs
util/main-loop.c
vl.c

index b66b7725512c7e0abe5644263c445e1fc4c6f711..77522561b8ea3d168b3c29c69309b7171db27ad6 100644 (file)
@@ -1,3 +1,4 @@
+/.doctrees
 /config-devices.*
 /config-all-devices.*
 /config-all-disas.*
index cca57f4314806d5d42b939dc3159e5630ea9975b..e942175dd30cb4d27a698e4d1c3f7e86de992ff4 100644 (file)
@@ -149,6 +149,12 @@ matrix:
         - ${SRC_DIR}/scripts/travis/coverage-summary.sh
 
 
+    # We manually include builds which we disable "make check" for
+    - env:
+        - CONFIG="--without-default-devices"
+        - TEST_CMD=""
+
+
     # We manually include builds which we disable "make check" for
     - env:
         - CONFIG="--enable-debug --enable-tcg-interpreter"
diff --git a/Kconfig.host b/Kconfig.host
new file mode 100644 (file)
index 0000000..add5b17
--- /dev/null
@@ -0,0 +1,33 @@
+# These are "proxy" symbols used to pass config-host.mak values
+# down to Kconfig.  See also MINIKCONF_ARGS in the Makefile:
+# these two need to be kept in sync.
+
+config KVM
+    bool
+
+config LINUX
+    bool
+
+config OPENGL
+    bool
+
+config X11
+    bool
+
+config SPICE
+    bool
+
+config IVSHMEM
+    bool
+
+config TPM
+    bool
+
+config VHOST_USER
+    bool
+
+config XEN
+    bool
+
+config VIRTFS
+    bool
index 5040d9dfb125aeacc40db1fd82e125c3bd73c3fe..074ad46d47335663b27b5481178a9d9064bd532f 100644 (file)
@@ -2567,3 +2567,9 @@ GIT submodules
 M: Daniel P. Berrange <berrange@redhat.com>
 S: Odd Fixes
 F: scripts/git-submodule.sh
+
+Sphinx documentation configuration and build machinery
+M: Peter Maydell <peter.maydell@linaro.org>
+S: Maintained
+F: docs/conf.py
+F: docs/*/conf.py
index 2208bde4196166867b11c79e11abc4148fa31f1f..d2463c92371fa225c1778a2c1f9fee177bf18f8a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -87,6 +87,20 @@ endif
 
 include $(SRC_PATH)/rules.mak
 
+# Create QEMU_PKGVERSION and FULL_VERSION strings
+# If PKGVERSION is set, use that; otherwise get version and -dirty status from git
+QEMU_PKGVERSION := $(if $(PKGVERSION),$(PKGVERSION),$(shell \
+  cd $(SRC_PATH); \
+  if test -e .git; then \
+    git describe --match 'v*' 2>/dev/null | tr -d '\n'; \
+    if ! git diff-index --quiet HEAD &>/dev/null; then \
+      echo "-dirty"; \
+    fi; \
+  fi))
+
+# Either "version (pkgversion)", or just "version" if pkgversion not set
+FULL_VERSION := $(if $(QEMU_PKGVERSION),$(VERSION) ($(QEMU_PKGVERSION)),$(VERSION))
+
 GENERATED_FILES = qemu-version.h config-host.h qemu-options.def
 
 GENERATED_QAPI_FILES = qapi/qapi-builtin-types.h qapi/qapi-builtin-types.c
@@ -313,8 +327,8 @@ DOCS=
 endif
 
 SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory --quiet) BUILD_DIR=$(BUILD_DIR)
-SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
-SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %-config-devices.mak.d, $(TARGET_DIRS))
+SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(filter %-softmmu, $(TARGET_DIRS)))
+SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %.d, $(SUBDIR_DEVICES_MAK))
 
 ifeq ($(SUBDIR_DEVICES_MAK),)
 config-all-devices.mak:
@@ -329,9 +343,26 @@ endif
 
 -include $(SUBDIR_DEVICES_MAK_DEP)
 
-%/config-devices.mak: default-configs/%.mak $(SRC_PATH)/scripts/make_device_config.sh
-       $(call quiet-command, \
-            $(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $< $*-config-devices.mak.d $@ > $@.tmp,"GEN","$@.tmp")
+# This has to be kept in sync with Kconfig.host.
+MINIKCONF_ARGS = \
+    $(CONFIG_MINIKCONF_MODE) \
+    $@ $*-config.devices.mak.d $< $(MINIKCONF_INPUTS) \
+    CONFIG_KVM=$(CONFIG_KVM) \
+    CONFIG_SPICE=$(CONFIG_SPICE) \
+    CONFIG_IVSHMEM=$(CONFIG_IVSHMEM) \
+    CONFIG_TPM=$(CONFIG_TPM) \
+    CONFIG_XEN=$(CONFIG_XEN) \
+    CONFIG_OPENGL=$(CONFIG_OPENGL) \
+    CONFIG_X11=$(CONFIG_X11) \
+    CONFIG_VHOST_USER=$(CONFIG_VHOST_USER) \
+    CONFIG_VIRTFS=$(CONFIG_VIRTFS) \
+    CONFIG_LINUX=$(CONFIG_LINUX)
+
+MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/hw/Kconfig
+MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py \
+
+$(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(MINIKCONF_INPUTS) $(BUILD_DIR)/config-host.mak
+       $(call quiet-command, $(MINIKCONF) $(MINIKCONF_ARGS) > $@.tmp, "GEN", "$@.tmp")
        $(call quiet-command, if test -f $@; then \
          if cmp -s $@.old $@; then \
            mv $@.tmp $@; \
@@ -383,32 +414,16 @@ dummy := $(call unnest-vars,, \
                 ui-obj-m \
                 audio-obj-y \
                 audio-obj-m \
-                trace-obj-y \
-                slirp-obj-y)
+                trace-obj-y)
 
 include $(SRC_PATH)/tests/Makefile.include
 
-all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all modules
+all: $(DOCS) $(if $(BUILD_DOCS),sphinxdocs) $(TOOLS) $(HELPERS-y) recurse-all modules
 
 qemu-version.h: FORCE
        $(call quiet-command, \
-               (cd $(SRC_PATH); \
-               if test -n "$(PKGVERSION)"; then \
-                       pkgvers="$(PKGVERSION)"; \
-               else \
-                       if test -d .git; then \
-                               pkgvers=$$(git describe --match 'v*' 2>/dev/null | tr -d '\n');\
-                               if ! git diff-index --quiet HEAD &>/dev/null; then \
-                                       pkgvers="$${pkgvers}-dirty"; \
-                               fi; \
-                       fi; \
-               fi; \
-               printf "#define QEMU_PKGVERSION \"$${pkgvers}\"\n"; \
-               if test -n "$${pkgvers}"; then \
-                       printf '#define QEMU_FULL_VERSION QEMU_VERSION " (" QEMU_PKGVERSION ")"\n'; \
-               else \
-                       printf '#define QEMU_FULL_VERSION QEMU_VERSION\n'; \
-               fi; \
+                (printf '#define QEMU_PKGVERSION "$(QEMU_PKGVERSION)"\n'; \
+               printf '#define QEMU_FULL_VERSION "$(FULL_VERSION)"\n'; \
                ) > $@.tmp)
        $(call quiet-command, if ! cmp -s $@ $@.tmp; then \
          mv $@.tmp $@; \
@@ -458,7 +473,10 @@ CAP_CFLAGS += -DCAPSTONE_HAS_X86
 subdir-capstone: .git-submodule-status
        $(call quiet-command,$(MAKE) -C $(SRC_PATH)/capstone CAPSTONE_SHARED=no BUILDDIR="$(BUILD_DIR)/capstone" CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" CFLAGS="$(CAP_CFLAGS)" $(SUBDIR_MAKEFLAGS) $(BUILD_DIR)/capstone/$(LIBCAPSTONE))
 
-$(SUBDIR_RULES): libqemuutil.a $(common-obj-y) $(chardev-obj-y) $(slirp-obj-y) \
+subdir-slirp: .git-submodule-status
+       $(call quiet-command,$(MAKE) -C $(SRC_PATH)/slirp BUILD_DIR="$(BUILD_DIR)/slirp" CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" CFLAGS="$(QEMU_CFLAGS)")
+
+$(SUBDIR_RULES): libqemuutil.a $(common-obj-y) $(chardev-obj-y) \
        $(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY))
 
 ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
@@ -637,6 +655,14 @@ dist: qemu-$(VERSION).tar.bz2
 qemu-%.tar.bz2:
        $(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.bz2,%,$@)"
 
+# Note that these commands assume that there are no HTML files in
+# the docs subdir in the source tree! If there are then this will
+# blow them away for an in-source-tree 'make clean'.
+define clean-manual =
+rm -rf docs/$1/_static
+rm -f docs/$1/objects.inv docs/$1/searchindex.js docs/$1/*.html
+endef
+
 distclean: clean
        rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi qemu-monitor-info.texi
        rm -f config-all-devices.mak config-all-disas.mak config.status
@@ -657,6 +683,9 @@ distclean: clean
        rm -f docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html
        rm -f docs/qemu-block-drivers.7
        rm -f docs/qemu-cpu-models.7
+       rm -f .doctrees
+       $(call clean-manual,devel)
+       $(call clean-manual,interop)
        for d in $(TARGET_DIRS); do \
        rm -rf $$d || exit 1 ; \
         done
@@ -690,7 +719,18 @@ else
 BLOBS=
 endif
 
-install-doc: $(DOCS)
+define install-manual =
+for d in $$(cd docs && find $1 -type d); do $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)/$$d"; done
+for f in $$(cd docs && find $1 -type f); do $(INSTALL_DATA) "docs/$$f" "$(DESTDIR)$(qemu_docdir)/$$f"; done
+endef
+
+# Note that we deliberately do not install the "devel" manual: it is
+# for QEMU developers, and not interesting to our users.
+.PHONY: install-sphinxdocs
+install-sphinxdocs: sphinxdocs
+       $(call install-manual,interop)
+
+install-doc: $(DOCS) install-sphinxdocs
        $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
        $(INSTALL_DATA) qemu-doc.html "$(DESTDIR)$(qemu_docdir)"
        $(INSTALL_DATA) qemu-doc.txt "$(DESTDIR)$(qemu_docdir)"
@@ -841,6 +881,23 @@ docs/version.texi: $(SRC_PATH)/VERSION
 %.pdf: %.texi docs/version.texi
        $(call quiet-command,texi2pdf $(TEXI2PDFFLAGS) $< -o $@,"GEN","$@")
 
+# Sphinx builds all its documentation at once in one invocation
+# and handles "don't rebuild things unless necessary" itself.
+# The '.doctrees' files are cached information to speed this up.
+.PHONY: sphinxdocs
+sphinxdocs: docs/devel/index.html docs/interop/index.html
+
+# Canned command to build a single manual
+build-manual = $(call quiet-command,sphinx-build $(if $(V),,-q) -b html -D version=$(VERSION) -D release="$(FULL_VERSION)" -d .doctrees/$1 $(SRC_PATH)/docs/$1 docs/$1 ,"SPHINX","docs/$1")
+# We assume all RST files in the manual's directory are used in it
+manual-deps = $(wildcard $(SRC_PATH)/docs/$1/*.rst) $(SRC_PATH)/docs/$1/conf.py $(SRC_PATH)/docs/conf.py
+
+docs/devel/index.html: $(call manual-deps,devel)
+       $(call build-manual,devel)
+
+docs/interop/index.html: $(call manual-deps,interop)
+       $(call build-manual,interop)
+
 qemu-options.texi: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
        $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
 
@@ -869,7 +926,7 @@ docs/qemu-block-drivers.7: docs/qemu-block-drivers.texi
 docs/qemu-cpu-models.7: docs/qemu-cpu-models.texi
 scripts/qemu-trace-stap.1: scripts/qemu-trace-stap.texi
 
-html: qemu-doc.html docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html
+html: qemu-doc.html docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html sphinxdocs
 info: qemu-doc.info docs/interop/qemu-qmp-ref.info docs/interop/qemu-ga-ref.info
 pdf: qemu-doc.pdf docs/interop/qemu-qmp-ref.pdf docs/interop/qemu-ga-ref.pdf
 txt: qemu-doc.txt docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.txt
index 6e91ee5674b3a4b36e90ff9dfd147db529fed77a..ef65a6c12ef0d66a5e5664c382d6370b08a68274 100644 (file)
@@ -4,7 +4,6 @@ stub-obj-y = stubs/ util/ crypto/
 util-obj-y = util/ qobject/ qapi/
 
 chardev-obj-y = chardev/
-slirp-obj-$(CONFIG_SLIRP) = slirp/
 
 #######################################################################
 # authz-obj-y is code used by both qemu system emulation and qemu-img
index 3b79e7074c87d0930935ebb2a500d9e09e70a327..40830c5646563ee9aee3120e180389d378e2a208 100644 (file)
@@ -4,9 +4,12 @@ BUILD_DIR?=$(CURDIR)/..
 
 include ../config-host.mak
 include config-target.mak
-include config-devices.mak
 include $(SRC_PATH)/rules.mak
 
+ifdef CONFIG_SOFTMMU
+include config-devices.mak
+endif
+
 $(call set-vpath, $(SRC_PATH):$(BUILD_DIR))
 ifdef CONFIG_LINUX
 QEMU_CFLAGS += -I../linux-headers
@@ -174,7 +177,6 @@ target-obj-y :=
 block-obj-y :=
 common-obj-y :=
 chardev-obj-y :=
-slirp-obj-y :=
 include $(SRC_PATH)/Makefile.objs
 dummy := $(call unnest-vars,,target-obj-y)
 target-obj-y-save := $(target-obj-y)
@@ -188,8 +190,7 @@ dummy := $(call unnest-vars,.., \
                qom-obj-y \
                io-obj-y \
                common-obj-y \
-               common-obj-m \
-               slirp-obj-y)
+               common-obj-m)
 target-obj-y := $(target-obj-y-save)
 all-obj-y += $(common-obj-y)
 all-obj-y += $(target-obj-y)
@@ -199,9 +200,10 @@ all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y) $(chardev-obj-y)
 all-obj-$(CONFIG_USER_ONLY) += $(crypto-aes-obj-y)
 all-obj-$(CONFIG_SOFTMMU) += $(crypto-obj-y)
 all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y)
-all-obj-$(CONFIG_SOFTMMU) += $(slirp-obj-y)
 
+ifdef CONFIG_SOFTMMU
 $(QEMU_PROG_BUILD): config-devices.mak
+endif
 
 COMMON_LDADDS = ../libqemuutil.a
 
index f7b8c2ea946fbccba540f644f9261b918f9df757..79453a674fe8109b256ab3a2301f4a5fa570fbfd 100755 (executable)
--- a/configure
+++ b/configure
@@ -406,7 +406,7 @@ includedir="\${prefix}/include"
 sysconfdir="\${prefix}/etc"
 local_statedir="\${prefix}/var"
 confsuffix="/qemu"
-slirp="yes"
+slirp=""
 oss_lib=""
 bsd="no"
 linux="no"
@@ -466,7 +466,7 @@ gcrypt_hmac="no"
 auth_pam=""
 vte=""
 virglrenderer=""
-tpm="yes"
+tpm=""
 libssh2=""
 live_block_migration="yes"
 numa=""
@@ -487,7 +487,7 @@ libxml2=""
 docker="no"
 debug_mutex="no"
 libpmem=""
-libudev="no"
+default_devices="yes"
 
 # cross compilers defaults, can be overridden with --cross-cc-ARCH
 cross_cc_aarch64="aarch64-linux-gnu-gcc"
@@ -996,6 +996,10 @@ for opt do
   ;;
   --with-trace-file=*) trace_file="$optarg"
   ;;
+  --with-default-devices) default_devices="yes"
+  ;;
+  --without-default-devices) default_devices="no"
+  ;;
   --enable-gprof) gprof="yes"
   ;;
   --enable-gcov) gcov="yes"
@@ -1105,6 +1109,10 @@ for opt do
   ;;
   --disable-slirp) slirp="no"
   ;;
+  --enable-slirp=git) slirp="git"
+  ;;
+  --enable-slirp=system) slirp="system"
+  ;;
   --disable-vde) vde="no"
   ;;
   --enable-vde) vde="yes"
@@ -3873,20 +3881,20 @@ EOF
 fi
 
 ##########################################
-# TPM passthrough is only on x86 Linux
+# TPM emulation is only on POSIX
 
-if test "$targetos" = Linux && { test "$cpu" = i386 || test "$cpu" = x86_64; }; then
-  tpm_passthrough=$tpm
-else
-  tpm_passthrough=no
+if test "$tpm" = ""; then
+  if test "$mingw32" = "yes"; then
+    tpm=no
+  else
+    tpm=yes
+  fi
+elif test "$tpm" = "yes"; then
+  if test "$mingw32" = "yes" ; then
+    error_exit "TPM emulation only available on POSIX systems"
+  fi
 fi
 
-# TPM emulator is for all posix systems
-if test "$mingw32" != "yes"; then
-  tpm_emulator=$tpm
-else
-  tpm_emulator=no
-fi
 ##########################################
 # attr probe
 
@@ -4589,13 +4597,24 @@ if compile_prog "" "" ; then
   syncfs=yes
 fi
 
+# Check we have a new enough version of sphinx-build
+has_sphinx_build() {
+    # This is a bit awkward but works: create a trivial document and
+    # try to run it with our configuration file (which enforces a
+    # version requirement). This will fail if either
+    # sphinx-build doesn't exist at all or if it is too old.
+    mkdir -p "$TMPDIR1/sphinx"
+    touch "$TMPDIR1/sphinx/index.rst"
+    sphinx-build -c "$source_path/docs" -b html "$TMPDIR1/sphinx" "$TMPDIR1/sphinx/out" >/dev/null 2>&1
+}
+
 # Check if tools are available to build documentation.
 if test "$docs" != "no" ; then
-  if has makeinfo && has pod2man; then
+  if has makeinfo && has pod2man && has_sphinx_build; then
     docs=yes
   else
     if test "$docs" = "yes" ; then
-      feature_not_found "docs" "Install texinfo and Perl/perl-podlators"
+      feature_not_found "docs" "Install texinfo, Perl/perl-podlators and python-sphinx"
     fi
     docs=no
   fi
@@ -5754,6 +5773,55 @@ if test "$libpmem" != "no"; then
        fi
 fi
 
+##########################################
+# check for slirp
+
+case "$slirp" in
+  "" | yes)
+    if $pkg_config slirp; then
+      slirp=system
+    elif test -e "${source_path}/.git" && test $git_update = 'yes' ; then
+      slirp=git
+    elif test -e "${source_path}/slirp/Makefile" ; then
+      slirp=internal
+    elif test -z "$slirp" ; then
+      slirp=no
+    else
+      feature_not_found "slirp" "Install slirp devel or git submodule"
+    fi
+    ;;
+
+  system)
+    if ! $pkg_config slirp; then
+      feature_not_found "slirp" "Install slirp devel"
+    fi
+    ;;
+esac
+
+case "$slirp" in
+  git | internal)
+    if test "$slirp" = git; then
+      git_submodules="${git_submodules} slirp"
+    fi
+    mkdir -p slirp
+    slirp_cflags="-I\$(SRC_PATH)/slirp/src -I\$(BUILD_DIR)/slirp/src"
+    slirp_libs="-L\$(BUILD_DIR)/slirp -lslirp"
+    ;;
+
+  system)
+    slirp_version=$($pkg_config --modversion slirp 2>/dev/null)
+    slirp_cflags=$($pkg_config --cflags slirp 2>/dev/null)
+    slirp_libs=$($pkg_config --libs slirp 2>/dev/null)
+    ;;
+
+  no)
+    ;;
+  *)
+    error_exit "Unknown state for slirp: $slirp"
+    ;;
+esac
+
+
 ##########################################
 # End of CC checks
 # After here, no more $cc or $ld runs
@@ -6111,7 +6179,8 @@ echo "QEMU_LDFLAGS      $QEMU_LDFLAGS"
 echo "make              $make"
 echo "install           $install"
 echo "python            $python ($python_version)"
-if test "$slirp" = "yes" ; then
+echo "slirp support     $slirp $(echo_version $slirp $slirp_version)"
+if test "$slirp" != "no" ; then
     echo "smbd              $smbd"
 fi
 echo "module support    $modules"
@@ -6250,6 +6319,7 @@ echo "capstone          $capstone"
 echo "docker            $docker"
 echo "libpmem support   $libpmem"
 echo "libudev           $libudev"
+echo "default devices   $default_devices"
 
 if test "$supported_cpu" = "no"; then
     echo
@@ -6311,6 +6381,11 @@ echo "GIT_UPDATE=$git_update" >> $config_host_mak
 
 echo "ARCH=$ARCH" >> $config_host_mak
 
+if test "$default_devices" = "yes" ; then
+  echo "CONFIG_MINIKCONF_MODE=--defconfig" >> $config_host_mak
+else
+  echo "CONFIG_MINIKCONF_MODE=--allnoconfig" >> $config_host_mak
+fi
 if test "$debug_tcg" = "yes" ; then
   echo "CONFIG_DEBUG_TCG=y" >> $config_host_mak
 fi
@@ -6372,9 +6447,14 @@ fi
 if test "$profiler" = "yes" ; then
   echo "CONFIG_PROFILER=y" >> $config_host_mak
 fi
-if test "$slirp" = "yes" ; then
+if test "$slirp" != "no"; then
   echo "CONFIG_SLIRP=y" >> $config_host_mak
   echo "CONFIG_SMBD_COMMAND=\"$smbd\"" >> $config_host_mak
+  echo "SLIRP_CFLAGS=$slirp_cflags" >> $config_host_mak
+  echo "SLIRP_LIBS=$slirp_libs" >> $config_host_mak
+fi
+if [ "$slirp" = "git" -o "$slirp" = "internal" ]; then
+    echo "config-host.h: subdir-slirp" >> $config_host_mak
 fi
 if test "$vde" = "yes" ; then
   echo "CONFIG_VDE=y" >> $config_host_mak
@@ -7427,12 +7507,18 @@ fi
 
 if supported_xen_target $target; then
     echo "CONFIG_XEN=y" >> $config_target_mak
+    echo "$target/config-devices.mak: CONFIG_XEN=y" >> $config_host_mak
     if test "$xen_pci_passthrough" = yes; then
         echo "CONFIG_XEN_PCI_PASSTHROUGH=y" >> "$config_target_mak"
     fi
+else
+    echo "$target/config-devices.mak: CONFIG_XEN=n" >> $config_host_mak
 fi
 if supported_kvm_target $target; then
     echo "CONFIG_KVM=y" >> $config_target_mak
+    echo "$target/config-devices.mak: CONFIG_KVM=y" >> $config_host_mak
+else
+    echo "$target/config-devices.mak: CONFIG_KVM=n" >> $config_host_mak
 fi
 if supported_hax_target $target; then
     echo "CONFIG_HAX=y" >> $config_target_mak
@@ -7663,6 +7749,7 @@ LINKS="$LINKS pc-bios/qemu-icon.bmp"
 LINKS="$LINKS .gdbinit scripts" # scripts needed by relative path in .gdbinit
 LINKS="$LINKS tests/acceptance tests/data"
 LINKS="$LINKS tests/qemu-iotests/check"
+LINKS="$LINKS python"
 for bios_file in \
     $source_path/pc-bios/*.bin \
     $source_path/pc-bios/*.lid \
index 49cb7ce3511a73e56fb0b3ba9328136cec5e8fa7..d186fe8e9b146f4783f83d826f31d05ad1cba8e3 100644 (file)
@@ -1,22 +1,10 @@
 # Default configuration for alpha-softmmu
 
-include pci.mak
-include usb.mak
-CONFIG_SERIAL=y
-CONFIG_SERIAL_ISA=y
-CONFIG_I82374=y
-CONFIG_I8254=y
-CONFIG_I8257=y
-CONFIG_PARALLEL=y
-CONFIG_FDC=y
-CONFIG_PCKBD=y
-CONFIG_VGA_CIRRUS=y
-CONFIG_IDE_CORE=y
-CONFIG_IDE_QDEV=y
-CONFIG_VMWARE_VGA=y
-CONFIG_IDE_CMD646=y
-CONFIG_I8259=y
-CONFIG_MC146818RTC=y
-CONFIG_ISA_TESTDEV=y
-CONFIG_SMC37C669=y
+# Uncomment the following lines to disable these optional devices:
+#
+#CONFIG_PCI_DEVICES=n
+#CONFIG_TEST_DEVICES=n
+
+# Boards:
+#
 CONFIG_DP264=y
index bd6943b691ad512db2c01f61898f66d4284ba623..2a7efc11674a064dae892abe19fff2f5608f8d34 100644 (file)
@@ -1,13 +1,11 @@
 # Default configuration for arm-softmmu
 
-include pci.mak
-include usb.mak
+CONFIG_PCI=y
+CONFIG_PCI_DEVICES=y
 CONFIG_VGA=y
 CONFIG_NAND=y
 CONFIG_ECC=y
 CONFIG_SERIAL=y
-CONFIG_PTIMER=y
-CONFIG_SD=y
 CONFIG_MAX7310=y
 CONFIG_WM8750=y
 CONFIG_TWL92230=y
@@ -25,7 +23,6 @@ CONFIG_DDC=y
 CONFIG_SII9022=y
 CONFIG_ADS7846=y
 CONFIG_MAX111X=y
-CONFIG_SSI=y
 CONFIG_SSI_SD=y
 CONFIG_SSI_M25P80=y
 CONFIG_LAN9118=y
@@ -37,7 +34,6 @@ CONFIG_DS1338=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_MICRODRIVE=y
-CONFIG_USB=y
 CONFIG_USB_MUSB=y
 CONFIG_USB_EHCI_SYSBUS=y
 CONFIG_PLATFORM_BUS=y
@@ -51,7 +47,6 @@ CONFIG_ARM_V7M=y
 CONFIG_NETDUINO2=y
 
 CONFIG_ARM_GIC=y
-CONFIG_ARM_GIC_KVM=$(CONFIG_KVM)
 CONFIG_ARM_TIMER=y
 CONFIG_ARM_MPTIMER=y
 CONFIG_A9_GTIMER=y
@@ -71,7 +66,6 @@ CONFIG_CADENCE=y
 CONFIG_XGMAC=y
 CONFIG_EXYNOS4=y
 CONFIG_PXA2XX=y
-CONFIG_I2C=y
 CONFIG_BITBANG_I2C=y
 CONFIG_FRAMEBUFFER=y
 CONFIG_XILINX_SPIPS=y
@@ -125,11 +119,8 @@ CONFIG_VERSATILE=y
 CONFIG_VERSATILE_PCI=y
 CONFIG_VERSATILE_I2C=y
 
+CONFIG_PCI_EXPRESS=y
 CONFIG_PCI_EXPRESS_GENERIC_BRIDGE=y
-CONFIG_VFIO=$(CONFIG_LINUX)
-CONFIG_VFIO_PLATFORM=y
-CONFIG_VFIO_XGMAC=y
-CONFIG_VFIO_AMD_XGBE=y
 
 CONFIG_SDHCI=y
 CONFIG_INTEGRATOR=y
@@ -165,3 +156,6 @@ CONFIG_PCI_EXPRESS_DESIGNWARE=y
 CONFIG_STRONGARM=y
 CONFIG_HIGHBANK=y
 CONFIG_MUSICPAL=y
+
+# for realview and versatilepb
+CONFIG_LSI_SCSI_PCI=y
index a637c4b4bf73bc7b2f8186a7fe9bbe2670fc925c..5932cf4d06fbf0564730cd6607409d91c01f562a 100644 (file)
@@ -1,7 +1,5 @@
 # Default configuration for cris-softmmu
 
-CONFIG_ETRAXFS=y
-CONFIG_NAND=y
-CONFIG_PTIMER=y
-CONFIG_PFLASH_CFI02=y
+# Boards:
+#
 CONFIG_AXIS=y
index b594a6ddd94e8b54f92bf8b775de15945fc76cbf..b64c5eb3ff6453514461b64699633fcec5cfea52 100644 (file)
@@ -1,13 +1,9 @@
-include pci.mak
-include usb.mak
-CONFIG_SERIAL=y
-CONFIG_SERIAL_ISA=y
-CONFIG_ISA_BUS=y
-CONFIG_I8259=y
-CONFIG_E1000_PCI=y
-CONFIG_IDE_ISA=y
-CONFIG_IDE_CMD646=y
-# CONFIG_IDE_MMIO=y
-CONFIG_VIRTIO_VGA=y
-CONFIG_MC146818RTC=y
+# Default configuration for hppa-softmmu
+
+# Uncomment the following lines to disable these optional devices:
+#
+#CONFIG_PCI_DEVICES=n
+
+# Boards:
+#
 CONFIG_DINO=y
diff --git a/default-configs/hyperv.mak b/default-configs/hyperv.mak
deleted file mode 100644 (file)
index 5d0d9fd..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-CONFIG_HYPERV=$(CONFIG_KVM)
-CONFIG_HYPERV_TESTDEV=y
index 15b628757bae244e696c9d5f3c587cf36ff5c11f..ba3fb3ff50a7494c4b0814ffd758dc1b536a4e41 100644 (file)
@@ -1,74 +1,27 @@
 # Default configuration for i386-softmmu
 
-include pci.mak
-include sound.mak
-include usb.mak
-include hyperv.mak
-CONFIG_QXL=$(CONFIG_SPICE)
-CONFIG_VGA_ISA=y
-CONFIG_VGA_CIRRUS=y
-CONFIG_VMWARE_VGA=y
-CONFIG_VMXNET3_PCI=y
-CONFIG_VIRTIO_VGA=y
-CONFIG_VMMOUSE=y
-CONFIG_IPMI=y
-CONFIG_IPMI_LOCAL=y
-CONFIG_IPMI_EXTERN=y
-CONFIG_ISA_IPMI_KCS=y
-CONFIG_ISA_IPMI_BT=y
-CONFIG_SERIAL=y
-CONFIG_SERIAL_ISA=y
-CONFIG_PARALLEL=y
-CONFIG_I8254=y
-CONFIG_PCSPK=y
-CONFIG_PCKBD=y
-CONFIG_FDC=y
-CONFIG_ACPI=y
-CONFIG_ACPI_X86=y
-CONFIG_ACPI_X86_ICH=y
-CONFIG_ACPI_MEMORY_HOTPLUG=y
-CONFIG_ACPI_CPU_HOTPLUG=y
-CONFIG_APM=y
-CONFIG_I8257=y
-CONFIG_IDE_ISA=y
-CONFIG_IDE_PIIX=y
-CONFIG_NE2000_ISA=y
-CONFIG_HPET=y
-CONFIG_APPLESMC=y
-CONFIG_I8259=y
-CONFIG_PFLASH_CFI01=y
-CONFIG_TPM_TIS=$(CONFIG_TPM)
-CONFIG_TPM_CRB=$(CONFIG_TPM)
-CONFIG_MC146818RTC=y
-CONFIG_PCI_PIIX=y
-CONFIG_WDT_IB700=y
-CONFIG_ISA_DEBUG=y
-CONFIG_ISA_TESTDEV=y
-CONFIG_VMPORT=y
-CONFIG_SGA=y
-CONFIG_LPC_ICH9=y
-CONFIG_PCI_EXPRESS_Q35=y
-CONFIG_APIC=y
-CONFIG_IOAPIC=y
-CONFIG_PVPANIC=y
-CONFIG_MEM_DEVICE=y
-CONFIG_DIMM=y
-CONFIG_NVDIMM=y
-CONFIG_ACPI_NVDIMM=y
-CONFIG_PCIE_PORT=y
-CONFIG_XIO3130=y
-CONFIG_IOH3420=y
-CONFIG_I82801B11=y
-CONFIG_SMBIOS=y
-CONFIG_PXB=y
-CONFIG_ACPI_VMGENID=y
-CONFIG_ACPI_SMBUS=y
-CONFIG_SMBUS_EEPROM=y
-CONFIG_FW_CFG_DMA=y
-CONFIG_I2C=y
-CONFIG_SEV=$(CONFIG_KVM)
-CONFIG_VTD=y
-CONFIG_AMD_IOMMU=y
-CONFIG_PAM=y
+# Uncomment the following lines to disable these optional devices:
+#
+#CONFIG_AMD_IOMMU=n
+#CONFIG_APPLESMC=n
+#CONFIG_FDC=n
+#CONFIG_HPET=n
+#CONFIG_HYPERV=n
+#CONFIG_ISA_DEBUG=n
+#CONFIG_ISA_IPMI_BT=n
+#CONFIG_ISA_IPMI_KCS=n
+#CONFIG_PCI_DEVICES=n
+#CONFIG_PVPANIC=n
+#CONFIG_QXL=n
+#CONFIG_SEV=n
+#CONFIG_SGA=n
+#CONFIG_TEST_DEVICES=n
+#CONFIG_TPM_CRB=n
+#CONFIG_TPM_TIS=n
+#CONFIG_VTD=n
+
+# Boards:
+#
+CONFIG_ISAPC=y
 CONFIG_I440FX=y
 CONFIG_Q35=y
index 4049b23562bdf0ea10f3490598030ecbe8c9d1e4..6d259665d604b4a0cc07d4130ac52b729500e3d1 100644 (file)
@@ -1,10 +1,10 @@
 # Default configuration for lm32-softmmu
 
+# Uncomment the following lines to disable these optional devices:
+#
+#CONFIG_MILKYMIST_TMU2=n        # disabling it actually causes compile-time failures
+
+# Boards:
+#
 CONFIG_LM32=y
 CONFIG_MILKYMIST=y
-CONFIG_MILKYMIST_TMU2=$(call land,$(CONFIG_X11),$(CONFIG_OPENGL))
-CONFIG_FRAMEBUFFER=y
-CONFIG_PTIMER=y
-CONFIG_PFLASH_CFI01=y
-CONFIG_PFLASH_CFI02=y
-CONFIG_SD=y
index 27f5274244ae9771a5b36d93fd8d94a252a5aa2a..e17495e2a0b3ac90e5ab8520764c151d9189d2cc 100644 (file)
@@ -1,6 +1,6 @@
 # Default configuration for m68k-softmmu
 
-CONFIG_COLDFIRE=y
-CONFIG_PTIMER=y
+# Boards:
+#
 CONFIG_AN5206=y
 CONFIG_MCF5208=y
index 14837cf74ac0f7fe7fe8d1d55b3ac7ebd892f317..db8c6e4bba3461fd3d3ed42a9f459a2e8cd90c4a 100644 (file)
@@ -1,15 +1,7 @@
 # Default configuration for microblaze-softmmu
 
-CONFIG_PTIMER=y
-CONFIG_PFLASH_CFI01=y
-CONFIG_SERIAL=y
-CONFIG_XILINX=y
-CONFIG_XILINX_AXI=y
-CONFIG_XILINX_SPI=y
-CONFIG_XILINX_ETHLITE=y
-CONFIG_SSI=y
-CONFIG_SSI_M25P80=y
-CONFIG_XLNX_ZYNQMP=y
+# Boards:
+#
 CONFIG_PETALOGIX_S3ADSP1800=y
 CONFIG_PETALOGIX_ML605=y
 CONFIG_XLNX_ZYNQMP_PMU=y
index ded74980e1b7841f4d1b027263aa9f529a601985..0795d522dbf53065714deb6a7dc40e3eed950cc0 100644 (file)
@@ -1,10 +1,9 @@
 # Common mips*-softmmu CONFIG defines
 
-include pci.mak
-include sound.mak
-include usb.mak
+CONFIG_ISA_BUS=y
+CONFIG_PCI=y
+CONFIG_PCI_DEVICES=y
 CONFIG_ESP=y
-CONFIG_SCSI=y
 CONFIG_VGA_ISA=y
 CONFIG_VGA_ISA_MM=y
 CONFIG_VGA_CIRRUS=y
@@ -31,13 +30,12 @@ CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_I8259=y
 CONFIG_MC146818RTC=y
-CONFIG_ISA_TESTDEV=y
 CONFIG_EMPTY_SLOT=y
 CONFIG_MIPS_CPS=y
 CONFIG_MIPS_ITU=y
-CONFIG_I2C=y
 CONFIG_R4K=y
 CONFIG_MALTA=y
 CONFIG_MIPSSIM=y
 CONFIG_ACPI_SMBUS=y
 CONFIG_SMBUS_EEPROM=y
+CONFIG_TEST_DEVICES=y
index 9eb1208b5826a7ef12cffdbde01b599d003d39be..8b255efc5489ffe9ea4e328c96ff5d09a88c62dd 100644 (file)
@@ -10,6 +10,8 @@ CONFIG_JAZZ=y
 CONFIG_G364FB=y
 CONFIG_JAZZ_LED=y
 CONFIG_VT82C686=y
+CONFIG_AHCI=y
 CONFIG_MIPS_BOSTON=y
 CONFIG_FITLOADER=y
+CONFIG_PCI_EXPRESS=y
 CONFIG_PCI_EXPRESS_XILINX=y
index 17ba906dc2ffff4fdf67bfb88f2cb7d94e8f5bc5..bd50da3c58f7edc3ed0aeff3154a33cb7aa1c56a 100644 (file)
@@ -1,8 +1,5 @@
 # Default configuration for moxie-softmmu
 
-CONFIG_ISA_BUS=y
-CONFIG_MC146818RTC=y
-CONFIG_SERIAL=y
-CONFIG_SERIAL_ISA=y
-CONFIG_VGA=y
+# Boards:
+#
 CONFIG_MOXIESIM=y
index ab42d0fc280862fec288fd153f6a9d43eaf86a3a..e11dc549601edb1580cc32bccb51fe80e9047481 100644 (file)
@@ -1,7 +1,5 @@
 # Default configuration for nios2-softmmu
 
-CONFIG_NIOS2=y
-CONFIG_SERIAL=y
-CONFIG_PTIMER=y
-CONFIG_ALTERA_TIMER=y
+# Boards:
+#
 CONFIG_NIOS2_10M50=y
index 6a0f2ef6cf6aca4741e0ab8ba3c6dcfd9e65adcd..168101c39a548b1a9e83e43ac71edf31f91510aa 100644 (file)
@@ -1,6 +1,5 @@
 # Default configuration for or1k-softmmu
 
-CONFIG_SERIAL=y
-CONFIG_OPENCORES_ETH=y
-CONFIG_OMPIC=y
+# Boards:
+#
 CONFIG_OR1K_SIM=y
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
deleted file mode 100644 (file)
index 037636f..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-CONFIG_PCI=y
-# For now, CONFIG_IDE_CORE requires ISA, so we enable it here
-CONFIG_ISA_BUS=y
-CONFIG_VIRTIO_PCI=y
-include virtio.mak
-CONFIG_USB_UHCI=y
-CONFIG_USB_OHCI=y
-CONFIG_USB_EHCI=y
-CONFIG_USB_XHCI=y
-CONFIG_USB_XHCI_NEC=y
-CONFIG_NE2000_PCI=y
-CONFIG_EEPRO100_PCI=y
-CONFIG_PCNET_PCI=y
-CONFIG_PCNET_COMMON=y
-CONFIG_AC97=y
-CONFIG_HDA=y
-CONFIG_ES1370=y
-CONFIG_SCSI=y
-CONFIG_LSI_SCSI_PCI=y
-CONFIG_VMW_PVSCSI_SCSI_PCI=y
-CONFIG_MEGASAS_SCSI_PCI=y
-CONFIG_MPTSAS_SCSI_PCI=y
-CONFIG_RTL8139_PCI=y
-CONFIG_E1000_PCI=y
-CONFIG_E1000E_PCI_EXPRESS=y
-CONFIG_IDE_CORE=y
-CONFIG_IDE_QDEV=y
-CONFIG_IDE_PCI=y
-CONFIG_AHCI=y
-CONFIG_ESP=y
-CONFIG_ESP_PCI=y
-CONFIG_SERIAL=y
-CONFIG_SERIAL_ISA=y
-CONFIG_SERIAL_PCI=y
-CONFIG_CAN_BUS=y
-CONFIG_CAN_SJA1000=y
-CONFIG_CAN_PCI=y
-CONFIG_IPACK=y
-CONFIG_WDT_IB6300ESB=y
-CONFIG_PCI_TESTDEV=y
-CONFIG_NVME_PCI=y
-CONFIG_SD=y
-CONFIG_SDHCI=y
-CONFIG_EDU=y
-CONFIG_VGA=y
-CONFIG_VGA_PCI=y
-CONFIG_BOCHS_DISPLAY=y
-CONFIG_IVSHMEM_DEVICE=$(CONFIG_IVSHMEM)
-CONFIG_ROCKER=y
-CONFIG_VFIO=$(CONFIG_LINUX)
-CONFIG_VFIO_PCI=y
index 52acb7cf39e454895b7d96065b7dbaa8196e21e6..6ea36d40903619a03b8cd330f5b7177b4af70dc6 100644 (file)
@@ -1,77 +1,17 @@
 # Default configuration for ppc-softmmu
 
-include pci.mak
-include sound.mak
-include usb.mak
-
 # For embedded PPCs:
-CONFIG_PPC4XX=y
-CONFIG_M48T59=y
-CONFIG_SERIAL=y
-CONFIG_I8257=y
-CONFIG_OPENPIC=y
-CONFIG_PPCE500_PCI=y
-CONFIG_PFLASH_CFI01=y
-CONFIG_PFLASH_CFI02=y
-CONFIG_PTIMER=y
-CONFIG_I8259=y
-CONFIG_XILINX=y
-CONFIG_XILINX_ETHLITE=y
 CONFIG_E500=y
-CONFIG_OPENPIC_KVM=$(call land,$(CONFIG_E500),$(CONFIG_KVM))
-CONFIG_PLATFORM_BUS=y
-CONFIG_ETSEC=y
 CONFIG_PPC405=y
 CONFIG_PPC440=y
 CONFIG_VIRTEX=y
 
 # For Sam460ex
 CONFIG_SAM460EX=y
-CONFIG_USB_EHCI_SYSBUS=y
-CONFIG_SM501=y
-CONFIG_DDC=y
-CONFIG_IDE_SII3112=y
-CONFIG_I2C=y
-CONFIG_AT24C=y
-CONFIG_BITBANG_I2C=y
-CONFIG_M41T80=y
-CONFIG_VGA_CIRRUS=y
-CONFIG_SMBUS_EEPROM=y
 
 # For Macs
-CONFIG_ESCC=y
-CONFIG_MACIO=y
-CONFIG_MACIO_GPIO=y
-CONFIG_SUNGEM=y
-CONFIG_MOS6522=y
-CONFIG_CUDA=y
-CONFIG_ADB=y
-CONFIG_MAC_NVRAM=y
-CONFIG_MAC_DBDMA=y
-CONFIG_MAC_PMU=y
-CONFIG_HEATHROW_PIC=y
-CONFIG_GRACKLE_PCI=y
-CONFIG_UNIN_PCI=y
-CONFIG_DEC_PCI=y
-CONFIG_IDE_MACIO=y
 CONFIG_MAC_OLDWORLD=y
 CONFIG_MAC_NEWWORLD=y
 
 # For PReP
 CONFIG_PREP=y
-CONFIG_PREP_PCI=y
-CONFIG_SERIAL_ISA=y
-CONFIG_MC146818RTC=y
-CONFIG_ISA_TESTDEV=y
-CONFIG_RS6000_MC=y
-CONFIG_PARALLEL=y
-CONFIG_I82374=y
-CONFIG_I82378=y
-CONFIG_I8254=y
-CONFIG_PCKBD=y
-CONFIG_FDC=y
-CONFIG_NE2000_ISA=y
-CONFIG_PC87312=y
-CONFIG_PCSPK=y
-CONFIG_IDE_ISA=y
-CONFIG_CS4231A=y
index 7f34ad0528ed465c2de78f9685fced16b8314f94..cca52665d9077803fcee4330ae377e64df998c66 100644 (file)
@@ -5,19 +5,6 @@ include ppc-softmmu.mak
 
 # For PowerNV
 CONFIG_POWERNV=y
-CONFIG_IPMI=y
-CONFIG_IPMI_LOCAL=y
-CONFIG_IPMI_EXTERN=y
-CONFIG_ISA_IPMI_BT=y
 
 # For pSeries
 CONFIG_PSERIES=y
-CONFIG_VIRTIO_VGA=y
-CONFIG_XICS=$(CONFIG_PSERIES)
-CONFIG_XICS_SPAPR=$(CONFIG_PSERIES)
-CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM))
-CONFIG_XIVE=$(CONFIG_PSERIES)
-CONFIG_XIVE_SPAPR=$(CONFIG_PSERIES)
-CONFIG_MEM_DEVICE=y
-CONFIG_DIMM=y
-CONFIG_SPAPR_RNG=y
index 65337166e19de757658b053bc07cdcd68f6aff1c..1ae077ed877e64057b676afbbb20fe0c187f8f1c 100644 (file)
@@ -1,21 +1,12 @@
-# Default configuration for riscv-softmmu
+# Default configuration for riscv32-softmmu
 
-include pci.mak
-include usb.mak
-
-CONFIG_SERIAL=y
-CONFIG_VIRTIO_MMIO=y
-
-CONFIG_CADENCE=y
-
-CONFIG_PCI_EXPRESS_GENERIC_BRIDGE=y
-
-CONFIG_VGA=y
-CONFIG_VGA_PCI=y
+# Uncomment the following lines to disable these optional devices:
+#
+#CONFIG_PCI_DEVICES=n
 
+# Boards:
+#
 CONFIG_SPIKE=y
-CONFIG_HART=y
 CONFIG_SIFIVE_E=y
-CONFIG_SIFIVE=y
 CONFIG_SIFIVE_U=y
 CONFIG_RISCV_VIRT=y
index 65337166e19de757658b053bc07cdcd68f6aff1c..235c6f473f7cf3b9c4b349fceed3ea6f882bd6e8 100644 (file)
@@ -1,21 +1,3 @@
-# Default configuration for riscv-softmmu
+# Default configuration for riscv64-softmmu
 
-include pci.mak
-include usb.mak
-
-CONFIG_SERIAL=y
-CONFIG_VIRTIO_MMIO=y
-
-CONFIG_CADENCE=y
-
-CONFIG_PCI_EXPRESS_GENERIC_BRIDGE=y
-
-CONFIG_VGA=y
-CONFIG_VGA_PCI=y
-
-CONFIG_SPIKE=y
-CONFIG_HART=y
-CONFIG_SIFIVE_E=y
-CONFIG_SIFIVE=y
-CONFIG_SIFIVE_U=y
-CONFIG_RISCV_VIRT=y
+include riscv32-softmmu.mak
index 6f2c6cec18ae412e23013320fcb6e13ae46783b6..f2287a133f366f64ecdf7a25f24daab725f533cf 100644 (file)
@@ -1,12 +1,13 @@
-CONFIG_PCI=y
-CONFIG_VIRTIO_PCI=$(CONFIG_PCI)
-include virtio.mak
-CONFIG_SCLPCONSOLE=y
-CONFIG_TERMINAL3270=y
-CONFIG_S390_FLIC=y
-CONFIG_S390_FLIC_KVM=$(CONFIG_KVM)
-CONFIG_WDT_DIAG288=y
+# Default configuration for s390x-softmmu
+
+# Uncomment the following lines to disable these optional devices:
+#
+#CONFIG_TERMINAL3270=n
+#CONFIG_VFIO_AP=n
+#CONFIG_VFIO_CCW=n
+#CONFIG_VIRTIO_PCI=n
+#CONFIG_WDT_DIAG288=n
+
+# Boards:
+#
 CONFIG_S390_CCW_VIRTIO=y
-CONFIG_VFIO=$(CONFIG_LINUX)
-CONFIG_VFIO_CCW=y
-CONFIG_VFIO_AP=y
index 1fdb009151a88405cdac8945eb82b539ff0b44fe..565e8b0b5df697ed047fe4c577d8431743b28f07 100644 (file)
@@ -1,23 +1,11 @@
-# Default configuration for sh4-softmmu
+# Default configuration for sh4eb-softmmu
 
-include pci.mak
-include usb.mak
-CONFIG_SERIAL=y
-CONFIG_SERIAL_ISA=y
-CONFIG_PTIMER=y
-CONFIG_PFLASH_CFI02=y
-CONFIG_SH4=y
-CONFIG_IDE_MMIO=y
-CONFIG_SM501=y
-CONFIG_I2C=y
-CONFIG_DDC=y
-CONFIG_ISA_TESTDEV=y
-CONFIG_I82378=y
-CONFIG_I8259=y
-CONFIG_I8254=y
-CONFIG_PCSPK=y
-CONFIG_I82374=y
-CONFIG_I8257=y
-CONFIG_MC146818RTC=y
+# Uncomment the following lines to disable these optional devices:
+#
+#CONFIG_PCI_DEVICES=n
+#CONFIG_TEST_DEVICES=n
+
+# Boards:
+#
 CONFIG_R2D=y
 CONFIG_SHIX=y
index 3b550a5fe89b63c82b2fc5686ecc4271f82e707b..522a7a50fab12f8ef021946b24a58118cc966252 100644 (file)
@@ -1,23 +1,3 @@
 # Default configuration for sh4eb-softmmu
 
-include pci.mak
-include usb.mak
-CONFIG_SERIAL=y
-CONFIG_SERIAL_ISA=y
-CONFIG_PTIMER=y
-CONFIG_PFLASH_CFI02=y
-CONFIG_SH4=y
-CONFIG_IDE_MMIO=y
-CONFIG_SM501=y
-CONFIG_I2C=y
-CONFIG_DDC=y
-CONFIG_ISA_TESTDEV=y
-CONFIG_I82378=y
-CONFIG_I8259=y
-CONFIG_I8254=y
-CONFIG_PCSPK=y
-CONFIG_I82374=y
-CONFIG_I8257=y
-CONFIG_MC146818RTC=y
-CONFIG_R2D=y
-CONFIG_SHIX=y
+include sh4-softmmu.mak
diff --git a/default-configs/sound.mak b/default-configs/sound.mak
deleted file mode 100644 (file)
index 4f22c34..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG_SB16=y
-CONFIG_ADLIB=y
-CONFIG_GUS=y
-CONFIG_CS4231A=y
index 59a4a3d693ab1f1bc812ef63c2b87c8247e22f0f..ee85218115113561591b60d8051b5d14ce0beed7 100644 (file)
@@ -1,23 +1,11 @@
 # Default configuration for sparc-softmmu
 
-CONFIG_ISA_BUS=y
-CONFIG_ECC=y
-CONFIG_SCSI=y
-CONFIG_ESP=y
-CONFIG_ESCC=y
-CONFIG_M48T59=y
-CONFIG_PTIMER=y
-CONFIG_FDC=y
-CONFIG_EMPTY_SLOT=y
-CONFIG_PCNET_COMMON=y
-CONFIG_LANCE=y
-CONFIG_TCX=y
-CONFIG_CG3=y
-CONFIG_SLAVIO=y
-CONFIG_CS4231=y
-CONFIG_GRLIB=y
-CONFIG_STP2000=y
-CONFIG_ECCMEMCTL=y
+# Uncomment the following lines to disable these optional devices:
+#
+#CONFIG_TCX=n
+#CONFIG_CG3=n
 
+# Boards:
+#
 CONFIG_SUN4M=y
 CONFIG_LEON3=y
index 1fae4888dbe97f938d4019fe6d4ca0a22ac166a6..e50030a229cf7ce235789ec0df506f144cad16af 100644 (file)
@@ -1,21 +1,12 @@
 # Default configuration for sparc64-softmmu
 
-include pci.mak
-include usb.mak
-CONFIG_M48T59=y
-CONFIG_PTIMER=y
-CONFIG_SERIAL=y
-CONFIG_SERIAL_ISA=y
-CONFIG_PARALLEL=y
-CONFIG_PCKBD=y
-CONFIG_FDC=y
-CONFIG_IDE_ISA=y
-CONFIG_IDE_CMD646=y
-CONFIG_PCI_SABRE=y
-CONFIG_SIMBA=y
-CONFIG_SUNHME=y
-CONFIG_MC146818RTC=y
-CONFIG_ISA_TESTDEV=y
-CONFIG_SUN4V_RTC=y
+# Uncomment the following lines to disable these optional devices:
+#
+#CONFIG_PCI_DEVICES=n
+#CONFIG_SUNHME=n
+#CONFIG_TEST_DEVICES=n
+
+# Boards:
+#
 CONFIG_SUN4U=y
 CONFIG_NIAGARA=y
index 5f6c4a80471564f12a770effbad57c8ed58770ac..0bfce48c6da75ffd94ae44b6b1a9348269b8b9ff 100644 (file)
@@ -1,5 +1,5 @@
 # Default configuration for unicore32-softmmu
-CONFIG_ISA_BUS=y
+
+# Boards:
+#
 CONFIG_PUV3=y
-CONFIG_PTIMER=y
-CONFIG_PCKBD=y
diff --git a/default-configs/usb.mak b/default-configs/usb.mak
deleted file mode 100644 (file)
index e42cfea..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-CONFIG_USB=y
-CONFIG_USB_TABLET_WACOM=y
-CONFIG_USB_STORAGE_BOT=y
-CONFIG_USB_STORAGE_UAS=y
-CONFIG_USB_STORAGE_MTP=y
-CONFIG_SCSI=y
-CONFIG_USB_SMARTCARD=y
-CONFIG_USB_AUDIO=y
-CONFIG_USB_SERIAL=y
-CONFIG_USB_NETWORK=y
-CONFIG_USB_BLUETOOTH=y
diff --git a/default-configs/virtio.mak b/default-configs/virtio.mak
deleted file mode 100644 (file)
index b653aa0..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-CONFIG_VHOST_USER_SCSI=$(CONFIG_VHOST_USER)
-CONFIG_VHOST_USER_BLK=$(CONFIG_VHOST_USER)
-CONFIG_VIRTIO=y
-CONFIG_VIRTIO_9P=$(CONFIG_VIRTFS)
-CONFIG_VIRTIO_BALLOON=y
-CONFIG_VIRTIO_BLK=y
-CONFIG_VIRTIO_CRYPTO=y
-CONFIG_VIRTIO_GPU=y
-CONFIG_VIRTIO_INPUT=y
-CONFIG_VIRTIO_NET=y
-CONFIG_VIRTIO_RNG=y
-CONFIG_SCSI=y
-CONFIG_VIRTIO_SCSI=y
-CONFIG_VIRTIO_SERIAL=y
-CONFIG_VIRTIO_INPUT_HOST=$(CONFIG_LINUX)
index baf90ca162481a23aa7921cf1786c8e5a12e2b95..7e4d1cc0979c076e9f09d26aa81f3d451e1ed113 100644 (file)
@@ -1,8 +1,6 @@
 # Default configuration for Xtensa
 
-CONFIG_SERIAL=y
-CONFIG_OPENCORES_ETH=y
-CONFIG_PFLASH_CFI01=y
-
+# Boards:
+#
 CONFIG_XTENSA_SIM=y
-CONFIG_XTENSA_FPGA=y
+CONFIG_XTENSA_XTFPGA=y
index baf90ca162481a23aa7921cf1786c8e5a12e2b95..f7e48c750cda65fca0aef8d0c609733e8a026846 100644 (file)
@@ -1,8 +1,3 @@
 # Default configuration for Xtensa
 
-CONFIG_SERIAL=y
-CONFIG_OPENCORES_ETH=y
-CONFIG_PFLASH_CFI01=y
-
-CONFIG_XTENSA_SIM=y
-CONFIG_XTENSA_FPGA=y
+include xtensa-softmmu.mak
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644 (file)
index 0000000..befbcc6
--- /dev/null
@@ -0,0 +1,216 @@
+# -*- coding: utf-8 -*-
+#
+# QEMU documentation build configuration file, created by
+# sphinx-quickstart on Thu Jan 31 16:40:14 2019.
+#
+# This config file can be used in one of two ways:
+# (1) as a common config file which is included by the conf.py
+# for each of QEMU's manuals: in this case sphinx-build is run multiple
+# times, once per subdirectory.
+# (2) as a top level conf file which will result in building all
+# the manuals into a single document: in this case sphinx-build is
+# run once, on the top-level docs directory.
+#
+# QEMU's makefiles take option (1), which allows us to install
+# only the ones the user cares about (in particular we don't want
+# to ship the 'devel' manual to end-users).
+# Third-party sites such as readthedocs.org will take option (2).
+#
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import os
+import sys
+
+# The per-manual conf.py will set qemu_docdir for a single-manual build;
+# otherwise set it here if this is an entire-manual-set build.
+# This is always the absolute path of the docs/ directory in the source tree.
+try:
+    qemu_docdir
+except NameError:
+    qemu_docdir = os.path.abspath(".")
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use an absolute path starting from qemu_docdir.
+#
+# sys.path.insert(0, os.path.join(qemu_docdir, "my_subdir"))
+
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# 1.3 is where the 'alabaster' theme was shipped with Sphinx.
+needs_sphinx = '1.3'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'QEMU'
+copyright = u'2019, The QEMU Project Developers'
+author = u'The QEMU Project Developers'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+
+# Extract this information from the VERSION file, for the benefit of
+# standalone Sphinx runs as used by readthedocs.org. Builds run from
+# the Makefile will pass version and release on the sphinx-build
+# command line, which override this.
+try:
+    extracted_version = None
+    with open(os.path.join(qemu_docdir, '../VERSION')) as f:
+        extracted_version = f.readline().strip()
+except:
+    pass
+finally:
+    if extracted_version:
+        version = release = extracted_version
+    else:
+        version = release = "unknown version"
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+# Sphinx defaults to warning about use of :option: for options not defined
+# with "option::" in the document being processed. Turn that off.
+suppress_warnings = ["ref.option"]
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'alabaster'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+# We initialize this to empty here, so the per-manual conf.py can just
+# add individual key/value entries.
+html_theme_options = {
+}
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+# QEMU doesn't yet have any static files, so comment this out so we don't
+# get a warning about a missing directory.
+# If we do ever add this then it would probably be better to call the
+# subdirectory sphinx_static, as the Linux kernel does.
+# html_static_path = ['_static']
+
+# Custom sidebar templates, must be a dictionary that maps document names
+# to template names.
+#
+# This is required for the alabaster theme
+# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
+html_sidebars = {
+    '**': [
+        'about.html',
+        'navigation.html',
+        'searchbox.html',
+    ]
+}
+
+# Don't copy the rST source files to the HTML output directory,
+# and don't put links to the sources into the output HTML.
+html_copy_source = False
+
+# -- Options for HTMLHelp output ------------------------------------------
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'QEMUdoc'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+    # The paper size ('letterpaper' or 'a4paper').
+    #
+    # 'papersize': 'letterpaper',
+
+    # The font size ('10pt', '11pt' or '12pt').
+    #
+    # 'pointsize': '10pt',
+
+    # Additional stuff for the LaTeX preamble.
+    #
+    # 'preamble': '',
+
+    # Latex figure (float) alignment
+    #
+    # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+    (master_doc, 'QEMU.tex', u'QEMU Documentation',
+     u'The QEMU Project Developers', 'manual'),
+]
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    (master_doc, 'qemu', u'QEMU Documentation',
+     [author], 1)
+]
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+    (master_doc, 'QEMU', u'QEMU Documentation',
+     author, 'QEMU', 'One line description of project.',
+     'Miscellaneous'),
+]
+
+
+
index cfeb79f571113ffc06c32d89c0cfaa4a305ceccf..d0b06403f1958704e1b36a7e3606b1488966188b 100644 (file)
@@ -60,7 +60,7 @@ vCPU hotplug
     hot-plugged (no "qom-path" member).  From its output in step (3), we
     can see that ``IvyBridge-IBRS-x86_64-cpu`` is present in socket 0,
     while hot-plugging a CPU into socket 1 requires passing the listed
-    properties to QMP ``device_add``:
+    properties to QMP ``device_add``::
 
       (QEMU) device_add id=cpu-2 driver=IvyBridge-IBRS-x86_64-cpu socket-id=1 core-id=0 thread-id=0
       {
index f9fd27fab0c7293cf31d2eb0042ba9a2a7faad5d..addd274eebd9f0d75418cb2a7f4a3383e8d09ba0 100644 (file)
@@ -417,7 +417,6 @@ into each QEMU system and userspace emulator targets. They merely
 contain a long list of config variable definitions. For example,
 default-configs/x86_64-softmmu.mak has:
 
-  include pci.mak
   include sound.mak
   include usb.mak
   CONFIG_QXL=$(CONFIG_SPICE)
diff --git a/docs/devel/conf.py b/docs/devel/conf.py
new file mode 100644 (file)
index 0000000..7441f87
--- /dev/null
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+#
+# QEMU documentation build configuration file for the 'devel' manual.
+#
+# This includes the top level conf file and then makes any necessary tweaks.
+import sys
+import os
+
+qemu_docdir = os.path.abspath("..")
+parent_config = os.path.join(qemu_docdir, "conf.py")
+exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
+
+# This slightly misuses the 'description', but is the best way to get
+# the manual title to appear in the sidebar.
+html_theme_options['description'] = u'Developer''s Guide'
diff --git a/docs/devel/index.rst b/docs/devel/index.rst
new file mode 100644 (file)
index 0000000..6b11e49
--- /dev/null
@@ -0,0 +1,22 @@
+.. This is the top level page for the 'devel' manual.
+
+
+QEMU Developer's Guide
+======================
+
+This manual documents various parts of the internals of QEMU.
+You only need to read it if you are interested in reading or
+modifying QEMU's source code.
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   kconfig
+   loads-stores
+   memory
+   migration
+   stable-process
+   testing
+
diff --git a/docs/devel/kconfig.rst b/docs/devel/kconfig.rst
new file mode 100644 (file)
index 0000000..cce146f
--- /dev/null
@@ -0,0 +1,306 @@
+================
+QEMU and Kconfig
+================
+
+QEMU is a very versatile emulator; it can be built for a variety of
+targets, where each target can emulate various boards and at the same
+time different targets can share large amounts of code.  For example,
+a POWER and an x86 board can run the same code to emulate a PCI network
+card, even though the boards use different PCI host bridges, and they
+can run the same code to emulate a SCSI disk while using different
+SCSI adapters.  ARM, s390 and x86 boards can all present a virtio-blk
+disk to their guests, but with three different virtio guest interfaces.
+
+Each QEMU target enables a subset of the boards, devices and buses that
+are included in QEMU's source code.  As a result, each QEMU executable
+only links a small subset of the files that form QEMU's source code;
+anything that is not needed to support a particular target is culled.
+
+QEMU uses a simple domain-specific language to describe the dependencies
+between components.  This is useful for two reasons:
+
+* new targets and boards can be added without knowing in detail the
+  architecture of the hardware emulation subsystems.  Boards only have
+  to list the components they need, and the compiled executable will
+  include all the required dependencies and all the devices that the
+  user can add to that board;
+
+* users can easily build reduced versions of QEMU that support only a subset
+  of boards or devices.  For example, by default most targets will include
+  all emulated PCI devices that QEMU supports, but the build process is
+  configurable and it is easy to drop unnecessary (or otherwise unwanted)
+  code to make a leaner binary.
+
+This domain-specific language is based on the Kconfig language that
+originated in the Linux kernel, though it was heavily simplified and
+the handling of dependencies is stricter in QEMU.
+
+Unlike Linux, there is no user interface to edit the configuration, which
+is instead specified in per-target files under the ``default-configs/``
+directory of the QEMU source tree.  This is because, unlike Linux,
+configuration and dependencies can be treated as a black box when building
+QEMU; the default configuration that QEMU ships with should be okay in
+almost all cases.
+
+The Kconfig language
+--------------------
+
+Kconfig defines configurable components in files named ``hw/*/Kconfig``.
+Note that configurable components are _not_ visible in C code as preprocessor
+symbols; they are only visible in the Makefile.  Each configurable component
+defines a Makefile variable whose name starts with ``CONFIG_``.
+
+All elements have boolean (true/false) type; truth is written as ``y``, while
+falsehood is written ``n``.  They are defined in a Kconfig
+stanza like the following::
+
+      config ARM_VIRT
+         bool
+         imply PCI_DEVICES
+         imply VFIO_AMD_XGBE
+         imply VFIO_XGMAC
+         select A15MPCORE
+         select ACPI
+         select ARM_SMMUV3
+
+The ``config`` keyword introduces a new configuration element.  In the example
+above, Makefiles will have access to a variable named ``CONFIG_ARM_VIRT``,
+with value ``y`` or ``n`` (respectively for boolean true and false).
+
+Boolean expressions can be used within the language, whenever ``<expr>``
+is written in the remainder of this section.  The ``&&``, ``||`` and
+``!`` operators respectively denote conjunction (AND), disjunction (OR)
+and negation (NOT).
+
+The ``bool`` data type declaration is optional, but it is suggested to
+include it for clarity and future-proofing.  After ``bool`` the following
+directives can be included:
+
+**dependencies**: ``depends on <expr>``
+
+  This defines a dependency for this configurable element. Dependencies
+  evaluate an expression and force the value of the variable to false
+  if the expression is false.
+
+**reverse dependencies**: ``select <symbol> [if <expr>]``
+
+  While ``depends on`` can force a symbol to false, reverse dependencies can
+  be used to force another symbol to true.  In the following example,
+  ``CONFIG_BAZ`` will be true whenever ``CONFIG_FOO`` is true::
+
+    config FOO
+      select BAZ
+
+  The optional expression will prevent ``select`` from having any effect
+  unless it is true.
+
+  Note that unlike Linux's Kconfig implementation, QEMU will detect
+  contradictions between ``depends on`` and ``select`` statements and prevent
+  you from building such a configuration.
+
+**default value**: ``default <value> [if <expr>]``
+
+  Default values are assigned to the config symbol if no other value was
+  set by the user via ``default-configs/*.mak`` files, and only if
+  ``select`` or ``depends on`` directives do not force the value to true
+  or false respectively.  ``<value>`` can be ``y`` or ``n``; it cannot
+  be an arbitrary Boolean expression.  However, a condition for applying
+  the default value can be added with ``if``.
+
+  A configuration element can have any number of default values (usually,
+  if more than one default is present, they will have different
+  conditions). If multiple default values satisfy their condition,
+  only the first defined one is active.
+
+**reverse default** (weak reverse dependency): ``imply <symbol> [if <expr>]``
+
+  This is similar to ``select`` as it applies a lower limit of ``y``
+  to another symbol.  However, the lower limit is only a default
+  and the "implied" symbol's value may still be set to ``n`` from a
+  ``default-configs/*.mak`` files.  The following two examples are
+  equivalent::
+
+    config FOO
+      bool
+      imply BAZ
+
+    config BAZ
+      bool
+      default y if FOO
+
+  The next section explains where to use ``imply`` or ``default y``.
+
+Guidelines for writing Kconfig files
+------------------------------------
+
+Configurable elements in QEMU fall under five broad groups.  Each group
+declares its dependencies in different ways:
+
+**subsystems**, of which **buses** are a special case
+
+  Example::
+
+    config SCSI
+      bool
+
+  Subsystems always default to false (they have no ``default`` directive)
+  and are never visible in ``default-configs/*.mak`` files.  It's
+  up to other symbols to ``select`` whatever subsystems they require.
+
+  They sometimes have ``select`` directives to bring in other required
+  subsystems or buses.  For example, ``AUX`` (the DisplayPort auxiliary
+  channel "bus") selects ``I2C`` because it can act as an I2C master too.
+
+**devices**
+
+  Example::
+
+    config MEGASAS_SCSI_PCI
+      bool
+      default y if PCI_DEVICES
+      depends on PCI
+      select SCSI
+
+  Devices are the most complex of the five.  They can have a variety
+  of directives that cooperate so that a default configuration includes
+  all the devices that can be accessed from QEMU.
+
+  Devices *depend on* the bus that they lie on, for example a PCI
+  device would specify ``depends on PCI``.  An MMIO device will likely
+  have no ``depends on`` directive.  Devices also *select* the buses
+  that the device provides, for example a SCSI adapter would specify
+  ``select SCSI``.  Finally, devices are usually ``default y`` if and
+  only if they have at least one ``depends on``; the default could be
+  conditional on a device group.
+
+  Devices also select any optional subsystem that they use; for example
+  a video card might specify ``select EDID`` if it needs to build EDID
+  information and publish it to the guest.
+
+**device groups**
+
+  Example::
+
+    config PCI_DEVICES
+      bool
+
+  Device groups provide a convenient mechanism to enable/disable many
+  devices in one go.  This is useful when a set of devices is likely to
+  be enabled/disabled by several targets.  Device groups usually need
+  no directive and are not used in the Makefile either; they only appear
+  as conditions for ``default y`` directives.
+
+  QEMU currently has two device groups, ``PCI_DEVICES`` and
+  ``TEST_DEVICES``.  PCI devices usually have a ``default y if
+  PCI_DEVICES`` directive rather than just ``default y``.  This lets
+  some boards (notably s390) easily support a subset of PCI devices,
+  for example only VFIO (passthrough) and virtio-pci devices.
+  ``TEST_DEVICES`` instead is used for devices that are rarely used on
+  production virtual machines, but provide useful hooks to test QEMU
+  or KVM.
+
+**boards**
+
+  Example::
+
+    config SUN4M
+      bool
+      imply TCX
+      imply CG3
+      select CS4231
+      select ECCMEMCTL
+      select EMPTY_SLOT
+      select ESCC
+      select ESP
+      select FDC
+      select SLAVIO
+      select LANCE
+      select M48T59
+      select STP2000
+
+  Boards specify their constituent devices using ``imply`` and ``select``
+  directives.  A device should be listed under ``select`` if the board
+  cannot be started at all without it.  It should be listed under
+  ``imply`` if (depending on the QEMU command line) the board may or
+  may not be started without it.  Boards also default to false; they are
+  enabled by the ``default-configs/*.mak`` for the target they apply to.
+
+**internal elements**
+
+  Example::
+
+    config ECCMEMCTL
+      bool
+      select ECC
+
+  Internal elements group code that is useful in several boards or
+  devices.  They are usually enabled with ``select`` and in turn select
+  other elements; they are never visible in ``default-configs/*.mak``
+  files, and often not even in the Makefile.
+
+Writing and modifying default configurations
+--------------------------------------------
+
+In addition to the Kconfig files under hw/, each target also includes
+a file called ``default-configs/TARGETNAME-softmmu.mak``.  These files
+initialize some Kconfig variables to non-default values and provide the
+starting point to turn on devices and subsystems.
+
+A file in ``default-configs/`` looks like the following example::
+
+    # Default configuration for alpha-softmmu
+
+    # Uncomment the following lines to disable these optional devices:
+    #
+    #CONFIG_PCI_DEVICES=n
+    #CONFIG_TEST_DEVICES=n
+
+    # Boards:
+    #
+    CONFIG_DP264=y
+
+The first part, consisting of commented-out ``=n`` assignments, tells
+the user which devices or device groups are implied by the boards.
+The second part, consisting of ``=y`` assignments, tells the user which
+boards are supported by the target.  The user will typically modify
+the default configuration by uncommenting lines in the first group,
+or commenting out lines in the second group.
+
+It is also possible to run QEMU's configure script with the
+``--with-default-devices`` option.  When this is done, everything defaults
+to ``n`` unless it is ``select``ed or explicitly switched on in the
+``.mak`` files.  In other words, ``default`` and ``imply`` directives
+are disabled.  When QEMU is built with this option, the user will probably
+want to change some lines in the first group, for example like this::
+
+   CONFIG_PCI_DEVICES=y
+   #CONFIG_TEST_DEVICES=n
+
+and/or pick a subset of the devices in those device groups.  Right now
+there is no single place that lists all the optional devices for
+``CONFIG_PCI_DEVICES`` and ``CONFIG_TEST_DEVICES``.  In the future,
+we expect that ``.mak`` files will be automatically generated, so that
+they will include all these symbols and some help text on what they do.
+
+``Kconfig.host``
+----------------
+
+In some special cases, a configurable element depends on host features
+that are detected by QEMU's configure script; for example some devices
+depend on the availability of KVM or on the presence of a library on
+the host.
+
+These symbols should be listed in ``Kconfig.host`` like this::
+
+    config KVM
+      bool
+
+and also listed as follows in the top-level Makefile's ``MINIKCONF_ARGS``
+variable::
+
+    MINIKCONF_ARGS = \
+      $@ $*-config.devices.mak.d $< $(MINIKCONF_INPUTS) \
+      CONFIG_KVM=$(CONFIG_KVM) \
+      CONFIG_SPICE=$(CONFIG_SPICE) \
+      CONFIG_TPM=$(CONFIG_TPM) \
+      ...
diff --git a/docs/devel/memory.rst b/docs/devel/memory.rst
new file mode 100644 (file)
index 0000000..b6a4c37
--- /dev/null
@@ -0,0 +1,363 @@
+==============
+The memory API
+==============
+
+The memory API models the memory and I/O buses and controllers of a QEMU
+machine.  It attempts to allow modelling of:
+
+- ordinary RAM
+- memory-mapped I/O (MMIO)
+- memory controllers that can dynamically reroute physical memory regions
+  to different destinations
+
+The memory model provides support for
+
+- tracking RAM changes by the guest
+- setting up coalesced memory for kvm
+- setting up ioeventfd regions for kvm
+
+Memory is modelled as an acyclic graph of MemoryRegion objects.  Sinks
+(leaves) are RAM and MMIO regions, while other nodes represent
+buses, memory controllers, and memory regions that have been rerouted.
+
+In addition to MemoryRegion objects, the memory API provides AddressSpace
+objects for every root and possibly for intermediate MemoryRegions too.
+These represent memory as seen from the CPU or a device's viewpoint.
+
+Types of regions
+----------------
+
+There are multiple types of memory regions (all represented by a single C type
+MemoryRegion):
+
+- RAM: a RAM region is simply a range of host memory that can be made available
+  to the guest.
+  You typically initialize these with memory_region_init_ram().  Some special
+  purposes require the variants memory_region_init_resizeable_ram(),
+  memory_region_init_ram_from_file(), or memory_region_init_ram_ptr().
+
+- MMIO: a range of guest memory that is implemented by host callbacks;
+  each read or write causes a callback to be called on the host.
+  You initialize these with memory_region_init_io(), passing it a
+  MemoryRegionOps structure describing the callbacks.
+
+- ROM: a ROM memory region works like RAM for reads (directly accessing
+  a region of host memory), and forbids writes. You initialize these with
+  memory_region_init_rom().
+
+- ROM device: a ROM device memory region works like RAM for reads
+  (directly accessing a region of host memory), but like MMIO for
+  writes (invoking a callback).  You initialize these with
+  memory_region_init_rom_device().
+
+- IOMMU region: an IOMMU region translates addresses of accesses made to it
+  and forwards them to some other target memory region.  As the name suggests,
+  these are only needed for modelling an IOMMU, not for simple devices.
+  You initialize these with memory_region_init_iommu().
+
+- container: a container simply includes other memory regions, each at
+  a different offset.  Containers are useful for grouping several regions
+  into one unit.  For example, a PCI BAR may be composed of a RAM region
+  and an MMIO region.
+
+  A container's subregions are usually non-overlapping.  In some cases it is
+  useful to have overlapping regions; for example a memory controller that
+  can overlay a subregion of RAM with MMIO or ROM, or a PCI controller
+  that does not prevent card from claiming overlapping BARs.
+
+  You initialize a pure container with memory_region_init().
+
+- alias: a subsection of another region.  Aliases allow a region to be
+  split apart into discontiguous regions.  Examples of uses are memory banks
+  used when the guest address space is smaller than the amount of RAM
+  addressed, or a memory controller that splits main memory to expose a "PCI
+  hole".  Aliases may point to any type of region, including other aliases,
+  but an alias may not point back to itself, directly or indirectly.
+  You initialize these with memory_region_init_alias().
+
+- reservation region: a reservation region is primarily for debugging.
+  It claims I/O space that is not supposed to be handled by QEMU itself.
+  The typical use is to track parts of the address space which will be
+  handled by the host kernel when KVM is enabled.  You initialize these
+  by passing a NULL callback parameter to memory_region_init_io().
+
+It is valid to add subregions to a region which is not a pure container
+(that is, to an MMIO, RAM or ROM region). This means that the region
+will act like a container, except that any addresses within the container's
+region which are not claimed by any subregion are handled by the
+container itself (ie by its MMIO callbacks or RAM backing). However
+it is generally possible to achieve the same effect with a pure container
+one of whose subregions is a low priority "background" region covering
+the whole address range; this is often clearer and is preferred.
+Subregions cannot be added to an alias region.
+
+Migration
+---------
+
+Where the memory region is backed by host memory (RAM, ROM and
+ROM device memory region types), this host memory needs to be
+copied to the destination on migration. These APIs which allocate
+the host memory for you will also register the memory so it is
+migrated:
+
+- memory_region_init_ram()
+- memory_region_init_rom()
+- memory_region_init_rom_device()
+
+For most devices and boards this is the correct thing. If you
+have a special case where you need to manage the migration of
+the backing memory yourself, you can call the functions:
+
+- memory_region_init_ram_nomigrate()
+- memory_region_init_rom_nomigrate()
+- memory_region_init_rom_device_nomigrate()
+
+which only initialize the MemoryRegion and leave handling
+migration to the caller.
+
+The functions:
+
+- memory_region_init_resizeable_ram()
+- memory_region_init_ram_from_file()
+- memory_region_init_ram_from_fd()
+- memory_region_init_ram_ptr()
+- memory_region_init_ram_device_ptr()
+
+are for special cases only, and so they do not automatically
+register the backing memory for migration; the caller must
+manage migration if necessary.
+
+Region names
+------------
+
+Regions are assigned names by the constructor.  For most regions these are
+only used for debugging purposes, but RAM regions also use the name to identify
+live migration sections.  This means that RAM region names need to have ABI
+stability.
+
+Region lifecycle
+----------------
+
+A region is created by one of the memory_region_init*() functions and
+attached to an object, which acts as its owner or parent.  QEMU ensures
+that the owner object remains alive as long as the region is visible to
+the guest, or as long as the region is in use by a virtual CPU or another
+device.  For example, the owner object will not die between an
+address_space_map operation and the corresponding address_space_unmap.
+
+After creation, a region can be added to an address space or a
+container with memory_region_add_subregion(), and removed using
+memory_region_del_subregion().
+
+Various region attributes (read-only, dirty logging, coalesced mmio,
+ioeventfd) can be changed during the region lifecycle.  They take effect
+as soon as the region is made visible.  This can be immediately, later,
+or never.
+
+Destruction of a memory region happens automatically when the owner
+object dies.
+
+If however the memory region is part of a dynamically allocated data
+structure, you should call object_unparent() to destroy the memory region
+before the data structure is freed.  For an example see VFIOMSIXInfo
+and VFIOQuirk in hw/vfio/pci.c.
+
+You must not destroy a memory region as long as it may be in use by a
+device or CPU.  In order to do this, as a general rule do not create or
+destroy memory regions dynamically during a device's lifetime, and only
+call object_unparent() in the memory region owner's instance_finalize
+callback.  The dynamically allocated data structure that contains the
+memory region then should obviously be freed in the instance_finalize
+callback as well.
+
+If you break this rule, the following situation can happen:
+
+- the memory region's owner had a reference taken via memory_region_ref
+  (for example by address_space_map)
+
+- the region is unparented, and has no owner anymore
+
+- when address_space_unmap is called, the reference to the memory region's
+  owner is leaked.
+
+
+There is an exception to the above rule: it is okay to call
+object_unparent at any time for an alias or a container region.  It is
+therefore also okay to create or destroy alias and container regions
+dynamically during a device's lifetime.
+
+This exceptional usage is valid because aliases and containers only help
+QEMU building the guest's memory map; they are never accessed directly.
+memory_region_ref and memory_region_unref are never called on aliases
+or containers, and the above situation then cannot happen.  Exploiting
+this exception is rarely necessary, and therefore it is discouraged,
+but nevertheless it is used in a few places.
+
+For regions that "have no owner" (NULL is passed at creation time), the
+machine object is actually used as the owner.  Since instance_finalize is
+never called for the machine object, you must never call object_unparent
+on regions that have no owner, unless they are aliases or containers.
+
+
+Overlapping regions and priority
+--------------------------------
+Usually, regions may not overlap each other; a memory address decodes into
+exactly one target.  In some cases it is useful to allow regions to overlap,
+and sometimes to control which of an overlapping regions is visible to the
+guest.  This is done with memory_region_add_subregion_overlap(), which
+allows the region to overlap any other region in the same container, and
+specifies a priority that allows the core to decide which of two regions at
+the same address are visible (highest wins).
+Priority values are signed, and the default value is zero. This means that
+you can use memory_region_add_subregion_overlap() both to specify a region
+that must sit 'above' any others (with a positive priority) and also a
+background region that sits 'below' others (with a negative priority).
+
+If the higher priority region in an overlap is a container or alias, then
+the lower priority region will appear in any "holes" that the higher priority
+region has left by not mapping subregions to that area of its address range.
+(This applies recursively -- if the subregions are themselves containers or
+aliases that leave holes then the lower priority region will appear in these
+holes too.)
+
+For example, suppose we have a container A of size 0x8000 with two subregions
+B and C. B is a container mapped at 0x2000, size 0x4000, priority 2; C is
+an MMIO region mapped at 0x0, size 0x6000, priority 1. B currently has two
+of its own subregions: D of size 0x1000 at offset 0 and E of size 0x1000 at
+offset 0x2000. As a diagram::
+
+        0      1000   2000   3000   4000   5000   6000   7000   8000
+        |------|------|------|------|------|------|------|------|
+  A:    [                                                      ]
+  C:    [CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC]
+  B:                  [                          ]
+  D:                  [DDDDD]
+  E:                                [EEEEE]
+
+The regions that will be seen within this address range then are::
+
+  [CCCCCCCCCCCC][DDDDD][CCCCC][EEEEE][CCCCC]
+
+Since B has higher priority than C, its subregions appear in the flat map
+even where they overlap with C. In ranges where B has not mapped anything
+C's region appears.
+
+If B had provided its own MMIO operations (ie it was not a pure container)
+then these would be used for any addresses in its range not handled by
+D or E, and the result would be::
+
+  [CCCCCCCCCCCC][DDDDD][BBBBB][EEEEE][BBBBB]
+
+Priority values are local to a container, because the priorities of two
+regions are only compared when they are both children of the same container.
+This means that the device in charge of the container (typically modelling
+a bus or a memory controller) can use them to manage the interaction of
+its child regions without any side effects on other parts of the system.
+In the example above, the priorities of D and E are unimportant because
+they do not overlap each other. It is the relative priority of B and C
+that causes D and E to appear on top of C: D and E's priorities are never
+compared against the priority of C.
+
+Visibility
+----------
+The memory core uses the following rules to select a memory region when the
+guest accesses an address:
+
+- all direct subregions of the root region are matched against the address, in
+  descending priority order
+
+  - if the address lies outside the region offset/size, the subregion is
+    discarded
+  - if the subregion is a leaf (RAM or MMIO), the search terminates, returning
+    this leaf region
+  - if the subregion is a container, the same algorithm is used within the
+    subregion (after the address is adjusted by the subregion offset)
+  - if the subregion is an alias, the search is continued at the alias target
+    (after the address is adjusted by the subregion offset and alias offset)
+  - if a recursive search within a container or alias subregion does not
+    find a match (because of a "hole" in the container's coverage of its
+    address range), then if this is a container with its own MMIO or RAM
+    backing the search terminates, returning the container itself. Otherwise
+    we continue with the next subregion in priority order
+
+- if none of the subregions match the address then the search terminates
+  with no match found
+
+Example memory map
+------------------
+
+::
+
+  system_memory: container@0-2^48-1
+   |
+   +---- lomem: alias@0-0xdfffffff ---> #ram (0-0xdfffffff)
+   |
+   +---- himem: alias@0x100000000-0x11fffffff ---> #ram (0xe0000000-0xffffffff)
+   |
+   +---- vga-window: alias@0xa0000-0xbffff ---> #pci (0xa0000-0xbffff)
+   |      (prio 1)
+   |
+   +---- pci-hole: alias@0xe0000000-0xffffffff ---> #pci (0xe0000000-0xffffffff)
+
+  pci (0-2^32-1)
+   |
+   +--- vga-area: container@0xa0000-0xbffff
+   |      |
+   |      +--- alias@0x00000-0x7fff  ---> #vram (0x010000-0x017fff)
+   |      |
+   |      +--- alias@0x08000-0xffff  ---> #vram (0x020000-0x027fff)
+   |
+   +---- vram: ram@0xe1000000-0xe1ffffff
+   |
+   +---- vga-mmio: mmio@0xe2000000-0xe200ffff
+
+  ram: ram@0x00000000-0xffffffff
+
+This is a (simplified) PC memory map. The 4GB RAM block is mapped into the
+system address space via two aliases: "lomem" is a 1:1 mapping of the first
+3.5GB; "himem" maps the last 0.5GB at address 4GB.  This leaves 0.5GB for the
+so-called PCI hole, that allows a 32-bit PCI bus to exist in a system with
+4GB of memory.
+
+The memory controller diverts addresses in the range 640K-768K to the PCI
+address space.  This is modelled using the "vga-window" alias, mapped at a
+higher priority so it obscures the RAM at the same addresses.  The vga window
+can be removed by programming the memory controller; this is modelled by
+removing the alias and exposing the RAM underneath.
+
+The pci address space is not a direct child of the system address space, since
+we only want parts of it to be visible (we accomplish this using aliases).
+It has two subregions: vga-area models the legacy vga window and is occupied
+by two 32K memory banks pointing at two sections of the framebuffer.
+In addition the vram is mapped as a BAR at address e1000000, and an additional
+BAR containing MMIO registers is mapped after it.
+
+Note that if the guest maps a BAR outside the PCI hole, it would not be
+visible as the pci-hole alias clips it to a 0.5GB range.
+
+MMIO Operations
+---------------
+
+MMIO regions are provided with ->read() and ->write() callbacks,
+which are sufficient for most devices. Some devices change behaviour
+based on the attributes used for the memory transaction, or need
+to be able to respond that the access should provoke a bus error
+rather than completing successfully; those devices can use the
+->read_with_attrs() and ->write_with_attrs() callbacks instead.
+
+In addition various constraints can be supplied to control how these
+callbacks are called:
+
+- .valid.min_access_size, .valid.max_access_size define the access sizes
+  (in bytes) which the device accepts; accesses outside this range will
+  have device and bus specific behaviour (ignored, or machine check)
+- .valid.unaligned specifies that the *device being modelled* supports
+  unaligned accesses; if false, unaligned accesses will invoke the
+  appropriate bus or CPU specific behaviour.
+- .impl.min_access_size, .impl.max_access_size define the access sizes
+  (in bytes) supported by the *implementation*; other access sizes will be
+  emulated using the ones available.  For example a 4-byte write will be
+  emulated using four 1-byte writes, if .impl.max_access_size = 1.
+- .impl.unaligned specifies that the *implementation* supports unaligned
+  accesses; if false, unaligned accesses will be emulated by two aligned
+  accesses.
diff --git a/docs/devel/memory.txt b/docs/devel/memory.txt
deleted file mode 100644 (file)
index 42577e1..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-The memory API
-==============
-
-The memory API models the memory and I/O buses and controllers of a QEMU
-machine.  It attempts to allow modelling of:
-
- - ordinary RAM
- - memory-mapped I/O (MMIO)
- - memory controllers that can dynamically reroute physical memory regions
-   to different destinations
-
-The memory model provides support for
-
- - tracking RAM changes by the guest
- - setting up coalesced memory for kvm
- - setting up ioeventfd regions for kvm
-
-Memory is modelled as an acyclic graph of MemoryRegion objects.  Sinks
-(leaves) are RAM and MMIO regions, while other nodes represent
-buses, memory controllers, and memory regions that have been rerouted.
-
-In addition to MemoryRegion objects, the memory API provides AddressSpace
-objects for every root and possibly for intermediate MemoryRegions too.
-These represent memory as seen from the CPU or a device's viewpoint.
-
-Types of regions
-----------------
-
-There are multiple types of memory regions (all represented by a single C type
-MemoryRegion):
-
-- RAM: a RAM region is simply a range of host memory that can be made available
-  to the guest.
-  You typically initialize these with memory_region_init_ram().  Some special
-  purposes require the variants memory_region_init_resizeable_ram(),
-  memory_region_init_ram_from_file(), or memory_region_init_ram_ptr().
-
-- MMIO: a range of guest memory that is implemented by host callbacks;
-  each read or write causes a callback to be called on the host.
-  You initialize these with memory_region_init_io(), passing it a
-  MemoryRegionOps structure describing the callbacks.
-
-- ROM: a ROM memory region works like RAM for reads (directly accessing
-  a region of host memory), and forbids writes. You initialize these with
-  memory_region_init_rom().
-
-- ROM device: a ROM device memory region works like RAM for reads
-  (directly accessing a region of host memory), but like MMIO for
-  writes (invoking a callback).  You initialize these with
-  memory_region_init_rom_device().
-
-- IOMMU region: an IOMMU region translates addresses of accesses made to it
-  and forwards them to some other target memory region.  As the name suggests,
-  these are only needed for modelling an IOMMU, not for simple devices.
-  You initialize these with memory_region_init_iommu().
-
-- container: a container simply includes other memory regions, each at
-  a different offset.  Containers are useful for grouping several regions
-  into one unit.  For example, a PCI BAR may be composed of a RAM region
-  and an MMIO region.
-
-  A container's subregions are usually non-overlapping.  In some cases it is
-  useful to have overlapping regions; for example a memory controller that
-  can overlay a subregion of RAM with MMIO or ROM, or a PCI controller
-  that does not prevent card from claiming overlapping BARs.
-
-  You initialize a pure container with memory_region_init().
-
-- alias: a subsection of another region.  Aliases allow a region to be
-  split apart into discontiguous regions.  Examples of uses are memory banks
-  used when the guest address space is smaller than the amount of RAM
-  addressed, or a memory controller that splits main memory to expose a "PCI
-  hole".  Aliases may point to any type of region, including other aliases,
-  but an alias may not point back to itself, directly or indirectly.
-  You initialize these with memory_region_init_alias().
-
-- reservation region: a reservation region is primarily for debugging.
-  It claims I/O space that is not supposed to be handled by QEMU itself.
-  The typical use is to track parts of the address space which will be
-  handled by the host kernel when KVM is enabled.  You initialize these
-  by passing a NULL callback parameter to memory_region_init_io().
-
-It is valid to add subregions to a region which is not a pure container
-(that is, to an MMIO, RAM or ROM region). This means that the region
-will act like a container, except that any addresses within the container's
-region which are not claimed by any subregion are handled by the
-container itself (ie by its MMIO callbacks or RAM backing). However
-it is generally possible to achieve the same effect with a pure container
-one of whose subregions is a low priority "background" region covering
-the whole address range; this is often clearer and is preferred.
-Subregions cannot be added to an alias region.
-
-Migration
----------
-
-Where the memory region is backed by host memory (RAM, ROM and
-ROM device memory region types), this host memory needs to be
-copied to the destination on migration. These APIs which allocate
-the host memory for you will also register the memory so it is
-migrated:
- - memory_region_init_ram()
- - memory_region_init_rom()
- - memory_region_init_rom_device()
-
-For most devices and boards this is the correct thing. If you
-have a special case where you need to manage the migration of
-the backing memory yourself, you can call the functions:
- - memory_region_init_ram_nomigrate()
- - memory_region_init_rom_nomigrate()
- - memory_region_init_rom_device_nomigrate()
-which only initialize the MemoryRegion and leave handling
-migration to the caller.
-
-The functions:
- - memory_region_init_resizeable_ram()
- - memory_region_init_ram_from_file()
- - memory_region_init_ram_from_fd()
- - memory_region_init_ram_ptr()
- - memory_region_init_ram_device_ptr()
-are for special cases only, and so they do not automatically
-register the backing memory for migration; the caller must
-manage migration if necessary.
-
-Region names
-------------
-
-Regions are assigned names by the constructor.  For most regions these are
-only used for debugging purposes, but RAM regions also use the name to identify
-live migration sections.  This means that RAM region names need to have ABI
-stability.
-
-Region lifecycle
-----------------
-
-A region is created by one of the memory_region_init*() functions and
-attached to an object, which acts as its owner or parent.  QEMU ensures
-that the owner object remains alive as long as the region is visible to
-the guest, or as long as the region is in use by a virtual CPU or another
-device.  For example, the owner object will not die between an
-address_space_map operation and the corresponding address_space_unmap.
-
-After creation, a region can be added to an address space or a
-container with memory_region_add_subregion(), and removed using
-memory_region_del_subregion().
-
-Various region attributes (read-only, dirty logging, coalesced mmio,
-ioeventfd) can be changed during the region lifecycle.  They take effect
-as soon as the region is made visible.  This can be immediately, later,
-or never.
-
-Destruction of a memory region happens automatically when the owner
-object dies.
-
-If however the memory region is part of a dynamically allocated data
-structure, you should call object_unparent() to destroy the memory region
-before the data structure is freed.  For an example see VFIOMSIXInfo
-and VFIOQuirk in hw/vfio/pci.c.
-
-You must not destroy a memory region as long as it may be in use by a
-device or CPU.  In order to do this, as a general rule do not create or
-destroy memory regions dynamically during a device's lifetime, and only
-call object_unparent() in the memory region owner's instance_finalize
-callback.  The dynamically allocated data structure that contains the
-memory region then should obviously be freed in the instance_finalize
-callback as well.
-
-If you break this rule, the following situation can happen:
-
-- the memory region's owner had a reference taken via memory_region_ref
-  (for example by address_space_map)
-
-- the region is unparented, and has no owner anymore
-
-- when address_space_unmap is called, the reference to the memory region's
-  owner is leaked.
-
-
-There is an exception to the above rule: it is okay to call
-object_unparent at any time for an alias or a container region.  It is
-therefore also okay to create or destroy alias and container regions
-dynamically during a device's lifetime.
-
-This exceptional usage is valid because aliases and containers only help
-QEMU building the guest's memory map; they are never accessed directly.
-memory_region_ref and memory_region_unref are never called on aliases
-or containers, and the above situation then cannot happen.  Exploiting
-this exception is rarely necessary, and therefore it is discouraged,
-but nevertheless it is used in a few places.
-
-For regions that "have no owner" (NULL is passed at creation time), the
-machine object is actually used as the owner.  Since instance_finalize is
-never called for the machine object, you must never call object_unparent
-on regions that have no owner, unless they are aliases or containers.
-
-
-Overlapping regions and priority
---------------------------------
-Usually, regions may not overlap each other; a memory address decodes into
-exactly one target.  In some cases it is useful to allow regions to overlap,
-and sometimes to control which of an overlapping regions is visible to the
-guest.  This is done with memory_region_add_subregion_overlap(), which
-allows the region to overlap any other region in the same container, and
-specifies a priority that allows the core to decide which of two regions at
-the same address are visible (highest wins).
-Priority values are signed, and the default value is zero. This means that
-you can use memory_region_add_subregion_overlap() both to specify a region
-that must sit 'above' any others (with a positive priority) and also a
-background region that sits 'below' others (with a negative priority).
-
-If the higher priority region in an overlap is a container or alias, then
-the lower priority region will appear in any "holes" that the higher priority
-region has left by not mapping subregions to that area of its address range.
-(This applies recursively -- if the subregions are themselves containers or
-aliases that leave holes then the lower priority region will appear in these
-holes too.)
-
-For example, suppose we have a container A of size 0x8000 with two subregions
-B and C. B is a container mapped at 0x2000, size 0x4000, priority 2; C is
-an MMIO region mapped at 0x0, size 0x6000, priority 1. B currently has two
-of its own subregions: D of size 0x1000 at offset 0 and E of size 0x1000 at
-offset 0x2000. As a diagram:
-
-        0      1000   2000   3000   4000   5000   6000   7000   8000
-        |------|------|------|------|------|------|------|------|
-  A:    [                                                      ]
-  C:    [CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC]
-  B:                  [                          ]
-  D:                  [DDDDD]
-  E:                                [EEEEE]
-
-The regions that will be seen within this address range then are:
-        [CCCCCCCCCCCC][DDDDD][CCCCC][EEEEE][CCCCC]
-
-Since B has higher priority than C, its subregions appear in the flat map
-even where they overlap with C. In ranges where B has not mapped anything
-C's region appears.
-
-If B had provided its own MMIO operations (ie it was not a pure container)
-then these would be used for any addresses in its range not handled by
-D or E, and the result would be:
-        [CCCCCCCCCCCC][DDDDD][BBBBB][EEEEE][BBBBB]
-
-Priority values are local to a container, because the priorities of two
-regions are only compared when they are both children of the same container.
-This means that the device in charge of the container (typically modelling
-a bus or a memory controller) can use them to manage the interaction of
-its child regions without any side effects on other parts of the system.
-In the example above, the priorities of D and E are unimportant because
-they do not overlap each other. It is the relative priority of B and C
-that causes D and E to appear on top of C: D and E's priorities are never
-compared against the priority of C.
-
-Visibility
-----------
-The memory core uses the following rules to select a memory region when the
-guest accesses an address:
-
-- all direct subregions of the root region are matched against the address, in
-  descending priority order
-  - if the address lies outside the region offset/size, the subregion is
-    discarded
-  - if the subregion is a leaf (RAM or MMIO), the search terminates, returning
-    this leaf region
-  - if the subregion is a container, the same algorithm is used within the
-    subregion (after the address is adjusted by the subregion offset)
-  - if the subregion is an alias, the search is continued at the alias target
-    (after the address is adjusted by the subregion offset and alias offset)
-  - if a recursive search within a container or alias subregion does not
-    find a match (because of a "hole" in the container's coverage of its
-    address range), then if this is a container with its own MMIO or RAM
-    backing the search terminates, returning the container itself. Otherwise
-    we continue with the next subregion in priority order
-- if none of the subregions match the address then the search terminates
-  with no match found
-
-Example memory map
-------------------
-
-system_memory: container@0-2^48-1
- |
- +---- lomem: alias@0-0xdfffffff ---> #ram (0-0xdfffffff)
- |
- +---- himem: alias@0x100000000-0x11fffffff ---> #ram (0xe0000000-0xffffffff)
- |
- +---- vga-window: alias@0xa0000-0xbffff ---> #pci (0xa0000-0xbffff)
- |      (prio 1)
- |
- +---- pci-hole: alias@0xe0000000-0xffffffff ---> #pci (0xe0000000-0xffffffff)
-
-pci (0-2^32-1)
- |
- +--- vga-area: container@0xa0000-0xbffff
- |      |
- |      +--- alias@0x00000-0x7fff  ---> #vram (0x010000-0x017fff)
- |      |
- |      +--- alias@0x08000-0xffff  ---> #vram (0x020000-0x027fff)
- |
- +---- vram: ram@0xe1000000-0xe1ffffff
- |
- +---- vga-mmio: mmio@0xe2000000-0xe200ffff
-
-ram: ram@0x00000000-0xffffffff
-
-This is a (simplified) PC memory map. The 4GB RAM block is mapped into the
-system address space via two aliases: "lomem" is a 1:1 mapping of the first
-3.5GB; "himem" maps the last 0.5GB at address 4GB.  This leaves 0.5GB for the
-so-called PCI hole, that allows a 32-bit PCI bus to exist in a system with
-4GB of memory.
-
-The memory controller diverts addresses in the range 640K-768K to the PCI
-address space.  This is modelled using the "vga-window" alias, mapped at a
-higher priority so it obscures the RAM at the same addresses.  The vga window
-can be removed by programming the memory controller; this is modelled by
-removing the alias and exposing the RAM underneath.
-
-The pci address space is not a direct child of the system address space, since
-we only want parts of it to be visible (we accomplish this using aliases).
-It has two subregions: vga-area models the legacy vga window and is occupied
-by two 32K memory banks pointing at two sections of the framebuffer.
-In addition the vram is mapped as a BAR at address e1000000, and an additional
-BAR containing MMIO registers is mapped after it.
-
-Note that if the guest maps a BAR outside the PCI hole, it would not be
-visible as the pci-hole alias clips it to a 0.5GB range.
-
-MMIO Operations
----------------
-
-MMIO regions are provided with ->read() and ->write() callbacks,
-which are sufficient for most devices. Some devices change behaviour
-based on the attributes used for the memory transaction, or need
-to be able to respond that the access should provoke a bus error
-rather than completing successfully; those devices can use the
-->read_with_attrs() and ->write_with_attrs() callbacks instead.
-
-In addition various constraints can be supplied to control how these
-callbacks are called:
-
- - .valid.min_access_size, .valid.max_access_size define the access sizes
-   (in bytes) which the device accepts; accesses outside this range will
-   have device and bus specific behaviour (ignored, or machine check)
- - .valid.unaligned specifies that the *device being modelled* supports
-    unaligned accesses; if false, unaligned accesses will invoke the
-    appropriate bus or CPU specific behaviour.
- - .impl.min_access_size, .impl.max_access_size define the access sizes
-   (in bytes) supported by the *implementation*; other access sizes will be
-   emulated using the ones available.  For example a 4-byte write will be
-   emulated using four 1-byte writes, if .impl.max_access_size = 1.
- - .impl.unaligned specifies that the *implementation* supports unaligned
-   accesses; if false, unaligned accesses will be emulated by two aligned
-   accesses.
index 135743a2bf218401d66cba534d303d174aabe5cd..60f897d915f41ea5c5a8186bae89ca3205a50319 100644 (file)
@@ -600,7 +600,6 @@ the ``avocado_qemu.Test`` class.  Here's a simple usage example:
 
   class Version(Test):
       """
-      :avocado: enable
       :avocado: tags=quick
       """
       def test_qmp_human_info_version(self):
@@ -634,7 +633,46 @@ instance, available at ``self.vm``.  Because many tests will tweak the
 QEMU command line, launching the QEMUMachine (by using ``self.vm.launch()``)
 is left to the test writer.
 
-At test "tear down", ``avocado_qemu.Test`` handles the QEMUMachine
+The base test class has also support for tests with more than one
+QEMUMachine. The way to get machines is through the ``self.get_vm()``
+method which will return a QEMUMachine instance. The ``self.get_vm()``
+method accepts arguments that will be passed to the QEMUMachine creation
+and also an optional `name` attribute so you can identify a specific
+machine and get it more than once through the tests methods. A simple
+and hypothetical example follows:
+
+.. code::
+
+  from avocado_qemu import Test
+
+
+  class MultipleMachines(Test):
+      """
+      :avocado: enable
+      """
+      def test_multiple_machines(self):
+          first_machine = self.get_vm()
+          second_machine = self.get_vm()
+          self.get_vm(name='third_machine').launch()
+
+          first_machine.launch()
+          second_machine.launch()
+
+          first_res = first_machine.command(
+              'human-monitor-command',
+              command_line='info version')
+
+          second_res = second_machine.command(
+              'human-monitor-command',
+              command_line='info version')
+
+          third_res = self.get_vm(name='third_machine').command(
+              'human-monitor-command',
+              command_line='info version')
+
+          self.assertEquals(first_res, second_res, third_res)
+
+At test "tear down", ``avocado_qemu.Test`` handles all the QEMUMachines
 shutdown.
 
 QEMUMachine
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644 (file)
index 0000000..3690955
--- /dev/null
@@ -0,0 +1,15 @@
+.. QEMU documentation master file, created by
+   sphinx-quickstart on Thu Jan 31 16:40:14 2019.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Welcome to QEMU's documentation!
+================================
+
+.. toctree::
+   :maxdepth: 2
+   :caption: Contents:
+
+   interop/index
+   devel/index
+
diff --git a/docs/interop/conf.py b/docs/interop/conf.py
new file mode 100644 (file)
index 0000000..cf3c69d
--- /dev/null
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+#
+# QEMU documentation build configuration file for the 'interop' manual.
+#
+# This includes the top level conf file and then makes any necessary tweaks.
+import sys
+import os
+
+qemu_docdir = os.path.abspath("..")
+parent_config = os.path.join(qemu_docdir, "conf.py")
+exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
+
+# This slightly misuses the 'description', but is the best way to get
+# the manual title to appear in the sidebar.
+html_theme_options['description'] = u'System Emulation Management and Interoperability Guide'
diff --git a/docs/interop/index.rst b/docs/interop/index.rst
new file mode 100644 (file)
index 0000000..2df977d
--- /dev/null
@@ -0,0 +1,18 @@
+.. This is the top level page for the 'interop' manual.
+
+
+QEMU System Emulation Management and Interoperability Guide
+===========================================================
+
+This manual contains documents and specifications that are useful
+for making QEMU interoperate with other software.
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   bitmaps
+   live-block-operations
+   pr-helper
+
diff --git a/hw/9pfs/Kconfig b/hw/9pfs/Kconfig
new file mode 100644 (file)
index 0000000..8c5032c
--- /dev/null
@@ -0,0 +1,4 @@
+config VIRTIO_9P
+    bool
+    default y
+    depends on VIRTFS && VIRTIO
index 8ac04962bd135f751f2ac98aab1b2070b7953c9e..70ded6fd8fbf4e490124e00321544a614674e8fb 100644 (file)
@@ -1,11 +1,9 @@
-ifeq ($(call lor,$(CONFIG_VIRTIO_9P),$(CONFIG_XEN)),y)
 common-obj-y  = 9p.o 9p-util.o
 common-obj-y += 9p-local.o 9p-xattr.o
 common-obj-y += 9p-xattr-user.o 9p-posix-acl.o
 common-obj-y += coth.o cofs.o codir.o cofile.o
 common-obj-y += coxattr.o 9p-synth.o
 common-obj-y += 9p-proxy.o
-endif
 
 common-obj-$(CONFIG_XEN) += xen-9p-backend.o
 obj-$(CONFIG_VIRTIO_9P) += virtio-9p-device.o
diff --git a/hw/Kconfig b/hw/Kconfig
new file mode 100644 (file)
index 0000000..d5ecd02
--- /dev/null
@@ -0,0 +1,73 @@
+# devices Kconfig
+source 9pfs/Kconfig
+source acpi/Kconfig
+source adc/Kconfig
+source audio/Kconfig
+source block/Kconfig
+source bt/Kconfig
+source char/Kconfig
+source core/Kconfig
+source display/Kconfig
+source dma/Kconfig
+source gpio/Kconfig
+source hyperv/Kconfig
+source i2c/Kconfig
+source ide/Kconfig
+source input/Kconfig
+source intc/Kconfig
+source ipack/Kconfig
+source ipmi/Kconfig
+source isa/Kconfig
+source mem/Kconfig
+source misc/Kconfig
+source net/Kconfig
+source nvram/Kconfig
+source pci-bridge/Kconfig
+source pci-host/Kconfig
+source pcmcia/Kconfig
+source pci/Kconfig
+source scsi/Kconfig
+source sd/Kconfig
+source smbios/Kconfig
+source ssi/Kconfig
+source timer/Kconfig
+source tpm/Kconfig
+source usb/Kconfig
+source virtio/Kconfig
+source vfio/Kconfig
+source watchdog/Kconfig
+
+# arch Kconfig
+source arm/Kconfig
+source alpha/Kconfig
+source cris/Kconfig
+source hppa/Kconfig
+source i386/Kconfig
+source lm32/Kconfig
+source m68k/Kconfig
+source microblaze/Kconfig
+source mips/Kconfig
+source moxie/Kconfig
+source nios2/Kconfig
+source openrisc/Kconfig
+source ppc/Kconfig
+source riscv/Kconfig
+source s390x/Kconfig
+source sh4/Kconfig
+source sparc/Kconfig
+source sparc64/Kconfig
+source tricore/Kconfig
+source unicore32/Kconfig
+source xtensa/Kconfig
+
+# Symbols used by multiple targets
+config TEST_DEVICES
+    bool
+
+config XILINX
+    bool
+    select PTIMER # for hw/timer/xilinx_timer.c
+
+config XILINX_AXI
+    bool
+    select PTIMER # for hw/dma/xilinx_axidma.c
index e2fcd6aafc19a1efcaa1ef1ba3268b086d5403a0..82aa7fab8e42caf409001c1316c0712a0f1aaa99 100644 (file)
@@ -1,4 +1,4 @@
-devices-dirs-$(call land,$(CONFIG_VIRTFS),$(call lor,$(CONFIG_VIRTIO),$(CONFIG_XEN))) += 9pfs/
+devices-dirs-$(call lor,$(CONFIG_VIRTIO_9P),$(call land,$(CONFIG_VIRTFS),$(CONFIG_XEN))) += 9pfs/
 devices-dirs-$(CONFIG_SOFTMMU) += acpi/
 devices-dirs-$(CONFIG_SOFTMMU) += adc/
 devices-dirs-$(CONFIG_SOFTMMU) += audio/
@@ -10,7 +10,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += display/
 devices-dirs-$(CONFIG_SOFTMMU) += dma/
 devices-dirs-$(CONFIG_SOFTMMU) += gpio/
 devices-dirs-$(CONFIG_HYPERV) += hyperv/
-devices-dirs-$(CONFIG_SOFTMMU) += i2c/
+devices-dirs-$(CONFIG_I2C) += i2c/
 devices-dirs-$(CONFIG_SOFTMMU) += ide/
 devices-dirs-$(CONFIG_SOFTMMU) += input/
 devices-dirs-$(CONFIG_SOFTMMU) += intc/
diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig
new file mode 100644 (file)
index 0000000..eca3bee
--- /dev/null
@@ -0,0 +1,29 @@
+config ACPI
+    bool
+
+config ACPI_X86
+    bool
+    select ACPI
+    select ACPI_NVDIMM
+    select ACPI_CPU_HOTPLUG
+    select ACPI_MEMORY_HOTPLUG
+
+config ACPI_X86_ICH
+    bool
+    select ACPI_X86
+
+config ACPI_CPU_HOTPLUG
+    bool
+
+config ACPI_MEMORY_HOTPLUG
+    bool
+    select MEM_DEVICE
+
+config ACPI_NVDIMM
+    bool
+    depends on ACPI
+
+config ACPI_VMGENID
+    bool
+    default y
+    depends on PC
diff --git a/hw/adc/Kconfig b/hw/adc/Kconfig
new file mode 100644 (file)
index 0000000..25d2229
--- /dev/null
@@ -0,0 +1,2 @@
+config STM32F2XX_ADC
+    bool
diff --git a/hw/alpha/Kconfig b/hw/alpha/Kconfig
new file mode 100644 (file)
index 0000000..22cefd9
--- /dev/null
@@ -0,0 +1,12 @@
+config DP264
+    bool
+    imply PCI_DEVICES
+    imply TEST_DEVICES
+    select I82374
+    select I8254
+    select I8259
+    select IDE_CMD646
+    select MC146818RTC
+    select PCI
+    select PCKBD
+    select SMC37C669
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
new file mode 100644 (file)
index 0000000..d298fbd
--- /dev/null
@@ -0,0 +1,124 @@
+config ARM_VIRT
+    bool
+    imply VFIO_PLATFORM
+
+config DIGIC
+    bool
+    select PTIMER
+
+config EXYNOS4
+    bool
+    select PTIMER
+
+config HIGHBANK
+    bool
+
+config INTEGRATOR
+    bool
+
+config MAINSTONE
+    bool
+
+config MUSICPAL
+    bool
+    select PTIMER
+
+config NETDUINO2
+    bool
+
+config NSERIES
+    bool
+
+config OMAP
+    bool
+
+config PXA2XX
+    bool
+
+config REALVIEW
+    bool
+
+config STELLARIS
+    bool
+
+config STRONGARM
+    bool
+
+config VERSATILE
+    bool
+
+config ZYNQ
+    bool
+
+config ARM_V7M
+    bool
+
+config ALLWINNER_A10
+    bool
+
+config RASPI
+    bool
+
+config STM32F205_SOC
+    bool
+
+config XLNX_ZYNQMP_ARM
+    bool
+
+config XLNX_VERSAL
+    bool
+
+config FSL_IMX25
+    bool
+
+config FSL_IMX31
+    bool
+
+config FSL_IMX6
+    bool
+
+config ASPEED_SOC
+    bool
+
+config MPS2
+    bool
+
+config FSL_IMX7
+    bool
+
+config ARM_SMMUV3
+    bool
+
+config FSL_IMX6UL
+    bool
+
+config NRF51_SOC
+    bool
+
+config MSF2
+    bool
+    select PTIMER
+
+config ZAURUS
+    bool
+
+config A9MPCORE
+    bool
+
+config A15MPCORE
+    bool
+
+config ARM11MPCORE
+    bool
+
+config ARMSSE
+    bool
+
+config ARMSSE_CPUID
+    bool
+
+config ARMSSE_MHU
+    bool
+
+config MUSCA
+    bool
diff --git a/hw/audio/Kconfig b/hw/audio/Kconfig
new file mode 100644 (file)
index 0000000..e9c6fed
--- /dev/null
@@ -0,0 +1,52 @@
+config SB16
+    bool
+    default y
+    depends on ISA_BUS
+
+config ES1370
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+
+config AC97
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+
+config ADLIB
+    bool
+    default y
+    depends on ISA_BUS
+
+config GUS
+    bool
+    default y
+    depends on ISA_BUS
+
+config CS4231A
+    bool
+    default y
+    depends on ISA_BUS
+
+config HDA
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+
+config PCSPK
+    bool
+    default y
+    depends on I8254
+
+config WM8750
+    bool
+    depends on I2C
+
+config PL041
+    bool
+
+config CS4231
+    bool
+
+config MARVELL_88W8618
+    bool
diff --git a/hw/block/Kconfig b/hw/block/Kconfig
new file mode 100644 (file)
index 0000000..df96dc5
--- /dev/null
@@ -0,0 +1,39 @@
+config FDC
+    bool
+    # FIXME: there is no separate file for the MMIO floppy disk controller, so
+    # select ISA_BUS here instead of polluting each board that requires one
+    select ISA_BUS
+
+config SSI_M25P80
+    bool
+
+config NAND
+    bool
+
+config PFLASH_CFI01
+    bool
+
+config PFLASH_CFI02
+    bool
+
+config ECC
+    bool
+
+config ONENAND
+    bool
+
+config NVME_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+
+config VIRTIO_BLK
+    bool
+    default y
+    depends on VIRTIO
+
+config VHOST_USER_BLK
+    bool
+    # Only PCI devices are provided for now
+    default y if VIRTIO_PCI
+    depends on VIRTIO && VHOST_USER && LINUX
index e206b8e7123bae61cd61c9037bb9c3a42fb2fe7e..f5f643f0cc06ba73962e3233a4bd32fa04cae406 100644 (file)
@@ -12,5 +12,6 @@ common-obj-$(CONFIG_NVME_PCI) += nvme.o
 obj-$(CONFIG_SH4) += tc58128.o
 
 obj-$(CONFIG_VIRTIO_BLK) += virtio-blk.o
-obj-$(CONFIG_VIRTIO_BLK) += dataplane/
 obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk.o
+
+obj-y += dataplane/
index c6c68dbc00b7f8461afc03545c088b3f39a7fc65..0c5270268e8a92515dca7958feb3650be80c9b99 100644 (file)
@@ -1,2 +1,2 @@
-obj-y += virtio-blk.o
+obj-$(CONFIG_VIRTIO_BLK) += virtio-blk.o
 obj-$(CONFIG_XEN) += xen-block.o
diff --git a/hw/bt/Kconfig b/hw/bt/Kconfig
new file mode 100644 (file)
index 0000000..554a9ee
--- /dev/null
@@ -0,0 +1,2 @@
+config BLUETOOTH
+    bool
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
new file mode 100644 (file)
index 0000000..6360c9f
--- /dev/null
@@ -0,0 +1,42 @@
+config ESCC
+    bool
+
+config PARALLEL
+    bool
+    default y
+    depends on ISA_BUS
+
+config PL011
+    bool
+
+config SERIAL
+    bool
+
+config SERIAL_ISA
+    bool
+    default y
+    depends on ISA_BUS
+    select SERIAL
+
+config SERIAL_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select SERIAL
+
+config VIRTIO_SERIAL
+    bool
+    default y
+    depends on VIRTIO
+
+config STM32F2XX_USART
+    bool
+
+config CMSDK_APB_UART
+    bool
+
+config SCLPCONSOLE
+    bool
+
+config TERMINAL3270
+    bool
diff --git a/hw/core/Kconfig b/hw/core/Kconfig
new file mode 100644 (file)
index 0000000..c2a1ae8
--- /dev/null
@@ -0,0 +1,11 @@
+config EMPTY_SLOT
+    bool
+
+config PTIMER
+    bool
+
+config FITLOADER
+    bool
+
+config PLATFORM_BUS
+    bool
diff --git a/hw/cpu/Kconfig b/hw/cpu/Kconfig
new file mode 100644 (file)
index 0000000..1767d02
--- /dev/null
@@ -0,0 +1,8 @@
+config ARM11MPCORE
+    bool
+
+config A9MPCORE
+    bool
+
+config A15MPCORE
+    bool
diff --git a/hw/cris/Kconfig b/hw/cris/Kconfig
new file mode 100644 (file)
index 0000000..884ad2c
--- /dev/null
@@ -0,0 +1,9 @@
+config AXIS
+    bool
+    select ETRAXFS
+    select PFLASH_CFI02
+    select NAND
+
+config ETRAXFS
+   bool
+   select PTIMER
diff --git a/hw/display/Kconfig b/hw/display/Kconfig
new file mode 100644 (file)
index 0000000..a96ea76
--- /dev/null
@@ -0,0 +1,108 @@
+config EDID
+    bool
+
+config FW_CFG_DMA
+    bool
+
+config ADS7846
+    bool
+
+config VGA_CIRRUS
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select VGA
+
+config G364FB
+    bool
+
+config JAZZ_LED
+    bool
+
+config PL110
+    bool
+
+config SII9022
+    bool
+    depends on I2C
+
+config SSD0303
+    bool
+    depends on I2C
+
+config SSD0323
+    bool
+
+config VGA_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select VGA
+    select EDID
+
+config VGA_ISA
+    bool
+    depends on ISA_BUS
+    select VGA
+
+config VGA_ISA_MM
+    bool
+    select VGA
+
+config VMWARE_VGA
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select VGA
+
+config BOCHS_DISPLAY
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select VGA
+    select EDID
+
+config BLIZZARD
+    bool
+
+config FRAMEBUFFER
+    bool
+
+config MILKYMIST_TMU2
+    bool
+    depends on OPENGL && X11
+
+config SM501
+    bool
+    select I2C
+    select DDC
+    select SERIAL
+
+config TCX
+    bool
+
+config CG3
+    bool
+
+config VGA
+    bool
+
+config QXL
+    bool
+    depends on SPICE && PCI
+    select VGA
+
+config VIRTIO_GPU
+    bool
+    default y
+    depends on VIRTIO
+    select EDID
+
+config VIRTIO_VGA
+    bool
+    default y if PCI_DEVICES
+    depends on VIRTIO_PCI
+    select VGA
+
+config DPCD
+    bool
index 7c4ae9a0fd0ac815e24842826f62c39a2e99e92e..576fca4eb6a3322d949ead3e4f787b98362c7e82 100644 (file)
@@ -1,4 +1,4 @@
-common-obj-y += edid-generate.o
+common-obj-$(CONFIG_EDID) += edid-generate.o edid-region.o
 
 common-obj-$(CONFIG_FW_CFG_DMA) += ramfb.o
 common-obj-$(CONFIG_FW_CFG_DMA) += ramfb-standalone.o
@@ -15,12 +15,10 @@ common-obj-$(CONFIG_SSD0323) += ssd0323.o
 common-obj-$(CONFIG_XEN) += xenfb.o
 
 common-obj-$(CONFIG_VGA_PCI) += vga-pci.o
-common-obj-$(CONFIG_VGA_PCI) += edid-region.o
 common-obj-$(CONFIG_VGA_ISA) += vga-isa.o
 common-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
 common-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
 common-obj-$(CONFIG_BOCHS_DISPLAY) += bochs-display.o
-common-obj-$(CONFIG_BOCHS_DISPLAY) += edid-region.o
 
 common-obj-$(CONFIG_BLIZZARD) += blizzard.o
 common-obj-$(CONFIG_EXYNOS4) += exynos4210_fimd.o
diff --git a/hw/dma/Kconfig b/hw/dma/Kconfig
new file mode 100644 (file)
index 0000000..751dec5
--- /dev/null
@@ -0,0 +1,21 @@
+config RC4030
+    bool
+
+config PL080
+    bool
+
+config PL330
+    bool
+
+config I82374
+    bool
+    select I8257
+
+config I8257
+    bool
+
+config ZYNQ_DEVCFG
+    bool
+
+config STP2000
+    bool
diff --git a/hw/gpio/Kconfig b/hw/gpio/Kconfig
new file mode 100644 (file)
index 0000000..9227cb5
--- /dev/null
@@ -0,0 +1,9 @@
+config MAX7310
+    bool
+    depends on I2C
+
+config PL061
+    bool
+
+config GPIO_KEY
+    bool
diff --git a/hw/hppa/Kconfig b/hw/hppa/Kconfig
new file mode 100644 (file)
index 0000000..2d9b072
--- /dev/null
@@ -0,0 +1,10 @@
+config DINO
+    bool
+    imply PCI_DEVICES
+    select PCI
+    select SERIAL
+    select ISA_BUS
+    select I8259
+    select IDE_CMD646
+    select MC146818RTC
+    select LSI_SCSI_PCI
diff --git a/hw/hyperv/Kconfig b/hw/hyperv/Kconfig
new file mode 100644 (file)
index 0000000..a1fa8ff
--- /dev/null
@@ -0,0 +1,8 @@
+config HYPERV
+    bool
+    depends on KVM
+
+config HYPERV_TESTDEV
+    bool
+    default y if TEST_DEVICES
+    depends on HYPERV
diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig
new file mode 100644 (file)
index 0000000..ef1caa6
--- /dev/null
@@ -0,0 +1,27 @@
+config I2C
+    bool
+
+config SMBUS_EEPROM
+    bool
+    depends on I2C
+
+config DDC
+    bool
+    depends on I2C
+    select EDID
+
+config VERSATILE_I2C
+    bool
+    select I2C
+
+config ACPI_SMBUS
+    bool
+    select I2C
+
+config BITBANG_I2C
+    bool
+    select I2C
+
+config IMX_I2C
+    bool
+    select I2C
index 9205cbee16c7691b142510717b1cd6817315a443..2a3c106551e10b0faff1ecc563070a154963e257 100644 (file)
@@ -2,7 +2,7 @@ common-obj-$(CONFIG_I2C) += core.o smbus_slave.o smbus_master.o
 common-obj-$(CONFIG_SMBUS_EEPROM) += smbus_eeprom.o
 common-obj-$(CONFIG_DDC) += i2c-ddc.o
 common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
-common-obj-$(CONFIG_ACPI_X86) += smbus_ich9.o
+common-obj-$(CONFIG_ACPI_X86_ICH) += smbus_ich9.o
 common-obj-$(CONFIG_ACPI_SMBUS) += pm_smbus.o
 common-obj-$(CONFIG_BITBANG_I2C) += bitbang_i2c.o
 common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o
diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
new file mode 100644 (file)
index 0000000..78fd703
--- /dev/null
@@ -0,0 +1,99 @@
+config SEV
+    bool
+    depends on KVM
+
+config PC
+    bool
+    imply APPLESMC
+    imply HYPERV
+    imply ISA_IPMI_KCS
+    imply ISA_IPMI_BT
+    imply ISA_DEBUG
+    imply PCI_DEVICES
+    imply PVPANIC
+    imply QXL
+    imply SEV
+    imply SGA
+    imply TEST_DEVICES
+    imply TPM_CRB
+    imply TPM_TIS
+    select FDC
+    select I8259
+    select I8254
+    select PCKBD
+    select PCSPK
+    select I82374
+    select I8257
+    select MC146818RTC
+    # Needed by the board code:
+    select PARALLEL
+    # For ACPI builder:
+    select SERIAL_ISA
+    select ACPI_VMGENID
+
+config PC_PCI
+    bool
+    select APIC
+    select IOAPIC
+    select APM
+    select PC
+
+config PC_ACPI
+    bool
+    select ACPI_X86
+    select ACPI_CPU_HOTPLUG
+    select ACPI_MEMORY_HOTPLUG
+    select SMBUS_EEPROM
+    select PFLASH_CFI01
+    depends on ACPI_SMBUS
+
+config I440FX
+    bool
+    select PC_PCI
+    select PC_ACPI
+    select ACPI_SMBUS
+    select PCI_PIIX
+    select IDE_PIIX
+    select DIMM
+    select SMBIOS
+    select VMPORT
+    select VMMOUSE
+    select FW_CFG_DMA
+
+config ISAPC
+    bool
+    select ISA_BUS
+    select PC
+    select IDE_ISA
+    select VGA_ISA
+    # FIXME: it is in the same file as i440fx, and does not compile
+    # if separated
+    depends on I440FX
+
+config Q35
+    bool
+    imply VTD
+    imply AMD_IOMMU
+    select PC_PCI
+    select PC_ACPI
+    select PCI_EXPRESS_Q35
+    select LPC_ICH9
+    select AHCI
+    select DIMM
+    select SMBIOS
+    select VMPORT
+    select VMMOUSE
+    select FW_CFG_DMA
+
+config VTD
+    bool
+
+config AMD_IOMMU
+    bool
+
+config VMPORT
+    bool
+
+config VMMOUSE
+    bool
+    depends on VMPORT
index 3de7ca2bb9e5346c869ece4000fbd5791698436f..27248a0777c3fbd9a5cc9ac9f40bbff80741c6e9 100644 (file)
@@ -4,8 +4,9 @@ obj-y += pc.o
 obj-$(CONFIG_I440FX) += pc_piix.o
 obj-$(CONFIG_Q35) += pc_q35.o
 obj-y += pc_sysfw.o
-obj-$(CONFIG_VTD) += x86-iommu.o intel_iommu.o
-obj-$(CONFIG_AMD_IOMMU) += x86-iommu.o amd_iommu.o
+obj-y += x86-iommu.o
+obj-$(CONFIG_VTD) += intel_iommu.o
+obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o
 obj-$(CONFIG_XEN) += ../xenpv/ xen/
 obj-$(CONFIG_VMPORT) += vmport.o
 obj-$(CONFIG_VMMOUSE) += vmmouse.o
diff --git a/hw/ide/Kconfig b/hw/ide/Kconfig
new file mode 100644 (file)
index 0000000..ab47b6a
--- /dev/null
@@ -0,0 +1,54 @@
+config IDE_CORE
+    bool
+
+config IDE_QDEV
+    bool
+    select IDE_CORE
+
+config IDE_PCI
+    bool
+    depends on PCI
+    select IDE_CORE
+
+config IDE_ISA
+    bool
+    depends on ISA_BUS
+    select IDE_QDEV
+
+config IDE_PIIX
+    bool
+    select IDE_PCI
+    select IDE_QDEV
+
+config IDE_CMD646
+    bool
+    select IDE_PCI
+    select IDE_QDEV
+
+config IDE_MACIO
+    bool
+    select IDE_QDEV
+
+config IDE_MMIO
+    bool
+    select IDE_QDEV
+
+config IDE_VIA
+    bool
+    select IDE_PCI
+    select IDE_QDEV
+
+config MICRODRIVE
+    bool
+    select IDE_QDEV
+
+config AHCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select IDE_QDEV
+
+config IDE_SII3112
+    bool
+    select IDE_PCI
+    select IDE_QDEV
diff --git a/hw/input/Kconfig b/hw/input/Kconfig
new file mode 100644 (file)
index 0000000..e2e66f0
--- /dev/null
@@ -0,0 +1,33 @@
+config ADB
+    bool
+
+config LM832X
+    bool
+    depends on I2C
+
+config PCKBD
+    bool
+    default y
+    depends on ISA_BUS
+
+config PL050
+    bool
+
+config STELLARIS_INPUT
+    bool
+
+config TSC2005
+    bool
+
+config VIRTIO_INPUT
+    bool
+    default y
+    depends on VIRTIO
+
+config VIRTIO_INPUT_HOST
+    bool
+    default y
+    depends on VIRTIO && LINUX
+
+config TSC210X
+    bool
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
new file mode 100644 (file)
index 0000000..de10a6b
--- /dev/null
@@ -0,0 +1,57 @@
+config HEATHROW_PIC
+    bool
+
+config I8259
+    bool
+
+config PL190
+    bool
+
+config IOAPIC
+    bool
+
+config ARM_GIC
+    bool
+
+config OPENPIC
+    bool
+
+config APIC
+    bool
+
+config ARM_GIC_KVM
+    bool
+    default y
+    depends on ARM_GIC && KVM
+
+config OPENPIC_KVM
+    bool
+    default y
+    depends on OPENPIC && KVM
+
+config XICS
+    bool
+    depends on POWERNV || PSERIES
+
+config XICS_SPAPR
+    bool
+    select XICS
+
+config XICS_KVM
+    bool
+    default y
+    depends on XICS && KVM
+
+config ALLWINNER_A10_PIC
+    bool
+
+config S390_FLIC
+    bool
+
+config S390_FLIC_KVM
+    bool
+    default y
+    depends on S390_FLIC && KVM
+
+config OMPIC
+    bool
diff --git a/hw/ipack/Kconfig b/hw/ipack/Kconfig
new file mode 100644 (file)
index 0000000..f8da24a
--- /dev/null
@@ -0,0 +1,4 @@
+config IPACK
+    bool
+    default y if PCI_DEVICES
+           depends on PCI
diff --git a/hw/ipmi/Kconfig b/hw/ipmi/Kconfig
new file mode 100644 (file)
index 0000000..b944fae
--- /dev/null
@@ -0,0 +1,22 @@
+config IPMI
+    bool
+
+config IPMI_LOCAL
+    bool
+    default y
+    depends on IPMI
+
+config IPMI_EXTERN
+    bool
+    default y
+    depends on IPMI
+
+config ISA_IPMI_KCS
+    bool
+    depends on ISA_BUS
+    select IPMI
+
+config ISA_IPMI_BT
+    bool
+    depends on ISA_BUS
+    select IPMI
diff --git a/hw/isa/Kconfig b/hw/isa/Kconfig
new file mode 100644 (file)
index 0000000..57e09a0
--- /dev/null
@@ -0,0 +1,53 @@
+config ISA_BUS
+    bool
+
+config APM
+    bool
+
+config I82378
+    bool
+    select ISA_BUS
+    select I8259
+    select I8254
+    select I82374
+    select MC146818RTC
+
+config PC87312
+    bool
+    select ISA_BUS
+    select I8259
+    select I8254
+    select I8257
+    select MC146818RTC
+    select SERIAL_ISA
+    select PARALLEL
+    select FDC
+    select IDE_ISA
+
+config PIIX4
+    bool
+    # For historical reasons, SuperIO devices are created in the board
+    # for PIIX4.
+    select ISA_BUS
+
+config VT82C686
+    bool
+    select ISA_BUS
+    select ACPI_SMBUS
+    select SERIAL_ISA
+    select FDC
+
+config SMC37C669
+    bool
+    select ISA_BUS
+    select SERIAL_ISA
+    select PARALLEL
+    select FDC
+
+config LPC_ICH9
+    bool
+    # For historical reasons, SuperIO devices are created in the board
+    # for ICH9.
+    select ISA_BUS
+    select ACPI_SMBUS
+    select ACPI_X86_ICH
diff --git a/hw/lm32/Kconfig b/hw/lm32/Kconfig
new file mode 100644 (file)
index 0000000..3d09c2d
--- /dev/null
@@ -0,0 +1,13 @@
+config LM32
+    bool
+    select PTIMER
+    select PFLASH_CFI02
+
+config MILKYMIST
+    bool
+    # FIXME: disabling it results in compile-time errors
+    select MILKYMIST_TMU2 if OPENGL && X11
+    select PTIMER
+    select PFLASH_CFI01
+    select FRAMEBUFFER
+    select SD
diff --git a/hw/m68k/Kconfig b/hw/m68k/Kconfig
new file mode 100644 (file)
index 0000000..49ef0b3
--- /dev/null
@@ -0,0 +1,9 @@
+config AN5206
+    bool
+    select COLDFIRE
+    select PTIMER
+
+config MCF5208
+    bool
+    select COLDFIRE
+    select PTIMER
diff --git a/hw/mem/Kconfig b/hw/mem/Kconfig
new file mode 100644 (file)
index 0000000..620fd4c
--- /dev/null
@@ -0,0 +1,11 @@
+config DIMM
+    bool
+    select MEM_DEVICE
+
+config MEM_DEVICE
+    bool
+
+config NVDIMM
+    bool
+    default y
+    depends on PC
diff --git a/hw/microblaze/Kconfig b/hw/microblaze/Kconfig
new file mode 100644 (file)
index 0000000..c4dc120
--- /dev/null
@@ -0,0 +1,20 @@
+config PETALOGIX_S3ADSP1800
+    bool
+    select PFLASH_CFI01
+    select XILINX
+    select XILINX_AXI
+    select XILINX_ETHLITE
+
+config PETALOGIX_ML605
+    bool
+    select PFLASH_CFI01
+    select SERIAL
+    select SSI_M25P80
+    select XILINX
+    select XILINX_AXI
+    select XILINX_ETHLITE
+    select XILINX_SPI
+
+config XLNX_ZYNQMP_PMU
+    bool
+    select XLNX_ZYNQMP
diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
new file mode 100644 (file)
index 0000000..cdc07e5
--- /dev/null
@@ -0,0 +1,21 @@
+config R4K
+    bool
+
+config MALTA
+    bool
+
+config MIPSSIM
+    bool
+
+config JAZZ
+    bool
+
+config FULONG
+    bool
+
+config MIPS_CPS
+    bool
+    select PTIMER
+
+config MIPS_BOSTON
+    bool
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
new file mode 100644 (file)
index 0000000..2c60be9
--- /dev/null
@@ -0,0 +1,118 @@
+config APPLESMC
+    bool
+    depends on ISA_BUS
+
+config MAX111X
+    bool
+
+config TMP105
+    bool
+    depends on I2C
+
+config TMP421
+    bool
+    depends on I2C
+
+config ISA_DEBUG
+    bool
+    depends on ISA_BUS
+
+config SGA
+    bool
+    depends on ISA_BUS
+
+config ISA_TESTDEV
+    bool
+    default y if TEST_DEVICES
+    depends on ISA_BUS
+
+config PCI_TESTDEV
+    bool
+    default y if TEST_DEVICES
+    depends on PCI
+
+config EDU
+    bool
+    default y if TEST_DEVICES
+    depends on PCI
+
+config PCA9552
+    bool
+    depends on I2C
+
+config PL310
+    bool
+
+config INTEGRATOR_DEBUG
+    bool
+
+config A9SCU
+    bool
+
+config ARM11SCU
+    bool
+
+config MOS6522
+    bool
+
+config MACIO
+    bool
+    select CUDA
+    select ESCC
+    select IDE_MACIO
+    select MAC_DBDMA
+    select MAC_NVRAM
+    select MOS6522
+
+config IVSHMEM_DEVICE
+    bool
+    default y if PCI_DEVICES
+    depends on PCI && LINUX && IVSHMEM
+
+config ECCMEMCTL
+    bool
+    select ECC
+
+config IMX
+    bool
+    select PTIMER
+
+config STM32F2XX_SYSCFG
+    bool
+
+config MIPS_ITU
+    bool
+
+config MPS2_FPGAIO
+    bool
+
+config MPS2_SCC
+    bool
+
+config TZ_MPC
+    bool
+
+config TZ_MSC
+    bool
+
+config TZ_PPC
+    bool
+
+config IOTKIT_SECCTL
+    bool
+
+config IOTKIT_SYSCTL
+    bool
+
+config IOTKIT_SYSINFO
+    bool
+
+config PVPANIC
+    bool
+    depends on ISA_BUS
+
+config AUX
+    bool
+    select I2C
+
+source macio/Kconfig
diff --git a/hw/misc/macio/Kconfig b/hw/misc/macio/Kconfig
new file mode 100644 (file)
index 0000000..c6caeb6
--- /dev/null
@@ -0,0 +1,11 @@
+config CUDA
+    bool
+
+config MAC_PMU
+    bool
+
+config MAC_DBDMA
+    bool
+
+config MACIO_GPIO
+    bool
diff --git a/hw/moxie/Kconfig b/hw/moxie/Kconfig
new file mode 100644 (file)
index 0000000..3793ef0
--- /dev/null
@@ -0,0 +1,3 @@
+config MOXIESIM
+    bool
+    select SERIAL
diff --git a/hw/net/Kconfig b/hw/net/Kconfig
new file mode 100644 (file)
index 0000000..c00ec03
--- /dev/null
@@ -0,0 +1,125 @@
+config DP8393X
+    bool
+
+config NE2000_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+
+config EEPRO100_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+
+config PCNET_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select PCNET_COMMON
+
+config PCNET_COMMON
+    bool
+
+config E1000_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+
+config E1000E_PCI_EXPRESS
+    bool
+    default y if PCI_DEVICES
+    depends on PCI_EXPRESS
+
+config RTL8139_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+
+config VMXNET3_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+
+config SMC91C111
+    bool
+
+config LAN9118
+    bool
+    select PTIMER
+
+config NE2000_ISA
+    bool
+    default y
+    depends on ISA_BUS
+    depends on PCI # for NE2000State
+    select NE2000_PCI
+
+config OPENCORES_ETH
+    bool
+
+config XGMAC
+    bool
+
+config MIPSNET
+    bool
+
+config ALLWINNER_EMAC
+    bool
+
+config IMX_FEC
+    bool
+
+config CADENCE
+    bool
+
+config STELLARIS_ENET
+    bool
+
+config LANCE
+    bool
+    select PCNET_COMMON
+
+config SUNHME
+    bool
+
+config FTGMAC100
+    bool
+
+config SUNGEM
+    bool
+    depends on PCI
+
+config COLDFIRE
+    bool
+
+config XILINX_ETHLITE
+    bool
+
+config VIRTIO_NET
+    bool
+    default y
+    depends on VIRTIO
+
+config ETSEC
+    bool
+    select PTIMER
+
+config ROCKER
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+
+config CAN_BUS
+    bool
+
+config CAN_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select CAN_BUS
+
+config CAN_SJA1000
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select CAN_BUS
diff --git a/hw/nios2/Kconfig b/hw/nios2/Kconfig
new file mode 100644 (file)
index 0000000..ab953e0
--- /dev/null
@@ -0,0 +1,8 @@
+config NIOS2_10M50
+    bool
+    select NIOS2
+    select SERIAL
+    select ALTERA_TIMER
+
+config NIOS2
+    bool
diff --git a/hw/nvram/Kconfig b/hw/nvram/Kconfig
new file mode 100644 (file)
index 0000000..ebaa749
--- /dev/null
@@ -0,0 +1,9 @@
+config DS1225Y
+    bool
+
+config AT24C
+    bool
+    depends on I2C
+
+config MAC_NVRAM
+    bool
diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig
new file mode 100644 (file)
index 0000000..6c1e868
--- /dev/null
@@ -0,0 +1,5 @@
+config OR1K_SIM
+    bool
+    select SERIAL
+    select OPENCORES_ETH
+    select OMPIC
diff --git a/hw/pci-bridge/Kconfig b/hw/pci-bridge/Kconfig
new file mode 100644 (file)
index 0000000..b167b98
--- /dev/null
@@ -0,0 +1,29 @@
+config PCIE_PORT
+    bool
+    default y if PCI_DEVICES
+    depends on PCI_EXPRESS
+
+config PXB
+    bool
+    default y if Q35
+
+config XIO3130
+    bool
+    default y if PCI_DEVICES
+    depends on PCI_EXPRESS
+
+config IOH3420
+    bool
+    default y if PCI_DEVICES
+    depends on PCI_EXPRESS
+
+config I82801B11
+    bool
+    default y if PCI_DEVICES
+    depends on PCI_EXPRESS
+
+config DEC_PCI
+    bool
+
+config SIMBA
+    bool
diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig
new file mode 100644 (file)
index 0000000..b39ea29
--- /dev/null
@@ -0,0 +1,51 @@
+config PAM
+    bool
+
+config PREP_PCI
+    select PCI
+    bool
+
+config GRACKLE_PCI
+    select PCI
+    bool
+
+config UNIN_PCI
+    bool
+    select PCI
+    select DEC_PCI
+    select OPENPIC
+
+config PPCE500_PCI
+    select PCI
+    bool
+
+config VERSATILE_PCI
+    select PCI
+    bool
+
+config PCI_SABRE
+    select PCI
+    bool
+
+config PCI_PIIX
+    bool
+    select PCI
+    select PAM
+    select ISA_BUS
+
+config PCI_EXPRESS_Q35
+    bool
+    select PCI_EXPRESS
+    select PAM
+
+config PCI_EXPRESS_GENERIC_BRIDGE
+    bool
+    select PCI_EXPRESS
+
+config PCI_EXPRESS_XILINX
+    bool
+    select PCI_EXPRESS
+
+config PCI_EXPRESS_DESIGNWARE
+    bool
+    select PCI_EXPRESS
diff --git a/hw/pci/Kconfig b/hw/pci/Kconfig
new file mode 100644 (file)
index 0000000..3b8638b
--- /dev/null
@@ -0,0 +1,9 @@
+config PCI
+    bool
+
+config PCI_EXPRESS
+    bool
+    select PCI
+
+config PCI_DEVICES
+    bool
index 9f905e6344c724695dbed7d3f4213131e01357c7..c78f2fb24b535a6b3d40729cab1da2c89167cfbb 100644 (file)
@@ -2,8 +2,13 @@ common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o
 common-obj-$(CONFIG_PCI) += msix.o msi.o
 common-obj-$(CONFIG_PCI) += shpc.o
 common-obj-$(CONFIG_PCI) += slotid_cap.o
-common-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
-common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o
+common-obj-$(CONFIG_PCI) += pci_host.o
+
+# The functions in these modules can be used by devices too.  Since we
+# allow plugging PCIe devices into PCI buses, include them even if
+# CONFIG_PCI_EXPRESS=n.
+common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o
+common-obj-$(CONFIG_PCI_EXPRESS) += pcie_port.o pcie_host.o
 
 common-obj-$(call lnot,$(CONFIG_PCI)) += pci-stub.o
 common-obj-$(CONFIG_ALL) += pci-stub.o
diff --git a/hw/pcmcia/Kconfig b/hw/pcmcia/Kconfig
new file mode 100644 (file)
index 0000000..41f2df9
--- /dev/null
@@ -0,0 +1,2 @@
+config PCMCIA
+    bool
diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
new file mode 100644 (file)
index 0000000..2b83637
--- /dev/null
@@ -0,0 +1,121 @@
+config PSERIES
+    bool
+    imply PCI_DEVICES
+    imply TEST_DEVICES
+    select DIMM
+    select PCI
+    select SPAPR_VSCSI
+    select VFIO if LINUX   # needed by spapr_pci_vfio.c
+    select XICS_SPAPR
+    select XIVE_SPAPR
+
+config SPAPR_RNG
+    bool
+    default y
+    depends on PSERIES
+
+config POWERNV
+    bool
+    imply PCI_DEVICES
+    imply TEST_DEVICES
+    select ISA_IPMI_BT
+    select IPMI_LOCAL
+    select ISA_BUS
+    select MC146818RTC
+    select XICS
+    select XIVE
+
+config PPC405
+    bool
+    select M48T59
+    select PFLASH_CFI02
+    select PPC4XX
+    select SERIAL
+
+config PPC440
+    bool
+    imply PCI_DEVICES
+    imply TEST_DEVICES
+    select PCI_EXPRESS
+    select PPC4XX
+    select SERIAL
+
+config PPC4XX
+    bool
+    select BITBANG_I2C
+    select PCI
+
+config SAM460EX
+    bool
+    select PFLASH_CFI01
+    select IDE_SII3112
+    select M41T80
+    select PPC440
+    select SERIAL
+    select SM501
+    select SMBUS_EEPROM
+    select USB_EHCI_SYSBUS
+    select USB_OHCI
+
+config PREP
+    bool
+    imply PCI_DEVICES
+    imply TEST_DEVICES
+    select CS4231A
+    select PREP_PCI
+    select I82374
+    select I82378
+    select LSI_SCSI_PCI
+    select M48T59
+    select PC87312
+    select RS6000_MC
+
+config RS6000_MC
+    bool
+
+config MAC_OLDWORLD
+    bool
+    imply PCI_DEVICES
+    imply SUNGEM
+    imply TEST_DEVICES
+    select ADB
+    select GRACKLE_PCI
+    select HEATHROW_PIC
+    select MACIO
+
+config MAC_NEWWORLD
+    bool
+    imply PCI_DEVICES
+    imply SUNGEM
+    imply TEST_DEVICES
+    select ADB
+    select MACIO
+    select MACIO_GPIO
+    select MAC_PMU
+    select UNIN_PCI
+
+config E500
+    bool
+    imply AT24C
+    select ETSEC
+    select OPENPIC
+    select PLATFORM_BUS
+    select PPCE500_PCI
+    select SERIAL
+
+config VIRTEX
+    bool
+    select PFLASH_CFI01
+    select SERIAL
+    select XILINX
+    select XILINX_ETHLITE
+
+config XIVE
+    bool
+    depends on POWERNV || PSERIES
+
+config XIVE_SPAPR
+    bool
+    default y
+    depends on PSERIES
+    select XIVE
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
new file mode 100644 (file)
index 0000000..e0ee304
--- /dev/null
@@ -0,0 +1,33 @@
+config HTIF
+    bool
+
+config HART
+    bool
+
+config SIFIVE
+    bool
+
+config SIFIVE_E
+    bool
+    select HART
+    select SIFIVE
+
+config SIFIVE_U
+    bool
+    select CADENCE
+    select HART
+    select SIFIVE
+
+config SPIKE
+    bool
+    select HART
+    select HTIF
+    select SIFIVE
+
+config RISCV_VIRT
+    bool
+    select HART
+    select SERIAL
+    select VIRTIO_MMIO
+    select PCI_EXPRESS_GENERIC_BRIDGE
+    select SIFIVE
diff --git a/hw/s390x/Kconfig b/hw/s390x/Kconfig
new file mode 100644 (file)
index 0000000..a7046ea
--- /dev/null
@@ -0,0 +1,11 @@
+config S390_CCW_VIRTIO
+    bool
+    imply VIRTIO_PCI
+    imply TERMINAL3270
+    imply VFIO_AP
+    imply VFIO_CCW
+    imply WDT_DIAG288
+    select PCI
+    select S390_FLIC
+    select SCLPCONSOLE
+    select VIRTIO_CCW
index bfd5326d7c3dce73461f44370666a47574481b7d..e02ed80b6829a511362abc3525ec3282664e035c 100644 (file)
@@ -6,7 +6,8 @@ obj-y += sclpcpu.o
 obj-y += ipl.o
 obj-y += css.o
 obj-$(CONFIG_S390_CCW_VIRTIO) += s390-virtio-ccw.o
-obj-y += 3270-ccw.o
+obj-$(CONFIG_TERMINAL3270) += 3270-ccw.o
+ifeq ($(CONFIG_VIRTIO_CCW),y)
 obj-y += virtio-ccw.o
 obj-$(CONFIG_VIRTIO_SERIAL) += virtio-ccw-serial.o
 obj-$(CONFIG_VIRTIO_BALLOON) += virtio-ccw-balloon.o
@@ -19,6 +20,7 @@ obj-$(CONFIG_VIRTIO_NET) += virtio-ccw-net.o
 obj-$(CONFIG_VIRTIO_BLK) += virtio-ccw-blk.o
 obj-$(call land,$(CONFIG_VIRTIO_9P),$(CONFIG_VIRTFS)) += virtio-ccw-9p.o
 obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-ccw.o
+endif
 obj-y += css-bridge.o
 obj-y += ccw-device.o
 obj-y += s390-pci-bus.o s390-pci-inst.o
diff --git a/hw/scsi/Kconfig b/hw/scsi/Kconfig
new file mode 100644 (file)
index 0000000..b3ba540
--- /dev/null
@@ -0,0 +1,54 @@
+config SCSI
+    bool
+
+config LSI_SCSI_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select SCSI
+
+config MPTSAS_SCSI_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select SCSI
+
+config MEGASAS_SCSI_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select SCSI
+
+config VMW_PVSCSI_SCSI_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select SCSI
+
+config ESP
+    bool
+    select SCSI
+
+config ESP_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select ESP
+
+config SPAPR_VSCSI
+    bool
+    default y
+    depends on PSERIES
+    select SCSI
+
+config VIRTIO_SCSI
+    bool
+    default y
+    depends on VIRTIO
+    select SCSI
+
+config VHOST_USER_SCSI
+    bool
+    # Only PCI devices are provided for now
+    default y if VIRTIO_PCI
+    depends on VIRTIO && VHOST_USER && LINUX
index 45167baeafcc964ff065d861198aba8187e2e6bf..54b36ed8b1068bd3c8ff188118976f0a6faf52f4 100644 (file)
@@ -6,7 +6,7 @@ common-obj-$(CONFIG_MEGASAS_SCSI_PCI) += megasas.o
 common-obj-$(CONFIG_VMW_PVSCSI_SCSI_PCI) += vmw_pvscsi.o
 common-obj-$(CONFIG_ESP) += esp.o
 common-obj-$(CONFIG_ESP_PCI) += esp-pci.o
-obj-$(CONFIG_PSERIES) += spapr_vscsi.o
+obj-$(CONFIG_SPAPR_VSCSI) += spapr_vscsi.o
 
 ifeq ($(CONFIG_VIRTIO_SCSI),y)
 obj-y += virtio-scsi.o virtio-scsi-dataplane.o
diff --git a/hw/sd/Kconfig b/hw/sd/Kconfig
new file mode 100644 (file)
index 0000000..864f535
--- /dev/null
@@ -0,0 +1,17 @@
+config PL181
+    bool
+    select SD
+
+config SSI_SD
+    bool
+    depends on SSI
+    select SD
+
+config SD
+    bool
+
+config SDHCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select SD
diff --git a/hw/sh4/Kconfig b/hw/sh4/Kconfig
new file mode 100644 (file)
index 0000000..8597613
--- /dev/null
@@ -0,0 +1,23 @@
+config R2D
+    bool
+    imply PCI_DEVICES
+    imply TEST_DEVICES
+    select I82378 if TEST_DEVICES
+    select IDE_MMIO
+    select PFLASH_CFI02
+    select USB_OHCI
+    select PCI
+    select SM501
+    select SH4
+
+config SHIX
+    bool
+    select SH7750
+    select SH4
+
+config SH7750
+    bool
+
+config SH4
+    bool
+    select PTIMER
diff --git a/hw/smbios/Kconfig b/hw/smbios/Kconfig
new file mode 100644 (file)
index 0000000..553adf4
--- /dev/null
@@ -0,0 +1,2 @@
+config SMBIOS
+    bool
diff --git a/hw/sparc/Kconfig b/hw/sparc/Kconfig
new file mode 100644 (file)
index 0000000..2a83a80
--- /dev/null
@@ -0,0 +1,26 @@
+config SUN4M
+    bool
+    imply TCX
+    imply CG3
+    select CS4231
+    select ECCMEMCTL
+    select EMPTY_SLOT
+    select ESCC
+    select ESP
+    select FDC
+    select SLAVIO
+    select LANCE
+    select M48T59
+    select STP2000
+
+config LEON3
+    bool
+    select GRLIB
+
+config GRLIB
+    bool
+    select PTIMER
+
+config SLAVIO
+    bool
+    select PTIMER
diff --git a/hw/sparc64/Kconfig b/hw/sparc64/Kconfig
new file mode 100644 (file)
index 0000000..4a8166e
--- /dev/null
@@ -0,0 +1,19 @@
+config SUN4U
+    bool
+    imply PCI_DEVICES
+    imply SUNHME
+    imply TEST_DEVICES
+    select M48T59
+    select ISA_BUS
+    select FDC
+    select SERIAL_ISA
+    select PCI_SABRE
+    select IDE_CMD646
+    select PARALLEL
+    select PCKBD
+    select SIMBA
+
+config NIAGARA
+    bool
+    select EMPTY_SLOT
+    select SUN4V_RTC
diff --git a/hw/ssi/Kconfig b/hw/ssi/Kconfig
new file mode 100644 (file)
index 0000000..9e54a0c
--- /dev/null
@@ -0,0 +1,18 @@
+config PL022
+    bool
+    select SSI
+
+config SSI
+    bool
+
+config XILINX_SPI
+    bool
+    select SSI
+
+config XILINX_SPIPS
+    bool
+    select SSI
+
+config STM32F2XX_SPI
+    bool
+    select SSI
diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig
new file mode 100644 (file)
index 0000000..51921eb
--- /dev/null
@@ -0,0 +1,63 @@
+config ARM_TIMER
+    bool
+    select PTIMER
+
+config ARM_MPTIMER
+    bool
+    select PTIMER
+
+config A9_GTIMER
+    bool
+
+config DS1338
+    bool
+    depends on I2C
+
+config HPET
+    bool
+    default y if PC
+
+config I8254
+    bool
+
+config M41T80
+    bool
+    depends on I2C
+
+config M48T59
+    bool
+
+config PL031
+    bool
+
+config TWL92230
+    bool
+    depends on I2C
+
+config XLNX_ZYNQMP
+    bool
+
+config ALTERA_TIMER
+    bool
+    select PTIMER
+
+config MC146818RTC
+    bool
+
+config ALLWINNER_A10_PIT
+    bool
+    select PTIMER
+
+config STM32F2XX_TIMER
+    bool
+
+config SUN4V_RTC
+    bool
+
+config CMSDK_APB_TIMER
+    bool
+    select PTIMER
+
+config CMSDK_APB_DUALTIMER
+    bool
+    select PTIMER
diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig
new file mode 100644 (file)
index 0000000..4c8ee87
--- /dev/null
@@ -0,0 +1,24 @@
+config TPMDEV
+    bool
+    depends on TPM
+
+config TPM_TIS
+    bool
+    depends on TPM && ISA_BUS
+    select TPMDEV
+
+config TPM_CRB
+    bool
+    depends on TPM && PC
+    select TPMDEV
+
+config TPM_PASSTHROUGH
+    bool
+    default y
+    # FIXME: should check for x86 host as well
+    depends on TPMDEV && LINUX
+
+config TPM_EMULATOR
+    bool
+    default y
+    depends on TPMDEV
diff --git a/hw/tricore/Kconfig b/hw/tricore/Kconfig
new file mode 100644 (file)
index 0000000..9313409
--- /dev/null
@@ -0,0 +1,2 @@
+config TRICORE
+    bool
diff --git a/hw/unicore32/Kconfig b/hw/unicore32/Kconfig
new file mode 100644 (file)
index 0000000..4443a29
--- /dev/null
@@ -0,0 +1,5 @@
+config PUV3
+    bool
+    select ISA_BUS
+    select PCKBD
+    select PTIMER
diff --git a/hw/usb/Kconfig b/hw/usb/Kconfig
new file mode 100644 (file)
index 0000000..a1b7acb
--- /dev/null
@@ -0,0 +1,91 @@
+config USB
+    bool
+
+config USB_UHCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select USB
+
+config USB_OHCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select USB
+
+config USB_EHCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select USB
+
+config USB_EHCI_SYSBUS
+    bool
+    select USB
+
+config USB_XHCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select USB
+
+config USB_XHCI_NEC
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select USB
+
+config USB_MUSB
+    bool
+    select USB
+
+config TUSB6010
+    bool
+    select USB_MUSB
+
+config USB_TABLET_WACOM
+    bool
+    default y
+    depends on USB
+
+config USB_STORAGE_BOT
+    bool
+    default y
+    depends on USB
+    select SCSI
+
+config USB_STORAGE_UAS
+    bool
+    default y
+    depends on USB
+    select SCSI
+
+config USB_AUDIO
+    bool
+    default y
+    depends on USB
+
+config USB_SERIAL
+    bool
+    default y
+    depends on USB
+
+config USB_NETWORK
+    bool
+    default y
+    depends on USB
+
+config USB_BLUETOOTH
+    bool
+    default y
+    depends on USB
+
+config USB_SMARTCARD
+    bool
+    default y
+    depends on USB
+
+config USB_STORAGE_MTP
+    bool
+    default y
+    depends on USB
index 41be700812a920e00a61b969cc0f07f312d87ded..2b929649acd03e8ec98cae7dc51ba754e5c730c6 100644 (file)
@@ -6,7 +6,7 @@ common-obj-$(CONFIG_USB) += desc.o desc-msos.o
 common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
 common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o
 common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o
-common-obj-$(CONFIG_USB_EHCI_SYSBUS) += hcd-ehci-sysbus.o
+common-obj-$(CONFIG_USB_EHCI_SYSBUS) += hcd-ehci.o hcd-ehci-sysbus.o
 common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
 common-obj-$(CONFIG_USB_XHCI_NEC) += hcd-xhci-nec.o
 common-obj-$(CONFIG_USB_MUSB) += hcd-musb.o
diff --git a/hw/vfio/Kconfig b/hw/vfio/Kconfig
new file mode 100644 (file)
index 0000000..ebda9fd
--- /dev/null
@@ -0,0 +1,36 @@
+config VFIO
+    bool
+    depends on LINUX
+
+config VFIO_PCI
+    bool
+    select VFIO
+    depends on LINUX
+
+config VFIO_CCW
+    bool
+    default y
+    select VFIO
+    depends on LINUX && S390_CCW_VIRTIO
+
+config VFIO_PLATFORM
+    bool
+    default y
+    select VFIO
+    depends on LINUX && PLATFORM_BUS
+
+config VFIO_XGMAC
+    bool
+    default y
+    depends on VFIO_PLATFORM
+
+config VFIO_AMD_XGBE
+    bool
+    default y
+    depends on VFIO_PLATFORM
+
+config VFIO_AP
+    bool
+    default y
+    select VFIO
+    depends on LINUX && S390_CCW_VIRTIO
diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig
new file mode 100644 (file)
index 0000000..e0452de
--- /dev/null
@@ -0,0 +1,31 @@
+config VIRTIO
+    bool
+
+config VIRTIO_RNG
+    bool
+    default y
+    depends on VIRTIO
+
+config VIRTIO_PCI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select VIRTIO
+
+config VIRTIO_MMIO
+    bool
+    select VIRTIO
+
+config VIRTIO_CCW
+    bool
+    select VIRTIO
+
+config VIRTIO_BALLOON
+    bool
+    default y
+    depends on VIRTIO
+
+config VIRTIO_CRYPTO
+    bool
+    default y
+    depends on VIRTIO
index a3eb8ed86628d325ebf238d5006a66286e55300d..f2ab667a2118e0a732567ad811b1b3860782c914 100644 (file)
@@ -29,6 +29,8 @@ obj-$(CONFIG_VIRTIO_BLK) += virtio-blk-pci.o
 obj-$(CONFIG_VIRTIO_NET) += virtio-net-pci.o
 obj-$(CONFIG_VIRTIO_SERIAL) += virtio-serial-pci.o
 endif
+else
+common-obj-y += vhost-stub.o
 endif
 
 common-obj-$(CONFIG_ALL) += vhost-stub.o
diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig
new file mode 100644 (file)
index 0000000..2118d89
--- /dev/null
@@ -0,0 +1,16 @@
+config CMSDK_APB_WATCHDOG
+    bool
+    select PTIMER
+
+config WDT_IB6300ESB
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+
+config WDT_IB700
+    bool
+    default y
+    depends on ISA_BUS
+
+config WDT_DIAG288
+    bool
diff --git a/hw/xtensa/Kconfig b/hw/xtensa/Kconfig
new file mode 100644 (file)
index 0000000..d72817d
--- /dev/null
@@ -0,0 +1,8 @@
+config XTENSA_SIM
+    bool
+
+config XTENSA_XTFPGA
+    bool
+    select OPENCORES_ETH
+    select PFLASH_CFI01
+    select SERIAL
index fa86730e23fa47790c2e523b60f6c8ccb0929ee1..0bbfccd6deaee182120f9319a0a57f023d7e38bb 100644 (file)
@@ -2,4 +2,4 @@ obj-y += mx_pic.o
 obj-y += pic_cpu.o
 obj-y += xtensa_memory.o
 obj-$(CONFIG_XTENSA_SIM) += sim.o
-obj-$(CONFIG_XTENSA_FPGA) += xtfpga.o
+obj-$(CONFIG_XTENSA_XTFPGA) += xtfpga.o
index bd6d7dd7f96758cd841df44db4433be5a456a867..bbe04d4484a2391a292f0e4a6b2d6620c98e7456 100644 (file)
@@ -25,6 +25,8 @@
 #ifndef QEMU_FILE_H
 #define QEMU_FILE_H
 
+int qemu_file_get_error(QEMUFile *f);
+
 void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, size_t size);
 void qemu_put_byte(QEMUFile *f, int v);
 
index 6e8762b40dea2c717fb4e97cc87e090c15047ecf..c1a26021f8d790513efa3d64741c0ec5ad420222 100644 (file)
@@ -500,13 +500,48 @@ static uint32_t get_elf_hwcap2(void)
 #undef GET_FEATURE
 #undef GET_FEATURE_ID
 
+#define ELF_PLATFORM get_elf_platform()
+
+static const char *get_elf_platform(void)
+{
+    CPUARMState *env = thread_cpu->env_ptr;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+# define END  "b"
+#else
+# define END  "l"
+#endif
+
+    if (arm_feature(env, ARM_FEATURE_V8)) {
+        return "v8" END;
+    } else if (arm_feature(env, ARM_FEATURE_V7)) {
+        if (arm_feature(env, ARM_FEATURE_M)) {
+            return "v7m" END;
+        } else {
+            return "v7" END;
+        }
+    } else if (arm_feature(env, ARM_FEATURE_V6)) {
+        return "v6" END;
+    } else if (arm_feature(env, ARM_FEATURE_V5)) {
+        return "v5" END;
+    } else {
+        return "v4" END;
+    }
+
+#undef END
+}
+
 #else
 /* 64 bit ARM definitions */
 #define ELF_START_MMAP 0x80000000
 
 #define ELF_ARCH        EM_AARCH64
 #define ELF_CLASS       ELFCLASS64
-#define ELF_PLATFORM    "aarch64"
+#ifdef TARGET_WORDS_BIGENDIAN
+# define ELF_PLATFORM    "aarch64_be"
+#else
+# define ELF_PLATFORM    "aarch64"
+#endif
 
 static inline void init_thread(struct target_pt_regs *regs,
                                struct image_info *infop)
index 30425c9df6bcf74fe36ce4be4a42063f998a973b..612819c1b1ec2018f7b5077ef907a094d85e70a5 100644 (file)
@@ -75,6 +75,8 @@ enum {
     QEMU_IFLA_BR_MCAST_STATS_ENABLED,
     QEMU_IFLA_BR_MCAST_IGMP_VERSION,
     QEMU_IFLA_BR_MCAST_MLD_VERSION,
+    QEMU_IFLA_BR_VLAN_STATS_PER_PORT,
+    QEMU_IFLA_BR_MULTI_BOOLOPT,
     QEMU___IFLA_BR_MAX,
 };
 
@@ -438,6 +440,7 @@ static abi_long host_to_target_data_bridge_nlattr(struct nlattr *nlattr,
     case QEMU_IFLA_BR_MCAST_STATS_ENABLED:
     case QEMU_IFLA_BR_MCAST_IGMP_VERSION:
     case QEMU_IFLA_BR_MCAST_MLD_VERSION:
+    case QEMU_IFLA_BR_VLAN_STATS_PER_PORT:
         break;
     /* uint16_t */
     case QEMU_IFLA_BR_PRIORITY:
@@ -543,6 +546,12 @@ static abi_long host_to_target_slave_data_bridge_nlattr(struct nlattr *nlattr,
     case QEMU_IFLA_BRPORT_ROOT_ID:
     case QEMU_IFLA_BRPORT_BRIDGE_ID:
         break;
+    /* br_boolopt_multi { uint32_t, uint32_t } */
+    case QEMU_IFLA_BR_MULTI_BOOLOPT:
+        u32 = NLA_DATA(nlattr);
+        u32[0] = tswap32(u32[0]); /* optval */
+        u32[1] = tswap32(u32[1]); /* optmask */
+        break;
     default:
         gemu_log("Unknown QEMU_IFLA_BRPORT type %d\n", nlattr->nla_type);
         break;
index b96b1aa1195aa86a867991c937b2b5cce2fd46ea..5aa1eca740deda9e1fe46da22f98f22d8e88ecdb 100644 (file)
@@ -73,6 +73,12 @@ void cpu_loop(CPUNios2State *env)
                 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
                 break;
             }
+        case EXCP_DEBUG:
+            info.si_signo = TARGET_SIGTRAP;
+            info.si_errno = 0;
+            info.si_code = TARGET_TRAP_BRKPT;
+            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+            break;
         case 0xaa:
             switch (env->regs[R_PC]) {
             /*case 0x1000:*/  /* TODO:__kuser_helper_version */
index 7318392e571cdc1f2ede34eb24aff08b10b28c15..6f72a74c091853106780ed5fd171d676602c4d72 100644 (file)
@@ -1235,6 +1235,18 @@ print_chdir(const struct syscallname *name,
 }
 #endif
 
+#ifdef TARGET_NR_chroot
+static void
+print_chroot(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_syscall_prologue(name);
+    print_string(arg0, 1);
+    print_syscall_epilogue(name);
+}
+#endif
+
 #ifdef TARGET_NR_chmod
 static void
 print_chmod(const struct syscallname *name,
index ff8bb19f5facfacd380c7cb3c022fd86889a66e0..db21ce41779fd6a36865bf21807184c25e5d4d18 100644 (file)
@@ -77,7 +77,7 @@
 { TARGET_NR_chown32, "chown32" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_chroot
-{ TARGET_NR_chroot, "chroot" , NULL, NULL, NULL },
+{ TARGET_NR_chroot, "chroot" , NULL, print_chroot, NULL },
 #endif
 #ifdef TARGET_NR_clock_adjtime
 { TARGET_NR_clock_adjtime, "clock_adjtime" , NULL, print_clock_adjtime, NULL },
index 5bbb72f3d5fce05cedf58fac3b37b816ac3a87af..208fd1813d6a932fe2c810c6b2713c42850bcaa6 100644 (file)
@@ -2759,6 +2759,7 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
             }
             if (!is_error(ret)) {
                 msgp->msg_namelen = tswap32(msg.msg_namelen);
+                msgp->msg_flags = tswap32(msg.msg_flags);
                 if (msg.msg_name != NULL && msg.msg_name != (void *)-1) {
                     ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
                                     msg.msg_name, msg.msg_namelen);
@@ -2846,7 +2847,7 @@ static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec,
 static abi_long do_accept4(int fd, abi_ulong target_addr,
                            abi_ulong target_addrlen_addr, int flags)
 {
-    socklen_t addrlen;
+    socklen_t addrlen, ret_addrlen;
     void *addr;
     abi_long ret;
     int host_flags;
@@ -2870,11 +2871,13 @@ static abi_long do_accept4(int fd, abi_ulong target_addr,
 
     addr = alloca(addrlen);
 
-    ret = get_errno(safe_accept4(fd, addr, &addrlen, host_flags));
+    ret_addrlen = addrlen;
+    ret = get_errno(safe_accept4(fd, addr, &ret_addrlen, host_flags));
     if (!is_error(ret)) {
-        host_to_target_sockaddr(target_addr, addr, addrlen);
-        if (put_user_u32(addrlen, target_addrlen_addr))
+        host_to_target_sockaddr(target_addr, addr, MIN(addrlen, ret_addrlen));
+        if (put_user_u32(ret_addrlen, target_addrlen_addr)) {
             ret = -TARGET_EFAULT;
+        }
     }
     return ret;
 }
@@ -2883,7 +2886,7 @@ static abi_long do_accept4(int fd, abi_ulong target_addr,
 static abi_long do_getpeername(int fd, abi_ulong target_addr,
                                abi_ulong target_addrlen_addr)
 {
-    socklen_t addrlen;
+    socklen_t addrlen, ret_addrlen;
     void *addr;
     abi_long ret;
 
@@ -2899,11 +2902,13 @@ static abi_long do_getpeername(int fd, abi_ulong target_addr,
 
     addr = alloca(addrlen);
 
-    ret = get_errno(getpeername(fd, addr, &addrlen));
+    ret_addrlen = addrlen;
+    ret = get_errno(getpeername(fd, addr, &ret_addrlen));
     if (!is_error(ret)) {
-        host_to_target_sockaddr(target_addr, addr, addrlen);
-        if (put_user_u32(addrlen, target_addrlen_addr))
+        host_to_target_sockaddr(target_addr, addr, MIN(addrlen, ret_addrlen));
+        if (put_user_u32(ret_addrlen, target_addrlen_addr)) {
             ret = -TARGET_EFAULT;
+        }
     }
     return ret;
 }
@@ -2912,7 +2917,7 @@ static abi_long do_getpeername(int fd, abi_ulong target_addr,
 static abi_long do_getsockname(int fd, abi_ulong target_addr,
                                abi_ulong target_addrlen_addr)
 {
-    socklen_t addrlen;
+    socklen_t addrlen, ret_addrlen;
     void *addr;
     abi_long ret;
 
@@ -2928,11 +2933,13 @@ static abi_long do_getsockname(int fd, abi_ulong target_addr,
 
     addr = alloca(addrlen);
 
-    ret = get_errno(getsockname(fd, addr, &addrlen));
+    ret_addrlen = addrlen;
+    ret = get_errno(getsockname(fd, addr, &ret_addrlen));
     if (!is_error(ret)) {
-        host_to_target_sockaddr(target_addr, addr, addrlen);
-        if (put_user_u32(addrlen, target_addrlen_addr))
+        host_to_target_sockaddr(target_addr, addr, MIN(addrlen, ret_addrlen));
+        if (put_user_u32(ret_addrlen, target_addrlen_addr)) {
             ret = -TARGET_EFAULT;
+        }
     }
     return ret;
 }
@@ -3004,7 +3011,7 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
                             abi_ulong target_addr,
                             abi_ulong target_addrlen)
 {
-    socklen_t addrlen;
+    socklen_t addrlen, ret_addrlen;
     void *addr;
     void *host_msg;
     abi_long ret;
@@ -3022,10 +3029,12 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
             goto fail;
         }
         addr = alloca(addrlen);
+        ret_addrlen = addrlen;
         ret = get_errno(safe_recvfrom(fd, host_msg, len, flags,
-                                      addr, &addrlen));
+                                      addr, &ret_addrlen));
     } else {
         addr = NULL; /* To keep compiler quiet.  */
+        addrlen = 0; /* To keep compiler quiet.  */
         ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, NULL, 0));
     }
     if (!is_error(ret)) {
@@ -3038,8 +3047,9 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
             }
         }
         if (target_addr) {
-            host_to_target_sockaddr(target_addr, addr, addrlen);
-            if (put_user_u32(addrlen, target_addrlen)) {
+            host_to_target_sockaddr(target_addr, addr,
+                                    MIN(addrlen, ret_addrlen));
+            if (put_user_u32(ret_addrlen, target_addrlen)) {
                 ret = -TARGET_EFAULT;
                 goto fail;
             }
@@ -4723,8 +4733,8 @@ static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
     const int *dst_offsets, *src_offsets;
     int target_size;
     void *argptr;
-    abi_ulong *target_rt_dev_ptr;
-    unsigned long *host_rt_dev_ptr;
+    abi_ulong *target_rt_dev_ptr = NULL;
+    unsigned long *host_rt_dev_ptr = NULL;
     abi_long ret;
     int i;
 
@@ -4770,6 +4780,9 @@ static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
     unlock_user(argptr, arg, 0);
 
     ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
+
+    assert(host_rt_dev_ptr != NULL);
+    assert(target_rt_dev_ptr != NULL);
     if (*host_rt_dev_ptr != 0) {
         unlock_user((void *)*host_rt_dev_ptr,
                     *target_rt_dev_ptr, 0);
@@ -6999,8 +7012,8 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         _exit(arg1);
         return 0; /* avoid warning */
     case TARGET_NR_read:
-        if (arg3 == 0) {
-            return 0;
+        if (arg2 == 0 && arg3 == 0) {
+            return get_errno(safe_read(arg1, 0, 0));
         } else {
             if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
                 return -TARGET_EFAULT;
index 2ccfcfb2a8ce6b60c5c330a6369b4d282c9cf879..13baf896bd2f182bad7fc0fa96ca35930d3715c2 100644 (file)
@@ -149,7 +149,6 @@ void qemu_update_position(QEMUFile *f, size_t size);
 void qemu_file_reset_rate_limit(QEMUFile *f);
 void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
 int64_t qemu_file_get_rate_limit(QEMUFile *f);
-int qemu_file_get_error(QEMUFile *f);
 void qemu_file_set_error(QEMUFile *f, int ret);
 int qemu_file_shutdown(QEMUFile *f);
 QEMUFile *qemu_file_get_return_path(QEMUFile *f);
index 8262f033b999da2b304f056b328777b88ad13807..c5d076d19c9e20c6ce996ab31154f460d0d10270 100644 (file)
@@ -8,6 +8,8 @@ common-obj-$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET_USER)) += vhost-u
 common-obj-$(call land,$(call lnot,$(CONFIG_VIRTIO_NET)),$(CONFIG_VHOST_NET_USER)) += vhost-user-stub.o
 common-obj-$(CONFIG_ALL) += vhost-user-stub.o
 common-obj-$(CONFIG_SLIRP) += slirp.o
+slirp.o-cflags := $(SLIRP_CFLAGS)
+slirp.o-libs := $(SLIRP_LIBS)
 common-obj-$(CONFIG_VDE) += vde.o
 common-obj-$(CONFIG_NETMAP) += netmap.o
 common-obj-y += filter.o
index 4ec989b59228a0a1d815e2b4a814ef2b53b0f769..95934fb36d61025ef45afa35a7a2ad29411f4717 100644 (file)
 #include "monitor/monitor.h"
 #include "qemu/error-report.h"
 #include "qemu/sockets.h"
-#include "slirp/libslirp.h"
+#include <libslirp.h>
 #include "chardev/char-fe.h"
 #include "sysemu/sysemu.h"
 #include "qemu/cutils.h"
 #include "qapi/error.h"
 #include "qapi/qmp/qdict.h"
 #include "util.h"
+#include "migration/register.h"
+#include "migration/qemu-file-types.h"
 
 static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
 {
@@ -146,6 +148,7 @@ static void net_slirp_cleanup(NetClientState *nc)
 
     g_slist_free_full(s->fwd, slirp_free_fwd);
     main_loop_poll_remove_notifier(&s->poll_notifier);
+    unregister_savevm(NULL, "slirp", s->slirp);
     slirp_cleanup(s->slirp);
     if (s->exit_notifier.notify) {
         qemu_remove_exit_notifier(&s->exit_notifier);
@@ -303,6 +306,46 @@ static void net_slirp_poll_notify(Notifier *notifier, void *data)
     }
 }
 
+static ssize_t
+net_slirp_stream_read(void *buf, size_t size, void *opaque)
+{
+    QEMUFile *f = opaque;
+
+    return qemu_get_buffer(f, buf, size);
+}
+
+static ssize_t
+net_slirp_stream_write(const void *buf, size_t size, void *opaque)
+{
+    QEMUFile *f = opaque;
+
+    qemu_put_buffer(f, buf, size);
+    if (qemu_file_get_error(f)) {
+        return -1;
+    }
+
+    return size;
+}
+
+static int net_slirp_state_load(QEMUFile *f, void *opaque, int version_id)
+{
+    Slirp *slirp = opaque;
+
+    return slirp_state_load(slirp, version_id, net_slirp_stream_read, f);
+}
+
+static void net_slirp_state_save(QEMUFile *f, void *opaque)
+{
+    Slirp *slirp = opaque;
+
+    slirp_state_save(slirp, net_slirp_stream_write, f);
+}
+
+static SaveVMHandlers savevm_slirp_state = {
+    .save_state = net_slirp_state_save,
+    .load_state = net_slirp_state_load,
+};
+
 static int net_slirp_init(NetClientState *peer, const char *model,
                           const char *name, int restricted,
                           bool ipv4, const char *vnetwork, const char *vhost,
@@ -523,6 +566,18 @@ static int net_slirp_init(NetClientState *peer, const char *model,
                           &slirp_cb, s);
     QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
 
+    /*
+     * Make sure the current bitstream version of slirp is 4, to avoid
+     * QEMU migration incompatibilities, if upstream slirp bumped the
+     * version.
+     *
+     * FIXME: use bitfields of features? teach libslirp to save with
+     * specific version?
+     */
+    g_assert(slirp_state_version() == 4);
+    register_savevm_live(NULL, "slirp", 0, slirp_state_version(),
+                         &savevm_slirp_state, s->slirp);
+
     s->poll_notifier.notify = net_slirp_poll_notify;
     main_loop_poll_add_notifier(&s->poll_notifier);
 
@@ -885,6 +940,7 @@ static ssize_t guestfwd_write(const void *buf, size_t len, void *chr)
 
 static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp)
 {
+    /* TODO: IPv6 */
     struct in_addr server = { .s_addr = 0 };
     struct GuestFwd *fwd;
     const char *p;
diff --git a/python/qemu/__init__.py b/python/qemu/__init__.py
new file mode 100644 (file)
index 0000000..fd144c0
--- /dev/null
@@ -0,0 +1,518 @@
+# QEMU library
+#
+# Copyright (C) 2015-2016 Red Hat Inc.
+# Copyright (C) 2012 IBM Corp.
+#
+# Authors:
+#  Fam Zheng <famz@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+#
+# Based on qmp.py.
+#
+
+import errno
+import logging
+import os
+import subprocess
+import re
+import shutil
+import socket
+import tempfile
+
+from . import qmp
+
+
+LOG = logging.getLogger(__name__)
+
+# Mapping host architecture to any additional architectures it can
+# support which often includes its 32 bit cousin.
+ADDITIONAL_ARCHES = {
+    "x86_64" : "i386",
+    "aarch64" : "armhf"
+}
+
+def kvm_available(target_arch=None):
+    host_arch = os.uname()[4]
+    if target_arch and target_arch != host_arch:
+        if target_arch != ADDITIONAL_ARCHES.get(host_arch):
+            return False
+    return os.access("/dev/kvm", os.R_OK | os.W_OK)
+
+
+#: Maps machine types to the preferred console device types
+CONSOLE_DEV_TYPES = {
+    r'^clipper$': 'isa-serial',
+    r'^malta': 'isa-serial',
+    r'^(pc.*|q35.*|isapc)$': 'isa-serial',
+    r'^(40p|powernv|prep)$': 'isa-serial',
+    r'^pseries.*': 'spapr-vty',
+    r'^s390-ccw-virtio.*': 'sclpconsole',
+    }
+
+
+class QEMUMachineError(Exception):
+    """
+    Exception called when an error in QEMUMachine happens.
+    """
+
+
+class QEMUMachineAddDeviceError(QEMUMachineError):
+    """
+    Exception raised when a request to add a device can not be fulfilled
+
+    The failures are caused by limitations, lack of information or conflicting
+    requests on the QEMUMachine methods.  This exception does not represent
+    failures reported by the QEMU binary itself.
+    """
+
+class MonitorResponseError(qmp.QMPError):
+    """
+    Represents erroneous QMP monitor reply
+    """
+    def __init__(self, reply):
+        try:
+            desc = reply["error"]["desc"]
+        except KeyError:
+            desc = reply
+        super(MonitorResponseError, self).__init__(desc)
+        self.reply = reply
+
+
+class QEMUMachine(object):
+    """
+    A QEMU VM
+
+    Use this object as a context manager to ensure the QEMU process terminates::
+
+        with VM(binary) as vm:
+            ...
+        # vm is guaranteed to be shut down here
+    """
+
+    def __init__(self, binary, args=None, wrapper=None, name=None,
+                 test_dir="/var/tmp", monitor_address=None,
+                 socket_scm_helper=None):
+        '''
+        Initialize a QEMUMachine
+
+        @param binary: path to the qemu binary
+        @param args: list of extra arguments
+        @param wrapper: list of arguments used as prefix to qemu binary
+        @param name: prefix for socket and log file names (default: qemu-PID)
+        @param test_dir: where to create socket and log file
+        @param monitor_address: address for QMP monitor
+        @param socket_scm_helper: helper program, required for send_fd_scm()
+        @note: Qemu process is not started until launch() is used.
+        '''
+        if args is None:
+            args = []
+        if wrapper is None:
+            wrapper = []
+        if name is None:
+            name = "qemu-%d" % os.getpid()
+        self._name = name
+        self._monitor_address = monitor_address
+        self._vm_monitor = None
+        self._qemu_log_path = None
+        self._qemu_log_file = None
+        self._popen = None
+        self._binary = binary
+        self._args = list(args)     # Force copy args in case we modify them
+        self._wrapper = wrapper
+        self._events = []
+        self._iolog = None
+        self._socket_scm_helper = socket_scm_helper
+        self._qmp = None
+        self._qemu_full_args = None
+        self._test_dir = test_dir
+        self._temp_dir = None
+        self._launched = False
+        self._machine = None
+        self._console_device_type = None
+        self._console_address = None
+        self._console_socket = None
+
+        # just in case logging wasn't configured by the main script:
+        logging.basicConfig()
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        self.shutdown()
+        return False
+
+    # This can be used to add an unused monitor instance.
+    def add_monitor_null(self):
+        self._args.append('-monitor')
+        self._args.append('null')
+
+    def add_fd(self, fd, fdset, opaque, opts=''):
+        """
+        Pass a file descriptor to the VM
+        """
+        options = ['fd=%d' % fd,
+                   'set=%d' % fdset,
+                   'opaque=%s' % opaque]
+        if opts:
+            options.append(opts)
+
+        # This did not exist before 3.4, but since then it is
+        # mandatory for our purpose
+        if hasattr(os, 'set_inheritable'):
+            os.set_inheritable(fd, True)
+
+        self._args.append('-add-fd')
+        self._args.append(','.join(options))
+        return self
+
+    # Exactly one of fd and file_path must be given.
+    # (If it is file_path, the helper will open that file and pass its
+    # own fd)
+    def send_fd_scm(self, fd=None, file_path=None):
+        # In iotest.py, the qmp should always use unix socket.
+        assert self._qmp.is_scm_available()
+        if self._socket_scm_helper is None:
+            raise QEMUMachineError("No path to socket_scm_helper set")
+        if not os.path.exists(self._socket_scm_helper):
+            raise QEMUMachineError("%s does not exist" %
+                                   self._socket_scm_helper)
+
+        # This did not exist before 3.4, but since then it is
+        # mandatory for our purpose
+        if hasattr(os, 'set_inheritable'):
+            os.set_inheritable(self._qmp.get_sock_fd(), True)
+            if fd is not None:
+                os.set_inheritable(fd, True)
+
+        fd_param = ["%s" % self._socket_scm_helper,
+                    "%d" % self._qmp.get_sock_fd()]
+
+        if file_path is not None:
+            assert fd is None
+            fd_param.append(file_path)
+        else:
+            assert fd is not None
+            fd_param.append(str(fd))
+
+        devnull = open(os.path.devnull, 'rb')
+        proc = subprocess.Popen(fd_param, stdin=devnull, stdout=subprocess.PIPE,
+                                stderr=subprocess.STDOUT, close_fds=False)
+        output = proc.communicate()[0]
+        if output:
+            LOG.debug(output)
+
+        return proc.returncode
+
+    @staticmethod
+    def _remove_if_exists(path):
+        """
+        Remove file object at path if it exists
+        """
+        try:
+            os.remove(path)
+        except OSError as exception:
+            if exception.errno == errno.ENOENT:
+                return
+            raise
+
+    def is_running(self):
+        return self._popen is not None and self._popen.poll() is None
+
+    def exitcode(self):
+        if self._popen is None:
+            return None
+        return self._popen.poll()
+
+    def get_pid(self):
+        if not self.is_running():
+            return None
+        return self._popen.pid
+
+    def _load_io_log(self):
+        if self._qemu_log_path is not None:
+            with open(self._qemu_log_path, "r") as iolog:
+                self._iolog = iolog.read()
+
+    def _base_args(self):
+        if isinstance(self._monitor_address, tuple):
+            moncdev = "socket,id=mon,host=%s,port=%s" % (
+                self._monitor_address[0],
+                self._monitor_address[1])
+        else:
+            moncdev = 'socket,id=mon,path=%s' % self._vm_monitor
+        args = ['-chardev', moncdev,
+                '-mon', 'chardev=mon,mode=control',
+                '-display', 'none', '-vga', 'none']
+        if self._machine is not None:
+            args.extend(['-machine', self._machine])
+        if self._console_device_type is not None:
+            self._console_address = os.path.join(self._temp_dir,
+                                                 self._name + "-console.sock")
+            chardev = ('socket,id=console,path=%s,server,nowait' %
+                       self._console_address)
+            device = '%s,chardev=console' % self._console_device_type
+            args.extend(['-chardev', chardev, '-device', device])
+        return args
+
+    def _pre_launch(self):
+        self._temp_dir = tempfile.mkdtemp(dir=self._test_dir)
+        if self._monitor_address is not None:
+            self._vm_monitor = self._monitor_address
+        else:
+            self._vm_monitor = os.path.join(self._temp_dir,
+                                            self._name + "-monitor.sock")
+        self._qemu_log_path = os.path.join(self._temp_dir, self._name + ".log")
+        self._qemu_log_file = open(self._qemu_log_path, 'wb')
+
+        self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor,
+                                            server=True)
+
+    def _post_launch(self):
+        self._qmp.accept()
+
+    def _post_shutdown(self):
+        if self._qemu_log_file is not None:
+            self._qemu_log_file.close()
+            self._qemu_log_file = None
+
+        self._qemu_log_path = None
+
+        if self._console_socket is not None:
+            self._console_socket.close()
+            self._console_socket = None
+
+        if self._temp_dir is not None:
+            shutil.rmtree(self._temp_dir)
+            self._temp_dir = None
+
+    def launch(self):
+        """
+        Launch the VM and make sure we cleanup and expose the
+        command line/output in case of exception
+        """
+
+        if self._launched:
+            raise QEMUMachineError('VM already launched')
+
+        self._iolog = None
+        self._qemu_full_args = None
+        try:
+            self._launch()
+            self._launched = True
+        except:
+            self.shutdown()
+
+            LOG.debug('Error launching VM')
+            if self._qemu_full_args:
+                LOG.debug('Command: %r', ' '.join(self._qemu_full_args))
+            if self._iolog:
+                LOG.debug('Output: %r', self._iolog)
+            raise
+
+    def _launch(self):
+        """
+        Launch the VM and establish a QMP connection
+        """
+        devnull = open(os.path.devnull, 'rb')
+        self._pre_launch()
+        self._qemu_full_args = (self._wrapper + [self._binary] +
+                                self._base_args() + self._args)
+        LOG.debug('VM launch command: %r', ' '.join(self._qemu_full_args))
+        self._popen = subprocess.Popen(self._qemu_full_args,
+                                       stdin=devnull,
+                                       stdout=self._qemu_log_file,
+                                       stderr=subprocess.STDOUT,
+                                       shell=False,
+                                       close_fds=False)
+        self._post_launch()
+
+    def wait(self):
+        """
+        Wait for the VM to power off
+        """
+        self._popen.wait()
+        self._qmp.close()
+        self._load_io_log()
+        self._post_shutdown()
+
+    def shutdown(self):
+        """
+        Terminate the VM and clean up
+        """
+        if self.is_running():
+            try:
+                self._qmp.cmd('quit')
+                self._qmp.close()
+            except:
+                self._popen.kill()
+            self._popen.wait()
+
+        self._load_io_log()
+        self._post_shutdown()
+
+        exitcode = self.exitcode()
+        if exitcode is not None and exitcode < 0:
+            msg = 'qemu received signal %i: %s'
+            if self._qemu_full_args:
+                command = ' '.join(self._qemu_full_args)
+            else:
+                command = ''
+            LOG.warn(msg, -exitcode, command)
+
+        self._launched = False
+
+    def qmp(self, cmd, conv_keys=True, **args):
+        """
+        Invoke a QMP command and return the response dict
+        """
+        qmp_args = dict()
+        for key, value in args.items():
+            if conv_keys:
+                qmp_args[key.replace('_', '-')] = value
+            else:
+                qmp_args[key] = value
+
+        return self._qmp.cmd(cmd, args=qmp_args)
+
+    def command(self, cmd, conv_keys=True, **args):
+        """
+        Invoke a QMP command.
+        On success return the response dict.
+        On failure raise an exception.
+        """
+        reply = self.qmp(cmd, conv_keys, **args)
+        if reply is None:
+            raise qmp.QMPError("Monitor is closed")
+        if "error" in reply:
+            raise MonitorResponseError(reply)
+        return reply["return"]
+
+    def get_qmp_event(self, wait=False):
+        """
+        Poll for one queued QMP events and return it
+        """
+        if len(self._events) > 0:
+            return self._events.pop(0)
+        return self._qmp.pull_event(wait=wait)
+
+    def get_qmp_events(self, wait=False):
+        """
+        Poll for queued QMP events and return a list of dicts
+        """
+        events = self._qmp.get_events(wait=wait)
+        events.extend(self._events)
+        del self._events[:]
+        self._qmp.clear_events()
+        return events
+
+    def event_wait(self, name, timeout=60.0, match=None):
+        """
+        Wait for specified timeout on named event in QMP; optionally filter
+        results by match.
+
+        The 'match' is checked to be a recursive subset of the 'event'; skips
+        branch processing on match's value None
+           {"foo": {"bar": 1}} matches {"foo": None}
+           {"foo": {"bar": 1}} does not matches {"foo": {"baz": None}}
+        """
+        def event_match(event, match=None):
+            if match is None:
+                return True
+
+            for key in match:
+                if key in event:
+                    if isinstance(event[key], dict):
+                        if not event_match(event[key], match[key]):
+                            return False
+                    elif event[key] != match[key]:
+                        return False
+                else:
+                    return False
+
+            return True
+
+        # Search cached events
+        for event in self._events:
+            if (event['event'] == name) and event_match(event, match):
+                self._events.remove(event)
+                return event
+
+        # Poll for new events
+        while True:
+            event = self._qmp.pull_event(wait=timeout)
+            if (event['event'] == name) and event_match(event, match):
+                return event
+            self._events.append(event)
+
+        return None
+
+    def get_log(self):
+        """
+        After self.shutdown or failed qemu execution, this returns the output
+        of the qemu process.
+        """
+        return self._iolog
+
+    def add_args(self, *args):
+        """
+        Adds to the list of extra arguments to be given to the QEMU binary
+        """
+        self._args.extend(args)
+
+    def set_machine(self, machine_type):
+        """
+        Sets the machine type
+
+        If set, the machine type will be added to the base arguments
+        of the resulting QEMU command line.
+        """
+        self._machine = machine_type
+
+    def set_console(self, device_type=None):
+        """
+        Sets the device type for a console device
+
+        If set, the console device and a backing character device will
+        be added to the base arguments of the resulting QEMU command
+        line.
+
+        This is a convenience method that will either use the provided
+        device type, of if not given, it will used the device type set
+        on CONSOLE_DEV_TYPES.
+
+        The actual setting of command line arguments will be be done at
+        machine launch time, as it depends on the temporary directory
+        to be created.
+
+        @param device_type: the device type, such as "isa-serial"
+        @raises: QEMUMachineAddDeviceError if the device type is not given
+                 and can not be determined.
+        """
+        if device_type is None:
+            if self._machine is None:
+                raise QEMUMachineAddDeviceError("Can not add a console device:"
+                                                " QEMU instance without a "
+                                                "defined machine type")
+            for regex, device in CONSOLE_DEV_TYPES.items():
+                if re.match(regex, self._machine):
+                    device_type = device
+                    break
+            if device_type is None:
+                raise QEMUMachineAddDeviceError("Can not add a console device:"
+                                                " no matching console device "
+                                                "type definition")
+        self._console_device_type = device_type
+
+    @property
+    def console_socket(self):
+        """
+        Returns a socket connected to the console
+        """
+        if self._console_socket is None:
+            self._console_socket = socket.socket(socket.AF_UNIX,
+                                                 socket.SOCK_STREAM)
+            self._console_socket.connect(self._console_address)
+        return self._console_socket
diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py
new file mode 100644 (file)
index 0000000..5c8cf6a
--- /dev/null
@@ -0,0 +1,256 @@
+# QEMU Monitor Protocol Python class
+#
+# Copyright (C) 2009, 2010 Red Hat Inc.
+#
+# Authors:
+#  Luiz Capitulino <lcapitulino@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+
+import json
+import errno
+import socket
+import logging
+
+
+class QMPError(Exception):
+    pass
+
+
+class QMPConnectError(QMPError):
+    pass
+
+
+class QMPCapabilitiesError(QMPError):
+    pass
+
+
+class QMPTimeoutError(QMPError):
+    pass
+
+
+class QEMUMonitorProtocol(object):
+
+    #: Logger object for debugging messages
+    logger = logging.getLogger('QMP')
+    #: Socket's error class
+    error = socket.error
+    #: Socket's timeout
+    timeout = socket.timeout
+
+    def __init__(self, address, server=False):
+        """
+        Create a QEMUMonitorProtocol class.
+
+        @param address: QEMU address, can be either a unix socket path (string)
+                        or a tuple in the form ( address, port ) for a TCP
+                        connection
+        @param server: server mode listens on the socket (bool)
+        @raise socket.error on socket connection errors
+        @note No connection is established, this is done by the connect() or
+              accept() methods
+        """
+        self.__events = []
+        self.__address = address
+        self.__sock = self.__get_sock()
+        self.__sockfile = None
+        if server:
+            self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+            self.__sock.bind(self.__address)
+            self.__sock.listen(1)
+
+    def __get_sock(self):
+        if isinstance(self.__address, tuple):
+            family = socket.AF_INET
+        else:
+            family = socket.AF_UNIX
+        return socket.socket(family, socket.SOCK_STREAM)
+
+    def __negotiate_capabilities(self):
+        greeting = self.__json_read()
+        if greeting is None or "QMP" not in greeting:
+            raise QMPConnectError
+        # Greeting seems ok, negotiate capabilities
+        resp = self.cmd('qmp_capabilities')
+        if "return" in resp:
+            return greeting
+        raise QMPCapabilitiesError
+
+    def __json_read(self, only_event=False):
+        while True:
+            data = self.__sockfile.readline()
+            if not data:
+                return
+            resp = json.loads(data)
+            if 'event' in resp:
+                self.logger.debug("<<< %s", resp)
+                self.__events.append(resp)
+                if not only_event:
+                    continue
+            return resp
+
+    def __get_events(self, wait=False):
+        """
+        Check for new events in the stream and cache them in __events.
+
+        @param wait (bool): block until an event is available.
+        @param wait (float): If wait is a float, treat it as a timeout value.
+
+        @raise QMPTimeoutError: If a timeout float is provided and the timeout
+                                period elapses.
+        @raise QMPConnectError: If wait is True but no events could be
+                                retrieved or if some other error occurred.
+        """
+
+        # Check for new events regardless and pull them into the cache:
+        self.__sock.setblocking(0)
+        try:
+            self.__json_read()
+        except socket.error as err:
+            if err[0] == errno.EAGAIN:
+                # No data available
+                pass
+        self.__sock.setblocking(1)
+
+        # Wait for new events, if needed.
+        # if wait is 0.0, this means "no wait" and is also implicitly false.
+        if not self.__events and wait:
+            if isinstance(wait, float):
+                self.__sock.settimeout(wait)
+            try:
+                ret = self.__json_read(only_event=True)
+            except socket.timeout:
+                raise QMPTimeoutError("Timeout waiting for event")
+            except:
+                raise QMPConnectError("Error while reading from socket")
+            if ret is None:
+                raise QMPConnectError("Error while reading from socket")
+            self.__sock.settimeout(None)
+
+    def connect(self, negotiate=True):
+        """
+        Connect to the QMP Monitor and perform capabilities negotiation.
+
+        @return QMP greeting dict
+        @raise socket.error on socket connection errors
+        @raise QMPConnectError if the greeting is not received
+        @raise QMPCapabilitiesError if fails to negotiate capabilities
+        """
+        self.__sock.connect(self.__address)
+        self.__sockfile = self.__sock.makefile()
+        if negotiate:
+            return self.__negotiate_capabilities()
+
+    def accept(self):
+        """
+        Await connection from QMP Monitor and perform capabilities negotiation.
+
+        @return QMP greeting dict
+        @raise socket.error on socket connection errors
+        @raise QMPConnectError if the greeting is not received
+        @raise QMPCapabilitiesError if fails to negotiate capabilities
+        """
+        self.__sock.settimeout(15)
+        self.__sock, _ = self.__sock.accept()
+        self.__sockfile = self.__sock.makefile()
+        return self.__negotiate_capabilities()
+
+    def cmd_obj(self, qmp_cmd):
+        """
+        Send a QMP command to the QMP Monitor.
+
+        @param qmp_cmd: QMP command to be sent as a Python dict
+        @return QMP response as a Python dict or None if the connection has
+                been closed
+        """
+        self.logger.debug(">>> %s", qmp_cmd)
+        try:
+            self.__sock.sendall(json.dumps(qmp_cmd).encode('utf-8'))
+        except socket.error as err:
+            if err[0] == errno.EPIPE:
+                return
+            raise socket.error(err)
+        resp = self.__json_read()
+        self.logger.debug("<<< %s", resp)
+        return resp
+
+    def cmd(self, name, args=None, cmd_id=None):
+        """
+        Build a QMP command and send it to the QMP Monitor.
+
+        @param name: command name (string)
+        @param args: command arguments (dict)
+        @param cmd_id: command id (dict, list, string or int)
+        """
+        qmp_cmd = {'execute': name}
+        if args:
+            qmp_cmd['arguments'] = args
+        if cmd_id:
+            qmp_cmd['id'] = cmd_id
+        return self.cmd_obj(qmp_cmd)
+
+    def command(self, cmd, **kwds):
+        """
+        Build and send a QMP command to the monitor, report errors if any
+        """
+        ret = self.cmd(cmd, kwds)
+        if "error" in ret:
+            raise Exception(ret['error']['desc'])
+        return ret['return']
+
+    def pull_event(self, wait=False):
+        """
+        Pulls a single event.
+
+        @param wait (bool): block until an event is available.
+        @param wait (float): If wait is a float, treat it as a timeout value.
+
+        @raise QMPTimeoutError: If a timeout float is provided and the timeout
+                                period elapses.
+        @raise QMPConnectError: If wait is True but no events could be
+                                retrieved or if some other error occurred.
+
+        @return The first available QMP event, or None.
+        """
+        self.__get_events(wait)
+
+        if self.__events:
+            return self.__events.pop(0)
+        return None
+
+    def get_events(self, wait=False):
+        """
+        Get a list of available QMP events.
+
+        @param wait (bool): block until an event is available.
+        @param wait (float): If wait is a float, treat it as a timeout value.
+
+        @raise QMPTimeoutError: If a timeout float is provided and the timeout
+                                period elapses.
+        @raise QMPConnectError: If wait is True but no events could be
+                                retrieved or if some other error occurred.
+
+        @return The list of available QMP events.
+        """
+        self.__get_events(wait)
+        return self.__events
+
+    def clear_events(self):
+        """
+        Clear current list of pending events.
+        """
+        self.__events = []
+
+    def close(self):
+        self.__sock.close()
+        self.__sockfile.close()
+
+    def settimeout(self, timeout):
+        self.__sock.settimeout(timeout)
+
+    def get_sock_fd(self):
+        return self.__sock.fileno()
+
+    def is_scm_available(self):
+        return self.__sock.family == socket.AF_UNIX
diff --git a/python/qemu/qtest.py b/python/qemu/qtest.py
new file mode 100644 (file)
index 0000000..eb45824
--- /dev/null
@@ -0,0 +1,116 @@
+# QEMU qtest library
+#
+# Copyright (C) 2015 Red Hat Inc.
+#
+# Authors:
+#  Fam Zheng <famz@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+#
+# Based on qmp.py.
+#
+
+import socket
+import os
+
+from . import QEMUMachine
+
+
+class QEMUQtestProtocol(object):
+    def __init__(self, address, server=False):
+        """
+        Create a QEMUQtestProtocol object.
+
+        @param address: QEMU address, can be either a unix socket path (string)
+                        or a tuple in the form ( address, port ) for a TCP
+                        connection
+        @param server: server mode, listens on the socket (bool)
+        @raise socket.error on socket connection errors
+        @note No connection is established, this is done by the connect() or
+              accept() methods
+        """
+        self._address = address
+        self._sock = self._get_sock()
+        self._sockfile = None
+        if server:
+            self._sock.bind(self._address)
+            self._sock.listen(1)
+
+    def _get_sock(self):
+        if isinstance(self._address, tuple):
+            family = socket.AF_INET
+        else:
+            family = socket.AF_UNIX
+        return socket.socket(family, socket.SOCK_STREAM)
+
+    def connect(self):
+        """
+        Connect to the qtest socket.
+
+        @raise socket.error on socket connection errors
+        """
+        self._sock.connect(self._address)
+        self._sockfile = self._sock.makefile()
+
+    def accept(self):
+        """
+        Await connection from QEMU.
+
+        @raise socket.error on socket connection errors
+        """
+        self._sock, _ = self._sock.accept()
+        self._sockfile = self._sock.makefile()
+
+    def cmd(self, qtest_cmd):
+        """
+        Send a qtest command on the wire.
+
+        @param qtest_cmd: qtest command text to be sent
+        """
+        self._sock.sendall((qtest_cmd + "\n").encode('utf-8'))
+        resp = self._sockfile.readline()
+        return resp
+
+    def close(self):
+        self._sock.close()
+        self._sockfile.close()
+
+    def settimeout(self, timeout):
+        self._sock.settimeout(timeout)
+
+
+class QEMUQtestMachine(QEMUMachine):
+    '''A QEMU VM'''
+
+    def __init__(self, binary, args=None, name=None, test_dir="/var/tmp",
+                 socket_scm_helper=None):
+        if name is None:
+            name = "qemu-%d" % os.getpid()
+        super(QEMUQtestMachine,
+              self).__init__(binary, args, name=name, test_dir=test_dir,
+                             socket_scm_helper=socket_scm_helper)
+        self._qtest = None
+        self._qtest_path = os.path.join(test_dir, name + "-qtest.sock")
+
+    def _base_args(self):
+        args = super(QEMUQtestMachine, self)._base_args()
+        args.extend(['-qtest', 'unix:path=' + self._qtest_path,
+                     '-machine', 'accel=qtest'])
+        return args
+
+    def _pre_launch(self):
+        super(QEMUQtestMachine, self)._pre_launch()
+        self._qtest = QEMUQtestProtocol(self._qtest_path, server=True)
+
+    def _post_launch(self):
+        super(QEMUQtestMachine, self)._post_launch()
+        self._qtest.accept()
+
+    def _post_shutdown(self):
+        super(QEMUQtestMachine, self)._post_shutdown()
+        self._remove_if_exists(self._qtest_path)
+
+    def qtest(self, cmd):
+        '''Send a qtest command to guest'''
+        return self._qtest.cmd(cmd)
index 19f3d2c1261d47305bdffe4017c42d55694b2288..df45bcffb4821ab766ae6fa85095edb6b2d7a0ba 100644 (file)
--- a/rules.mak
+++ b/rules.mak
@@ -144,7 +144,7 @@ cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \
 cc-c-option = $(if $(shell $(CC) $1 $2 -c -o /dev/null -xc /dev/null \
                 >/dev/null 2>&1 && echo OK), $2, $3)
 
-VPATH_SUFFIXES = %.c %.h %.S %.cc %.cpp %.m %.mak %.texi %.sh %.rc
+VPATH_SUFFIXES = %.c %.h %.S %.cc %.cpp %.m %.mak %.texi %.sh %.rc Kconfig%
 set-vpath = $(if $1,$(foreach PATTERN,$(VPATH_SUFFIXES),$(eval vpath $(PATTERN) $1)))
 
 # install-prog list, dir
index 2a13fa4f848fb6c04e90bdecb23bb8a1374c60dc..a6748910ad2eb0afa94acab4e0cf27212a3f6c7d 100755 (executable)
@@ -25,6 +25,7 @@ check for crashes and unexpected errors.
 """
 from __future__ import print_function
 
+import os
 import sys
 import glob
 import logging
@@ -34,6 +35,7 @@ import random
 import argparse
 from itertools import chain
 
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
 from qemu import QEMUMachine
 
 logger = logging.getLogger('device-crash-test')
diff --git a/scripts/make_device_config.sh b/scripts/make_device_config.sh
deleted file mode 100644 (file)
index 354af31..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#! /bin/sh
-# Writes a target device config file to stdout, from a default and from
-# include directives therein.  Also emits Makefile dependencies.
-#
-# Usage: make_device_config.sh SRC DEPFILE-NAME DEPFILE-TARGET > DEST
-
-src=$1
-dep=$2
-target=$3
-src_dir=$(dirname $src)
-all_includes=
-
-process_includes () {
-  cat $1 | grep '^include' | \
-  while read include file ; do
-    all_includes="$all_includes $src_dir/$file"
-    process_includes $src_dir/$file
-  done
-}
-
-f=$src
-while [ -n "$f" ] ; do
-  f=$(cat $f | tr -d '\r' | awk '/^include / {printf "'$src_dir'/%s ", $2}')
-  [ $? = 0 ] || exit 1
-  all_includes="$all_includes $f"
-done
-process_includes $src
-
-cat $src $all_includes | grep -v '^include'
-echo "$target: $all_includes" > $dep
diff --git a/scripts/minikconf.py b/scripts/minikconf.py
new file mode 100644 (file)
index 0000000..5421db0
--- /dev/null
@@ -0,0 +1,708 @@
+#
+# Mini-Kconfig parser
+#
+# Copyright (c) 2015 Red Hat Inc.
+#
+# Authors:
+#  Paolo Bonzini <pbonzini@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2
+# or, at your option, any later version.  See the COPYING file in
+# the top-level directory.
+
+from __future__ import print_function
+import os
+import sys
+import re
+import random
+
+__all__ = [ 'KconfigDataError', 'KconfigParserError',
+            'KconfigData', 'KconfigParser' ,
+            'defconfig', 'allyesconfig', 'allnoconfig', 'randconfig' ]
+
+def debug_print(*args):
+    #print('# ' + (' '.join(str(x) for x in args)))
+    pass
+
+# -------------------------------------------
+# KconfigData implements the Kconfig semantics.  For now it can only
+# detect undefined symbols, i.e. symbols that were referenced in
+# assignments or dependencies but were not declared with "config FOO".
+#
+# Semantic actions are represented by methods called do_*.  The do_var
+# method return the semantic value of a variable (which right now is
+# just its name).
+# -------------------------------------------
+
+class KconfigDataError(Exception):
+    def __init__(self, msg):
+        self.msg = msg
+
+    def __str__(self):
+        return self.msg
+
+allyesconfig = lambda x: True
+allnoconfig = lambda x: False
+defconfig = lambda x: x
+randconfig = lambda x: random.randint(0, 1) == 1
+
+class KconfigData:
+    class Expr:
+        def __and__(self, rhs):
+            return KconfigData.AND(self, rhs)
+        def __or__(self, rhs):
+            return KconfigData.OR(self, rhs)
+        def __invert__(self):
+            return KconfigData.NOT(self)
+
+        # Abstract methods
+        def add_edges_to(self, var):
+            pass
+        def evaluate(self):
+            assert False
+
+    class AND(Expr):
+        def __init__(self, lhs, rhs):
+            self.lhs = lhs
+            self.rhs = rhs
+        def __str__(self):
+            return "(%s && %s)" % (self.lhs, self.rhs)
+
+        def add_edges_to(self, var):
+            self.lhs.add_edges_to(var)
+            self.rhs.add_edges_to(var)
+        def evaluate(self):
+            return self.lhs.evaluate() and self.rhs.evaluate()
+
+    class OR(Expr):
+        def __init__(self, lhs, rhs):
+            self.lhs = lhs
+            self.rhs = rhs
+        def __str__(self):
+            return "(%s || %s)" % (self.lhs, self.rhs)
+
+        def add_edges_to(self, var):
+            self.lhs.add_edges_to(var)
+            self.rhs.add_edges_to(var)
+        def evaluate(self):
+            return self.lhs.evaluate() or self.rhs.evaluate()
+
+    class NOT(Expr):
+        def __init__(self, lhs):
+            self.lhs = lhs
+        def __str__(self):
+            return "!%s" % (self.lhs)
+
+        def add_edges_to(self, var):
+            self.lhs.add_edges_to(var)
+        def evaluate(self):
+            return not self.lhs.evaluate()
+
+    class Var(Expr):
+        def __init__(self, name):
+            self.name = name
+            self.value = None
+            self.outgoing = set()
+            self.clauses_for_var = list()
+        def __str__(self):
+            return self.name
+
+        def has_value(self):
+            return not (self.value is None)
+        def set_value(self, val, clause):
+            self.clauses_for_var.append(clause)
+            if self.has_value() and self.value != val:
+                print("The following clauses were found for " + self.name)
+                for i in self.clauses_for_var:
+                    print("    " + str(i), file=sys.stderr)
+                raise KconfigDataError('contradiction between clauses when setting %s' % self)
+            debug_print("=> %s is now %s" % (self.name, val))
+            self.value = val
+
+        # depth first search of the dependency graph
+        def dfs(self, visited, f):
+            if self in visited:
+                return
+            visited.add(self)
+            for v in self.outgoing:
+                v.dfs(visited, f)
+            f(self)
+
+        def add_edges_to(self, var):
+            self.outgoing.add(var)
+        def evaluate(self):
+            if not self.has_value():
+                raise KconfigDataError('cycle found including %s' % self)
+            return self.value
+
+    class Clause:
+        def __init__(self, dest):
+            self.dest = dest
+        def priority(self):
+            return 0
+        def process(self):
+            pass
+
+    class AssignmentClause(Clause):
+        def __init__(self, dest, value):
+            KconfigData.Clause.__init__(self, dest)
+            self.value = value
+        def __str__(self):
+            return "CONFIG_%s=%s" % (self.dest, 'y' if self.value else 'n')
+
+        def process(self):
+            self.dest.set_value(self.value, self)
+
+    class DefaultClause(Clause):
+        def __init__(self, dest, value, cond=None):
+            KconfigData.Clause.__init__(self, dest)
+            self.value = value
+            self.cond = cond
+            if not (self.cond is None):
+                self.cond.add_edges_to(self.dest)
+        def __str__(self):
+            value = 'y' if self.value else 'n'
+            if self.cond is None:
+                return "config %s default %s" % (self.dest, value)
+            else:
+                return "config %s default %s if %s" % (self.dest, value, self.cond)
+
+        def priority(self):
+            # Defaults are processed just before leaving the variable
+            return -1
+        def process(self):
+            if not self.dest.has_value() and \
+                    (self.cond is None or self.cond.evaluate()):
+                self.dest.set_value(self.value, self)
+
+    class DependsOnClause(Clause):
+        def __init__(self, dest, expr):
+            KconfigData.Clause.__init__(self, dest)
+            self.expr = expr
+            self.expr.add_edges_to(self.dest)
+        def __str__(self):
+            return "config %s depends on %s" % (self.dest, self.expr)
+
+        def process(self):
+            if not self.expr.evaluate():
+                self.dest.set_value(False, self)
+
+    class SelectClause(Clause):
+        def __init__(self, dest, cond):
+            KconfigData.Clause.__init__(self, dest)
+            self.cond = cond
+            self.cond.add_edges_to(self.dest)
+        def __str__(self):
+            return "select %s if %s" % (self.dest, self.cond)
+
+        def process(self):
+            if self.cond.evaluate():
+                self.dest.set_value(True, self)
+
+    def __init__(self, value_mangler=defconfig):
+        self.value_mangler = value_mangler
+        self.previously_included = []
+        self.incl_info = None
+        self.defined_vars = set()
+        self.referenced_vars = dict()
+        self.clauses = list()
+
+    # semantic analysis -------------
+
+    def check_undefined(self):
+        undef = False
+        for i in self.referenced_vars:
+            if not (i in self.defined_vars):
+                print("undefined symbol %s" % (i), file=sys.stderr)
+                undef = True
+        return undef
+
+    def compute_config(self):
+        if self.check_undefined():
+            raise KconfigDataError("there were undefined symbols")
+            return None
+
+        debug_print("Input:")
+        for clause in self.clauses:
+            debug_print(clause)
+
+        debug_print("\nDependency graph:")
+        for i in self.referenced_vars:
+            debug_print(i, "->", [str(x) for x in self.referenced_vars[i].outgoing])
+
+        # The reverse of the depth-first order is the topological sort
+        dfo = dict()
+        visited = set()
+        debug_print("\n")
+        def visit_fn(var):
+            debug_print(var, "has DFS number", len(dfo))
+            dfo[var] = len(dfo)
+
+        for name, v in self.referenced_vars.items():
+            self.do_default(v, False)
+            v.dfs(visited, visit_fn)
+
+        # Put higher DFS numbers and higher priorities first.  This
+        # places the clauses in topological order and places defaults
+        # after assignments and dependencies.
+        self.clauses.sort(key=lambda x: (-dfo[x.dest], -x.priority()))
+
+        debug_print("\nSorted clauses:")
+        for clause in self.clauses:
+            debug_print(clause)
+            clause.process()
+
+        debug_print("")
+        values = dict()
+        for name, v in self.referenced_vars.items():
+            debug_print("Evaluating", name)
+            values[name] = v.evaluate()
+
+        return values
+
+    # semantic actions -------------
+
+    def do_declaration(self, var):
+        if (var in self.defined_vars):
+            raise KconfigDataError('variable "' + var + '" defined twice')
+
+        self.defined_vars.add(var.name)
+
+    # var is a string with the variable's name.
+    def do_var(self, var):
+        if (var in self.referenced_vars):
+            return self.referenced_vars[var]
+
+        var_obj = self.referenced_vars[var] = KconfigData.Var(var)
+        return var_obj
+
+    def do_assignment(self, var, val):
+        self.clauses.append(KconfigData.AssignmentClause(var, val))
+
+    def do_default(self, var, val, cond=None):
+        val = self.value_mangler(val)
+        self.clauses.append(KconfigData.DefaultClause(var, val, cond))
+
+    def do_depends_on(self, var, expr):
+        self.clauses.append(KconfigData.DependsOnClause(var, expr))
+
+    def do_select(self, var, symbol, cond=None):
+        cond = (cond & var) if cond is not None else var
+        self.clauses.append(KconfigData.SelectClause(symbol, cond))
+
+    def do_imply(self, var, symbol, cond=None):
+        # "config X imply Y [if COND]" is the same as
+        # "config Y default y if X [&& COND]"
+        cond = (cond & var) if cond is not None else var
+        self.do_default(symbol, True, cond)
+
+# -------------------------------------------
+# KconfigParser implements a recursive descent parser for (simplified)
+# Kconfig syntax.
+# -------------------------------------------
+
+# tokens table
+TOKENS = {}
+TOK_NONE = -1
+TOK_LPAREN = 0;   TOKENS[TOK_LPAREN] = '"("';
+TOK_RPAREN = 1;   TOKENS[TOK_RPAREN] = '")"';
+TOK_EQUAL = 2;    TOKENS[TOK_EQUAL] = '"="';
+TOK_AND = 3;      TOKENS[TOK_AND] = '"&&"';
+TOK_OR = 4;       TOKENS[TOK_OR] = '"||"';
+TOK_NOT = 5;      TOKENS[TOK_NOT] = '"!"';
+TOK_DEPENDS = 6;  TOKENS[TOK_DEPENDS] = '"depends"';
+TOK_ON = 7;       TOKENS[TOK_ON] = '"on"';
+TOK_SELECT = 8;   TOKENS[TOK_SELECT] = '"select"';
+TOK_IMPLY = 9;    TOKENS[TOK_IMPLY] = '"imply"';
+TOK_CONFIG = 10;  TOKENS[TOK_CONFIG] = '"config"';
+TOK_DEFAULT = 11; TOKENS[TOK_DEFAULT] = '"default"';
+TOK_Y = 12;       TOKENS[TOK_Y] = '"y"';
+TOK_N = 13;       TOKENS[TOK_N] = '"n"';
+TOK_SOURCE = 14;  TOKENS[TOK_SOURCE] = '"source"';
+TOK_BOOL = 15;    TOKENS[TOK_BOOL] = '"bool"';
+TOK_IF = 16;      TOKENS[TOK_IF] = '"if"';
+TOK_ID = 17;      TOKENS[TOK_ID] = 'identifier';
+TOK_EOF = 18;     TOKENS[TOK_EOF] = 'end of file';
+
+class KconfigParserError(Exception):
+    def __init__(self, parser, msg, tok=None):
+        self.loc = parser.location()
+        tok = tok or parser.tok
+        if tok != TOK_NONE:
+            location = TOKENS.get(tok, None) or ('"%s"' % tok)
+            msg = '%s before %s' % (msg, location)
+        self.msg = msg
+
+    def __str__(self):
+        return "%s: %s" % (self.loc, self.msg)
+
+class KconfigParser:
+
+    @classmethod
+    def parse(self, fp, mode=None):
+        data = KconfigData(mode or KconfigParser.defconfig)
+        parser = KconfigParser(data)
+        parser.parse_file(fp)
+        return data
+
+    def __init__(self, data):
+        self.data = data
+
+    def parse_file(self, fp):
+        self.abs_fname = os.path.abspath(fp.name)
+        self.fname = fp.name
+        self.data.previously_included.append(self.abs_fname)
+        self.src = fp.read()
+        if self.src == '' or self.src[-1] != '\n':
+            self.src += '\n'
+        self.cursor = 0
+        self.line = 1
+        self.line_pos = 0
+        self.get_token()
+        self.parse_config()
+
+    def do_assignment(self, var, val):
+        if not var.startswith("CONFIG_"):
+            raise Error('assigned variable should start with CONFIG_')
+        var = self.data.do_var(var[7:])
+        self.data.do_assignment(var, val)
+
+    # file management -----
+
+    def error_path(self):
+        inf = self.data.incl_info
+        res = ""
+        while inf:
+            res = ("In file included from %s:%d:\n" % (inf['file'],
+                                                       inf['line'])) + res
+            inf = inf['parent']
+        return res
+
+    def location(self):
+        col = 1
+        for ch in self.src[self.line_pos:self.pos]:
+            if ch == '\t':
+                col += 8 - ((col - 1) % 8)
+            else:
+                col += 1
+        return '%s%s:%d:%d' %(self.error_path(), self.fname, self.line, col)
+
+    def do_include(self, include):
+        incl_abs_fname = os.path.join(os.path.dirname(self.abs_fname),
+                                      include)
+        # catch inclusion cycle
+        inf = self.data.incl_info
+        while inf:
+            if incl_abs_fname == os.path.abspath(inf['file']):
+                raise KconfigParserError(self, "Inclusion loop for %s"
+                                    % include)
+            inf = inf['parent']
+
+        # skip multiple include of the same file
+        if incl_abs_fname in self.data.previously_included:
+            return
+        try:
+            fp = open(incl_abs_fname, 'r')
+        except IOError as e:
+            raise KconfigParserError(self,
+                                '%s: %s' % (e.strerror, include))
+
+        inf = self.data.incl_info
+        self.data.incl_info = { 'file': self.fname, 'line': self.line,
+                'parent': inf }
+        KconfigParser(self.data).parse_file(fp)
+        self.data.incl_info = inf
+
+    # recursive descent parser -----
+
+    # y_or_n: Y | N
+    def parse_y_or_n(self):
+        if self.tok == TOK_Y:
+            self.get_token()
+            return True
+        if self.tok == TOK_N:
+            self.get_token()
+            return False
+        raise KconfigParserError(self, 'Expected "y" or "n"')
+
+    # var: ID
+    def parse_var(self):
+        if self.tok == TOK_ID:
+            val = self.val
+            self.get_token()
+            return self.data.do_var(val)
+        else:
+            raise KconfigParserError(self, 'Expected identifier')
+
+    # assignment_var: ID (starting with "CONFIG_")
+    def parse_assignment_var(self):
+        if self.tok == TOK_ID:
+            val = self.val
+            if not val.startswith("CONFIG_"):
+                raise KconfigParserError(self,
+                           'Expected identifier starting with "CONFIG_"', TOK_NONE)
+            self.get_token()
+            return self.data.do_var(val[7:])
+        else:
+            raise KconfigParserError(self, 'Expected identifier')
+
+    # assignment: var EQUAL y_or_n
+    def parse_assignment(self):
+        var = self.parse_assignment_var()
+        if self.tok != TOK_EQUAL:
+            raise KconfigParserError(self, 'Expected "="')
+        self.get_token()
+        self.data.do_assignment(var, self.parse_y_or_n())
+
+    # primary: NOT primary
+    #       | LPAREN expr RPAREN
+    #       | var
+    def parse_primary(self):
+        if self.tok == TOK_NOT:
+            self.get_token()
+            val = ~self.parse_primary()
+        elif self.tok == TOK_LPAREN:
+            self.get_token()
+            val = self.parse_expr()
+            if self.tok != TOK_RPAREN:
+                raise KconfigParserError(self, 'Expected ")"')
+            self.get_token()
+        elif self.tok == TOK_ID:
+            val = self.parse_var()
+        else:
+            raise KconfigParserError(self, 'Expected "!" or "(" or identifier')
+        return val
+
+    # disj: primary (OR primary)*
+    def parse_disj(self):
+        lhs = self.parse_primary()
+        while self.tok == TOK_OR:
+            self.get_token()
+            lhs = lhs | self.parse_primary()
+        return lhs
+
+    # expr: disj (AND disj)*
+    def parse_expr(self):
+        lhs = self.parse_disj()
+        while self.tok == TOK_AND:
+            self.get_token()
+            lhs = lhs & self.parse_disj()
+        return lhs
+
+    # condition: IF expr
+    #       | empty
+    def parse_condition(self):
+        if self.tok == TOK_IF:
+            self.get_token()
+            return self.parse_expr()
+        else:
+            return None
+
+    # property: DEFAULT y_or_n condition
+    #       | DEPENDS ON expr
+    #       | SELECT var condition
+    #       | BOOL
+    def parse_property(self, var):
+        if self.tok == TOK_DEFAULT:
+            self.get_token()
+            val = self.parse_y_or_n()
+            cond = self.parse_condition()
+            self.data.do_default(var, val, cond)
+        elif self.tok == TOK_DEPENDS:
+            self.get_token()
+            if self.tok != TOK_ON:
+                raise KconfigParserError(self, 'Expected "on"')
+            self.get_token()
+            self.data.do_depends_on(var, self.parse_expr())
+        elif self.tok == TOK_SELECT:
+            self.get_token()
+            symbol = self.parse_var()
+            cond = self.parse_condition()
+            self.data.do_select(var, symbol, cond)
+        elif self.tok == TOK_IMPLY:
+            self.get_token()
+            symbol = self.parse_var()
+            cond = self.parse_condition()
+            self.data.do_imply(var, symbol, cond)
+        elif self.tok == TOK_BOOL:
+            self.get_token()
+        else:
+            raise KconfigParserError(self, 'Error in recursive descent?')
+
+    # properties: properties property
+    #       | /* empty */
+    def parse_properties(self, var):
+        had_default = False
+        while self.tok == TOK_DEFAULT or self.tok == TOK_DEPENDS or \
+              self.tok == TOK_SELECT or self.tok == TOK_BOOL or \
+              self.tok == TOK_IMPLY:
+            self.parse_property(var)
+
+        # for nicer error message
+        if self.tok != TOK_SOURCE and self.tok != TOK_CONFIG and \
+           self.tok != TOK_ID and self.tok != TOK_EOF:
+            raise KconfigParserError(self, 'expected "source", "config", identifier, '
+                    + '"default", "depends on", "imply" or "select"')
+
+    # declaration: config var properties
+    def parse_declaration(self):
+        if self.tok == TOK_CONFIG:
+            self.get_token()
+            var = self.parse_var()
+            self.data.do_declaration(var)
+            self.parse_properties(var)
+        else:
+            raise KconfigParserError(self, 'Error in recursive descent?')
+
+    # clause: SOURCE
+    #       | declaration
+    #       | assignment
+    def parse_clause(self):
+        if self.tok == TOK_SOURCE:
+            val = self.val
+            self.get_token()
+            self.do_include(val)
+        elif self.tok == TOK_CONFIG:
+            self.parse_declaration()
+        elif self.tok == TOK_ID:
+            self.parse_assignment()
+        else:
+            raise KconfigParserError(self, 'expected "source", "config" or identifier')
+
+    # config: clause+ EOF
+    def parse_config(self):
+        while self.tok != TOK_EOF:
+            self.parse_clause()
+        return self.data
+
+    # scanner -----
+
+    def get_token(self):
+        while True:
+            self.tok = self.src[self.cursor]
+            self.pos = self.cursor
+            self.cursor += 1
+
+            self.val = None
+            self.tok = self.scan_token()
+            if self.tok is not None:
+                return
+
+    def check_keyword(self, rest):
+        if not self.src.startswith(rest, self.cursor):
+            return False
+        length = len(rest)
+        if self.src[self.cursor + length].isalnum() or self.src[self.cursor + length] == '|':
+            return False
+        self.cursor += length
+        return True
+
+    def scan_token(self):
+        if self.tok == '#':
+            self.cursor = self.src.find('\n', self.cursor)
+            return None
+        elif self.tok == '=':
+            return TOK_EQUAL
+        elif self.tok == '(':
+            return TOK_LPAREN
+        elif self.tok == ')':
+            return TOK_RPAREN
+        elif self.tok == '&' and self.src[self.pos+1] == '&':
+            self.cursor += 1
+            return TOK_AND
+        elif self.tok == '|' and self.src[self.pos+1] == '|':
+            self.cursor += 1
+            return TOK_OR
+        elif self.tok == '!':
+            return TOK_NOT
+        elif self.tok == 'd' and self.check_keyword("epends"):
+            return TOK_DEPENDS
+        elif self.tok == 'o' and self.check_keyword("n"):
+            return TOK_ON
+        elif self.tok == 's' and self.check_keyword("elect"):
+            return TOK_SELECT
+        elif self.tok == 'i' and self.check_keyword("mply"):
+            return TOK_IMPLY
+        elif self.tok == 'c' and self.check_keyword("onfig"):
+            return TOK_CONFIG
+        elif self.tok == 'd' and self.check_keyword("efault"):
+            return TOK_DEFAULT
+        elif self.tok == 'b' and self.check_keyword("ool"):
+            return TOK_BOOL
+        elif self.tok == 'i' and self.check_keyword("f"):
+            return TOK_IF
+        elif self.tok == 'y' and self.check_keyword(""):
+            return TOK_Y
+        elif self.tok == 'n' and self.check_keyword(""):
+            return TOK_N
+        elif (self.tok == 's' and self.check_keyword("ource")) or \
+              self.tok == 'i' and self.check_keyword("nclude"):
+            # source FILENAME
+            # include FILENAME
+            while self.src[self.cursor].isspace():
+                self.cursor += 1
+            start = self.cursor
+            self.cursor = self.src.find('\n', self.cursor)
+            self.val = self.src[start:self.cursor]
+            return TOK_SOURCE
+        elif self.tok.isalpha():
+            # identifier
+            while self.src[self.cursor].isalnum() or self.src[self.cursor] == '_':
+                self.cursor += 1
+            self.val = self.src[self.pos:self.cursor]
+            return TOK_ID
+        elif self.tok == '\n':
+            if self.cursor == len(self.src):
+                return TOK_EOF
+            self.line += 1
+            self.line_pos = self.cursor
+        elif not self.tok.isspace():
+            raise KconfigParserError(self, 'invalid input')
+
+        return None
+
+if __name__ == '__main__':
+    argv = sys.argv
+    mode = defconfig
+    if len(sys.argv) > 1:
+        if argv[1] == '--defconfig':
+            del argv[1]
+        elif argv[1] == '--randconfig':
+            random.seed()
+            mode = randconfig
+            del argv[1]
+        elif argv[1] == '--allyesconfig':
+            mode = allyesconfig
+            del argv[1]
+        elif argv[1] == '--allnoconfig':
+            mode = allnoconfig
+            del argv[1]
+
+    if len(argv) == 1:
+        print ("%s: at least one argument is required" % argv[0], file=sys.stderr)
+        sys.exit(1)
+
+    if argv[1].startswith('-'):
+        print ("%s: invalid option %s" % (argv[0], argv[1]), file=sys.stderr)
+        sys.exit(1)
+
+    data = KconfigData(mode)
+    parser = KconfigParser(data)
+    for arg in argv[3:]:
+        m = re.match(r'^(CONFIG_[A-Z0-9_]+)=([yn]?)$', arg)
+        if m is not None:
+            name, value = m.groups()
+            parser.do_assignment(name, value == 'y')
+        else:
+            fp = open(arg, 'r')
+            parser.parse_file(fp)
+            fp.close()
+
+    config = data.compute_config()
+    for key in sorted(config.keys()):
+        print ('CONFIG_%s=%s' % (key, ('y' if config[key] else 'n')))
+
+    deps = open(argv[2], 'w')
+    for fname in data.previously_included:
+        print ('%s: %s' % (argv[1], fname), file=deps)
+    deps.close()
diff --git a/scripts/qemu.py b/scripts/qemu.py
deleted file mode 100644 (file)
index f7269ee..0000000
+++ /dev/null
@@ -1,516 +0,0 @@
-# QEMU library
-#
-# Copyright (C) 2015-2016 Red Hat Inc.
-# Copyright (C) 2012 IBM Corp.
-#
-# Authors:
-#  Fam Zheng <famz@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2.  See
-# the COPYING file in the top-level directory.
-#
-# Based on qmp.py.
-#
-
-import errno
-import logging
-import os
-import subprocess
-import qmp.qmp
-import re
-import shutil
-import socket
-import tempfile
-
-
-LOG = logging.getLogger(__name__)
-
-# Mapping host architecture to any additional architectures it can
-# support which often includes its 32 bit cousin.
-ADDITIONAL_ARCHES = {
-    "x86_64" : "i386",
-    "aarch64" : "armhf"
-}
-
-def kvm_available(target_arch=None):
-    host_arch = os.uname()[4]
-    if target_arch and target_arch != host_arch:
-        if target_arch != ADDITIONAL_ARCHES.get(host_arch):
-            return False
-    return os.access("/dev/kvm", os.R_OK | os.W_OK)
-
-
-#: Maps machine types to the preferred console device types
-CONSOLE_DEV_TYPES = {
-    r'^clipper$': 'isa-serial',
-    r'^malta': 'isa-serial',
-    r'^(pc.*|q35.*|isapc)$': 'isa-serial',
-    r'^(40p|powernv|prep)$': 'isa-serial',
-    r'^pseries.*': 'spapr-vty',
-    r'^s390-ccw-virtio.*': 'sclpconsole',
-    }
-
-
-class QEMUMachineError(Exception):
-    """
-    Exception called when an error in QEMUMachine happens.
-    """
-
-
-class QEMUMachineAddDeviceError(QEMUMachineError):
-    """
-    Exception raised when a request to add a device can not be fulfilled
-
-    The failures are caused by limitations, lack of information or conflicting
-    requests on the QEMUMachine methods.  This exception does not represent
-    failures reported by the QEMU binary itself.
-    """
-
-class MonitorResponseError(qmp.qmp.QMPError):
-    """
-    Represents erroneous QMP monitor reply
-    """
-    def __init__(self, reply):
-        try:
-            desc = reply["error"]["desc"]
-        except KeyError:
-            desc = reply
-        super(MonitorResponseError, self).__init__(desc)
-        self.reply = reply
-
-
-class QEMUMachine(object):
-    """
-    A QEMU VM
-
-    Use this object as a context manager to ensure the QEMU process terminates::
-
-        with VM(binary) as vm:
-            ...
-        # vm is guaranteed to be shut down here
-    """
-
-    def __init__(self, binary, args=None, wrapper=None, name=None,
-                 test_dir="/var/tmp", monitor_address=None,
-                 socket_scm_helper=None):
-        '''
-        Initialize a QEMUMachine
-
-        @param binary: path to the qemu binary
-        @param args: list of extra arguments
-        @param wrapper: list of arguments used as prefix to qemu binary
-        @param name: prefix for socket and log file names (default: qemu-PID)
-        @param test_dir: where to create socket and log file
-        @param monitor_address: address for QMP monitor
-        @param socket_scm_helper: helper program, required for send_fd_scm()
-        @note: Qemu process is not started until launch() is used.
-        '''
-        if args is None:
-            args = []
-        if wrapper is None:
-            wrapper = []
-        if name is None:
-            name = "qemu-%d" % os.getpid()
-        self._name = name
-        self._monitor_address = monitor_address
-        self._vm_monitor = None
-        self._qemu_log_path = None
-        self._qemu_log_file = None
-        self._popen = None
-        self._binary = binary
-        self._args = list(args)     # Force copy args in case we modify them
-        self._wrapper = wrapper
-        self._events = []
-        self._iolog = None
-        self._socket_scm_helper = socket_scm_helper
-        self._qmp = None
-        self._qemu_full_args = None
-        self._test_dir = test_dir
-        self._temp_dir = None
-        self._launched = False
-        self._machine = None
-        self._console_device_type = None
-        self._console_address = None
-        self._console_socket = None
-
-        # just in case logging wasn't configured by the main script:
-        logging.basicConfig()
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, exc_type, exc_val, exc_tb):
-        self.shutdown()
-        return False
-
-    # This can be used to add an unused monitor instance.
-    def add_monitor_null(self):
-        self._args.append('-monitor')
-        self._args.append('null')
-
-    def add_fd(self, fd, fdset, opaque, opts=''):
-        """
-        Pass a file descriptor to the VM
-        """
-        options = ['fd=%d' % fd,
-                   'set=%d' % fdset,
-                   'opaque=%s' % opaque]
-        if opts:
-            options.append(opts)
-
-        # This did not exist before 3.4, but since then it is
-        # mandatory for our purpose
-        if hasattr(os, 'set_inheritable'):
-            os.set_inheritable(fd, True)
-
-        self._args.append('-add-fd')
-        self._args.append(','.join(options))
-        return self
-
-    # Exactly one of fd and file_path must be given.
-    # (If it is file_path, the helper will open that file and pass its
-    # own fd)
-    def send_fd_scm(self, fd=None, file_path=None):
-        # In iotest.py, the qmp should always use unix socket.
-        assert self._qmp.is_scm_available()
-        if self._socket_scm_helper is None:
-            raise QEMUMachineError("No path to socket_scm_helper set")
-        if not os.path.exists(self._socket_scm_helper):
-            raise QEMUMachineError("%s does not exist" %
-                                   self._socket_scm_helper)
-
-        # This did not exist before 3.4, but since then it is
-        # mandatory for our purpose
-        if hasattr(os, 'set_inheritable'):
-            os.set_inheritable(self._qmp.get_sock_fd(), True)
-            if fd is not None:
-                os.set_inheritable(fd, True)
-
-        fd_param = ["%s" % self._socket_scm_helper,
-                    "%d" % self._qmp.get_sock_fd()]
-
-        if file_path is not None:
-            assert fd is None
-            fd_param.append(file_path)
-        else:
-            assert fd is not None
-            fd_param.append(str(fd))
-
-        devnull = open(os.path.devnull, 'rb')
-        proc = subprocess.Popen(fd_param, stdin=devnull, stdout=subprocess.PIPE,
-                                stderr=subprocess.STDOUT, close_fds=False)
-        output = proc.communicate()[0]
-        if output:
-            LOG.debug(output)
-
-        return proc.returncode
-
-    @staticmethod
-    def _remove_if_exists(path):
-        """
-        Remove file object at path if it exists
-        """
-        try:
-            os.remove(path)
-        except OSError as exception:
-            if exception.errno == errno.ENOENT:
-                return
-            raise
-
-    def is_running(self):
-        return self._popen is not None and self._popen.poll() is None
-
-    def exitcode(self):
-        if self._popen is None:
-            return None
-        return self._popen.poll()
-
-    def get_pid(self):
-        if not self.is_running():
-            return None
-        return self._popen.pid
-
-    def _load_io_log(self):
-        if self._qemu_log_path is not None:
-            with open(self._qemu_log_path, "r") as iolog:
-                self._iolog = iolog.read()
-
-    def _base_args(self):
-        if isinstance(self._monitor_address, tuple):
-            moncdev = "socket,id=mon,host=%s,port=%s" % (
-                self._monitor_address[0],
-                self._monitor_address[1])
-        else:
-            moncdev = 'socket,id=mon,path=%s' % self._vm_monitor
-        args = ['-chardev', moncdev,
-                '-mon', 'chardev=mon,mode=control',
-                '-display', 'none', '-vga', 'none']
-        if self._machine is not None:
-            args.extend(['-machine', self._machine])
-        if self._console_device_type is not None:
-            self._console_address = os.path.join(self._temp_dir,
-                                                 self._name + "-console.sock")
-            chardev = ('socket,id=console,path=%s,server,nowait' %
-                       self._console_address)
-            device = '%s,chardev=console' % self._console_device_type
-            args.extend(['-chardev', chardev, '-device', device])
-        return args
-
-    def _pre_launch(self):
-        self._temp_dir = tempfile.mkdtemp(dir=self._test_dir)
-        if self._monitor_address is not None:
-            self._vm_monitor = self._monitor_address
-        else:
-            self._vm_monitor = os.path.join(self._temp_dir,
-                                            self._name + "-monitor.sock")
-        self._qemu_log_path = os.path.join(self._temp_dir, self._name + ".log")
-        self._qemu_log_file = open(self._qemu_log_path, 'wb')
-
-        self._qmp = qmp.qmp.QEMUMonitorProtocol(self._vm_monitor,
-                                                server=True)
-
-    def _post_launch(self):
-        self._qmp.accept()
-
-    def _post_shutdown(self):
-        if self._qemu_log_file is not None:
-            self._qemu_log_file.close()
-            self._qemu_log_file = None
-
-        self._qemu_log_path = None
-
-        if self._console_socket is not None:
-            self._console_socket.close()
-            self._console_socket = None
-
-        if self._temp_dir is not None:
-            shutil.rmtree(self._temp_dir)
-            self._temp_dir = None
-
-    def launch(self):
-        """
-        Launch the VM and make sure we cleanup and expose the
-        command line/output in case of exception
-        """
-
-        if self._launched:
-            raise QEMUMachineError('VM already launched')
-
-        self._iolog = None
-        self._qemu_full_args = None
-        try:
-            self._launch()
-            self._launched = True
-        except:
-            self.shutdown()
-
-            LOG.debug('Error launching VM')
-            if self._qemu_full_args:
-                LOG.debug('Command: %r', ' '.join(self._qemu_full_args))
-            if self._iolog:
-                LOG.debug('Output: %r', self._iolog)
-            raise
-
-    def _launch(self):
-        """
-        Launch the VM and establish a QMP connection
-        """
-        devnull = open(os.path.devnull, 'rb')
-        self._pre_launch()
-        self._qemu_full_args = (self._wrapper + [self._binary] +
-                                self._base_args() + self._args)
-        self._popen = subprocess.Popen(self._qemu_full_args,
-                                       stdin=devnull,
-                                       stdout=self._qemu_log_file,
-                                       stderr=subprocess.STDOUT,
-                                       shell=False,
-                                       close_fds=False)
-        self._post_launch()
-
-    def wait(self):
-        """
-        Wait for the VM to power off
-        """
-        self._popen.wait()
-        self._qmp.close()
-        self._load_io_log()
-        self._post_shutdown()
-
-    def shutdown(self):
-        """
-        Terminate the VM and clean up
-        """
-        if self.is_running():
-            try:
-                self._qmp.cmd('quit')
-                self._qmp.close()
-            except:
-                self._popen.kill()
-            self._popen.wait()
-
-        self._load_io_log()
-        self._post_shutdown()
-
-        exitcode = self.exitcode()
-        if exitcode is not None and exitcode < 0:
-            msg = 'qemu received signal %i: %s'
-            if self._qemu_full_args:
-                command = ' '.join(self._qemu_full_args)
-            else:
-                command = ''
-            LOG.warn(msg, -exitcode, command)
-
-        self._launched = False
-
-    def qmp(self, cmd, conv_keys=True, **args):
-        """
-        Invoke a QMP command and return the response dict
-        """
-        qmp_args = dict()
-        for key, value in args.items():
-            if conv_keys:
-                qmp_args[key.replace('_', '-')] = value
-            else:
-                qmp_args[key] = value
-
-        return self._qmp.cmd(cmd, args=qmp_args)
-
-    def command(self, cmd, conv_keys=True, **args):
-        """
-        Invoke a QMP command.
-        On success return the response dict.
-        On failure raise an exception.
-        """
-        reply = self.qmp(cmd, conv_keys, **args)
-        if reply is None:
-            raise qmp.qmp.QMPError("Monitor is closed")
-        if "error" in reply:
-            raise MonitorResponseError(reply)
-        return reply["return"]
-
-    def get_qmp_event(self, wait=False):
-        """
-        Poll for one queued QMP events and return it
-        """
-        if len(self._events) > 0:
-            return self._events.pop(0)
-        return self._qmp.pull_event(wait=wait)
-
-    def get_qmp_events(self, wait=False):
-        """
-        Poll for queued QMP events and return a list of dicts
-        """
-        events = self._qmp.get_events(wait=wait)
-        events.extend(self._events)
-        del self._events[:]
-        self._qmp.clear_events()
-        return events
-
-    def event_wait(self, name, timeout=60.0, match=None):
-        """
-        Wait for specified timeout on named event in QMP; optionally filter
-        results by match.
-
-        The 'match' is checked to be a recursive subset of the 'event'; skips
-        branch processing on match's value None
-           {"foo": {"bar": 1}} matches {"foo": None}
-           {"foo": {"bar": 1}} does not matches {"foo": {"baz": None}}
-        """
-        def event_match(event, match=None):
-            if match is None:
-                return True
-
-            for key in match:
-                if key in event:
-                    if isinstance(event[key], dict):
-                        if not event_match(event[key], match[key]):
-                            return False
-                    elif event[key] != match[key]:
-                        return False
-                else:
-                    return False
-
-            return True
-
-        # Search cached events
-        for event in self._events:
-            if (event['event'] == name) and event_match(event, match):
-                self._events.remove(event)
-                return event
-
-        # Poll for new events
-        while True:
-            event = self._qmp.pull_event(wait=timeout)
-            if (event['event'] == name) and event_match(event, match):
-                return event
-            self._events.append(event)
-
-        return None
-
-    def get_log(self):
-        """
-        After self.shutdown or failed qemu execution, this returns the output
-        of the qemu process.
-        """
-        return self._iolog
-
-    def add_args(self, *args):
-        """
-        Adds to the list of extra arguments to be given to the QEMU binary
-        """
-        self._args.extend(args)
-
-    def set_machine(self, machine_type):
-        """
-        Sets the machine type
-
-        If set, the machine type will be added to the base arguments
-        of the resulting QEMU command line.
-        """
-        self._machine = machine_type
-
-    def set_console(self, device_type=None):
-        """
-        Sets the device type for a console device
-
-        If set, the console device and a backing character device will
-        be added to the base arguments of the resulting QEMU command
-        line.
-
-        This is a convenience method that will either use the provided
-        device type, of if not given, it will used the device type set
-        on CONSOLE_DEV_TYPES.
-
-        The actual setting of command line arguments will be be done at
-        machine launch time, as it depends on the temporary directory
-        to be created.
-
-        @param device_type: the device type, such as "isa-serial"
-        @raises: QEMUMachineAddDeviceError if the device type is not given
-                 and can not be determined.
-        """
-        if device_type is None:
-            if self._machine is None:
-                raise QEMUMachineAddDeviceError("Can not add a console device:"
-                                                " QEMU instance without a "
-                                                "defined machine type")
-            for regex, device in CONSOLE_DEV_TYPES.items():
-                if re.match(regex, self._machine):
-                    device_type = device
-                    break
-            if device_type is None:
-                raise QEMUMachineAddDeviceError("Can not add a console device:"
-                                                " no matching console device "
-                                                "type definition")
-        self._console_device_type = device_type
-
-    @property
-    def console_socket(self):
-        """
-        Returns a socket connected to the console
-        """
-        if self._console_socket is None:
-            self._console_socket = socket.socket(socket.AF_UNIX,
-                                                 socket.SOCK_STREAM)
-            self._console_socket.connect(self._console_address)
-        return self._console_socket
diff --git a/scripts/qmp/__init__.py b/scripts/qmp/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
index e8cb7646a0be1127c6fecaa41085448ae787156a..30cf8a9a0da6a436bf3ab52c3ffcbaa932ded79c 100755 (executable)
 #
 
 from __future__ import print_function
+import os
+import sys
 import base64
 import random
 
-import qmp
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu import qmp
 
 
 class QemuGuestAgent(qmp.QEMUMonitorProtocol):
index 770140772d07b90d8a03d54a6d570d269002cb07..9fec46e2ed0d98cf158c50bc2fda251999f9a90a 100755 (executable)
@@ -66,7 +66,6 @@
 # sent to QEMU, which is useful for debugging and documentation generation.
 
 from __future__ import print_function
-import qmp
 import json
 import ast
 import readline
@@ -76,6 +75,9 @@ import errno
 import atexit
 import shlex
 
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu import qmp
+
 class QMPCompleter(list):
     def complete(self, text, state):
         for cmd in self:
diff --git a/scripts/qmp/qmp.py b/scripts/qmp/qmp.py
deleted file mode 100644 (file)
index 5c8cf6a..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-# QEMU Monitor Protocol Python class
-#
-# Copyright (C) 2009, 2010 Red Hat Inc.
-#
-# Authors:
-#  Luiz Capitulino <lcapitulino@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2.  See
-# the COPYING file in the top-level directory.
-
-import json
-import errno
-import socket
-import logging
-
-
-class QMPError(Exception):
-    pass
-
-
-class QMPConnectError(QMPError):
-    pass
-
-
-class QMPCapabilitiesError(QMPError):
-    pass
-
-
-class QMPTimeoutError(QMPError):
-    pass
-
-
-class QEMUMonitorProtocol(object):
-
-    #: Logger object for debugging messages
-    logger = logging.getLogger('QMP')
-    #: Socket's error class
-    error = socket.error
-    #: Socket's timeout
-    timeout = socket.timeout
-
-    def __init__(self, address, server=False):
-        """
-        Create a QEMUMonitorProtocol class.
-
-        @param address: QEMU address, can be either a unix socket path (string)
-                        or a tuple in the form ( address, port ) for a TCP
-                        connection
-        @param server: server mode listens on the socket (bool)
-        @raise socket.error on socket connection errors
-        @note No connection is established, this is done by the connect() or
-              accept() methods
-        """
-        self.__events = []
-        self.__address = address
-        self.__sock = self.__get_sock()
-        self.__sockfile = None
-        if server:
-            self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-            self.__sock.bind(self.__address)
-            self.__sock.listen(1)
-
-    def __get_sock(self):
-        if isinstance(self.__address, tuple):
-            family = socket.AF_INET
-        else:
-            family = socket.AF_UNIX
-        return socket.socket(family, socket.SOCK_STREAM)
-
-    def __negotiate_capabilities(self):
-        greeting = self.__json_read()
-        if greeting is None or "QMP" not in greeting:
-            raise QMPConnectError
-        # Greeting seems ok, negotiate capabilities
-        resp = self.cmd('qmp_capabilities')
-        if "return" in resp:
-            return greeting
-        raise QMPCapabilitiesError
-
-    def __json_read(self, only_event=False):
-        while True:
-            data = self.__sockfile.readline()
-            if not data:
-                return
-            resp = json.loads(data)
-            if 'event' in resp:
-                self.logger.debug("<<< %s", resp)
-                self.__events.append(resp)
-                if not only_event:
-                    continue
-            return resp
-
-    def __get_events(self, wait=False):
-        """
-        Check for new events in the stream and cache them in __events.
-
-        @param wait (bool): block until an event is available.
-        @param wait (float): If wait is a float, treat it as a timeout value.
-
-        @raise QMPTimeoutError: If a timeout float is provided and the timeout
-                                period elapses.
-        @raise QMPConnectError: If wait is True but no events could be
-                                retrieved or if some other error occurred.
-        """
-
-        # Check for new events regardless and pull them into the cache:
-        self.__sock.setblocking(0)
-        try:
-            self.__json_read()
-        except socket.error as err:
-            if err[0] == errno.EAGAIN:
-                # No data available
-                pass
-        self.__sock.setblocking(1)
-
-        # Wait for new events, if needed.
-        # if wait is 0.0, this means "no wait" and is also implicitly false.
-        if not self.__events and wait:
-            if isinstance(wait, float):
-                self.__sock.settimeout(wait)
-            try:
-                ret = self.__json_read(only_event=True)
-            except socket.timeout:
-                raise QMPTimeoutError("Timeout waiting for event")
-            except:
-                raise QMPConnectError("Error while reading from socket")
-            if ret is None:
-                raise QMPConnectError("Error while reading from socket")
-            self.__sock.settimeout(None)
-
-    def connect(self, negotiate=True):
-        """
-        Connect to the QMP Monitor and perform capabilities negotiation.
-
-        @return QMP greeting dict
-        @raise socket.error on socket connection errors
-        @raise QMPConnectError if the greeting is not received
-        @raise QMPCapabilitiesError if fails to negotiate capabilities
-        """
-        self.__sock.connect(self.__address)
-        self.__sockfile = self.__sock.makefile()
-        if negotiate:
-            return self.__negotiate_capabilities()
-
-    def accept(self):
-        """
-        Await connection from QMP Monitor and perform capabilities negotiation.
-
-        @return QMP greeting dict
-        @raise socket.error on socket connection errors
-        @raise QMPConnectError if the greeting is not received
-        @raise QMPCapabilitiesError if fails to negotiate capabilities
-        """
-        self.__sock.settimeout(15)
-        self.__sock, _ = self.__sock.accept()
-        self.__sockfile = self.__sock.makefile()
-        return self.__negotiate_capabilities()
-
-    def cmd_obj(self, qmp_cmd):
-        """
-        Send a QMP command to the QMP Monitor.
-
-        @param qmp_cmd: QMP command to be sent as a Python dict
-        @return QMP response as a Python dict or None if the connection has
-                been closed
-        """
-        self.logger.debug(">>> %s", qmp_cmd)
-        try:
-            self.__sock.sendall(json.dumps(qmp_cmd).encode('utf-8'))
-        except socket.error as err:
-            if err[0] == errno.EPIPE:
-                return
-            raise socket.error(err)
-        resp = self.__json_read()
-        self.logger.debug("<<< %s", resp)
-        return resp
-
-    def cmd(self, name, args=None, cmd_id=None):
-        """
-        Build a QMP command and send it to the QMP Monitor.
-
-        @param name: command name (string)
-        @param args: command arguments (dict)
-        @param cmd_id: command id (dict, list, string or int)
-        """
-        qmp_cmd = {'execute': name}
-        if args:
-            qmp_cmd['arguments'] = args
-        if cmd_id:
-            qmp_cmd['id'] = cmd_id
-        return self.cmd_obj(qmp_cmd)
-
-    def command(self, cmd, **kwds):
-        """
-        Build and send a QMP command to the monitor, report errors if any
-        """
-        ret = self.cmd(cmd, kwds)
-        if "error" in ret:
-            raise Exception(ret['error']['desc'])
-        return ret['return']
-
-    def pull_event(self, wait=False):
-        """
-        Pulls a single event.
-
-        @param wait (bool): block until an event is available.
-        @param wait (float): If wait is a float, treat it as a timeout value.
-
-        @raise QMPTimeoutError: If a timeout float is provided and the timeout
-                                period elapses.
-        @raise QMPConnectError: If wait is True but no events could be
-                                retrieved or if some other error occurred.
-
-        @return The first available QMP event, or None.
-        """
-        self.__get_events(wait)
-
-        if self.__events:
-            return self.__events.pop(0)
-        return None
-
-    def get_events(self, wait=False):
-        """
-        Get a list of available QMP events.
-
-        @param wait (bool): block until an event is available.
-        @param wait (float): If wait is a float, treat it as a timeout value.
-
-        @raise QMPTimeoutError: If a timeout float is provided and the timeout
-                                period elapses.
-        @raise QMPConnectError: If wait is True but no events could be
-                                retrieved or if some other error occurred.
-
-        @return The list of available QMP events.
-        """
-        self.__get_events(wait)
-        return self.__events
-
-    def clear_events(self):
-        """
-        Clear current list of pending events.
-        """
-        self.__events = []
-
-    def close(self):
-        self.__sock.close()
-        self.__sockfile.close()
-
-    def settimeout(self, timeout):
-        self.__sock.settimeout(timeout)
-
-    def get_sock_fd(self):
-        return self.__sock.fileno()
-
-    def is_scm_available(self):
-        return self.__sock.family == socket.AF_UNIX
diff --git a/scripts/qtest.py b/scripts/qtest.py
deleted file mode 100644 (file)
index afac3fe..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-# QEMU qtest library
-#
-# Copyright (C) 2015 Red Hat Inc.
-#
-# Authors:
-#  Fam Zheng <famz@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2.  See
-# the COPYING file in the top-level directory.
-#
-# Based on qmp.py.
-#
-
-import socket
-import os
-import qemu
-
-
-class QEMUQtestProtocol(object):
-    def __init__(self, address, server=False):
-        """
-        Create a QEMUQtestProtocol object.
-
-        @param address: QEMU address, can be either a unix socket path (string)
-                        or a tuple in the form ( address, port ) for a TCP
-                        connection
-        @param server: server mode, listens on the socket (bool)
-        @raise socket.error on socket connection errors
-        @note No connection is established, this is done by the connect() or
-              accept() methods
-        """
-        self._address = address
-        self._sock = self._get_sock()
-        self._sockfile = None
-        if server:
-            self._sock.bind(self._address)
-            self._sock.listen(1)
-
-    def _get_sock(self):
-        if isinstance(self._address, tuple):
-            family = socket.AF_INET
-        else:
-            family = socket.AF_UNIX
-        return socket.socket(family, socket.SOCK_STREAM)
-
-    def connect(self):
-        """
-        Connect to the qtest socket.
-
-        @raise socket.error on socket connection errors
-        """
-        self._sock.connect(self._address)
-        self._sockfile = self._sock.makefile()
-
-    def accept(self):
-        """
-        Await connection from QEMU.
-
-        @raise socket.error on socket connection errors
-        """
-        self._sock, _ = self._sock.accept()
-        self._sockfile = self._sock.makefile()
-
-    def cmd(self, qtest_cmd):
-        """
-        Send a qtest command on the wire.
-
-        @param qtest_cmd: qtest command text to be sent
-        """
-        self._sock.sendall((qtest_cmd + "\n").encode('utf-8'))
-        resp = self._sockfile.readline()
-        return resp
-
-    def close(self):
-        self._sock.close()
-        self._sockfile.close()
-
-    def settimeout(self, timeout):
-        self._sock.settimeout(timeout)
-
-
-class QEMUQtestMachine(qemu.QEMUMachine):
-    '''A QEMU VM'''
-
-    def __init__(self, binary, args=None, name=None, test_dir="/var/tmp",
-                 socket_scm_helper=None):
-        if name is None:
-            name = "qemu-%d" % os.getpid()
-        super(QEMUQtestMachine,
-              self).__init__(binary, args, name=name, test_dir=test_dir,
-                             socket_scm_helper=socket_scm_helper)
-        self._qtest = None
-        self._qtest_path = os.path.join(test_dir, name + "-qtest.sock")
-
-    def _base_args(self):
-        args = super(QEMUQtestMachine, self)._base_args()
-        args.extend(['-qtest', 'unix:path=' + self._qtest_path,
-                     '-machine', 'accel=qtest'])
-        return args
-
-    def _pre_launch(self):
-        super(QEMUQtestMachine, self)._pre_launch()
-        self._qtest = QEMUQtestProtocol(self._qtest_path, server=True)
-
-    def _post_launch(self):
-        super(QEMUQtestMachine, self)._post_launch()
-        self._qtest.accept()
-
-    def _post_shutdown(self):
-        super(QEMUQtestMachine, self)._post_shutdown()
-        self._remove_if_exists(self._qtest_path)
-
-    def qtest(self, cmd):
-        '''Send a qtest command to guest'''
-        return self._qtest.cmd(cmd)
index ed7e581b4f4ecaad49c42054a66760246ae5ccdd..3e9d282a49bd2a13fa4571e05c70d2c1c0fb1a3f 100755 (executable)
@@ -23,6 +23,8 @@ import sys
 import subprocess
 import json
 from graphviz import Digraph
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
 from qemu import MonitorResponseError
 
 
diff --git a/slirp/Makefile b/slirp/Makefile
new file mode 100644 (file)
index 0000000..6d48f62
--- /dev/null
@@ -0,0 +1,47 @@
+ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
+BUILD_DIR ?= .
+
+LIBSLIRP = $(BUILD_DIR)/libslirp.a
+
+all: $(LIBSLIRP)
+
+SRCS := $(wildcard src/*.c)
+OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
+DEPS := $(OBJS:%.o=%.d)
+
+INC_DIRS := $(BUILD_DIR)/src
+INC_FLAGS := $(addprefix -I,$(INC_DIRS))
+
+override CFLAGS +=                                     \
+       -DG_LOG_DOMAIN='"Slirp"'                        \
+       $(shell $(PKG_CONFIG) --cflags glib-2.0)        \
+       $(INC_FLAGS)                                    \
+       -MMD -MP
+override LDFLAGS += $(shell $(PKG_CONFIG) --libs glib-2.0)
+
+$(LIBSLIRP): $(OBJS)
+
+.PHONY: clean
+
+clean:
+       rm -r $(OBJS) $(DEPS) $(LIBSLIRP)
+
+$(BUILD_DIR)/src/%.o: $(ROOT_DIR)/src/%.c
+       @$(MKDIR_P) $(dir $@)
+       $(call quiet-command,$(CC) $(CFLAGS) -c -o $@ $<,"CC","$@")
+
+%.a:
+       $(call quiet-command,rm -f $@ && $(AR) rcs $@ $^,"AR","$@")
+
+PKG_CONFIG ?= pkg-config
+MKDIR_P ?= mkdir -p
+quiet-command-run = $(if $(V),,$(if $2,printf "  %-7s %s\n" $2 $3 && ))$1
+quiet-@ = $(if $(V),,@)
+quiet-command = $(quiet-@)$(call quiet-command-run,$1,$2,$3)
+
+print-%:
+       @echo '$*=$($*)'
+
+.SUFFIXES:
+
+-include $(DEPS)
diff --git a/slirp/Makefile.objs b/slirp/Makefile.objs
deleted file mode 100644 (file)
index 88340a5..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-slirp-obj-y = slirp.mo
-
-slirp.mo-objs = \
-       arp_table.o \
-       bootp.o \
-       cksum.o \
-       dhcpv6.o \
-       dnssearch.o \
-       if.o \
-       ip6_icmp.o \
-       ip6_input.o \
-       ip6_output.o \
-       ip_icmp.o \
-       ip_input.o \
-       ip_output.o \
-       mbuf.o \
-       misc.o \
-       ncsi.o \
-       ndp_table.o \
-       sbuf.o \
-       slirp.o \
-       socket.o \
-       state.o \
-       tcp_input.o \
-       tcp_output.o \
-       tcp_subr.o \
-       tcp_timer.o \
-       tftp.o \
-       udp.o \
-       udp6.o \
-       util.o \
-       $(NULL)
-
-slirp.mo-cflags = -DG_LOG_DOMAIN=\"Slirp\" -DWITH_QEMU
diff --git a/slirp/arp_table.c b/slirp/arp_table.c
deleted file mode 100644 (file)
index 58eafdc..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * ARP table
- *
- * Copyright (c) 2011 AdaCore
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "slirp.h"
-
-#include <string.h>
-
-void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
-{
-    const uint32_t broadcast_addr =
-        ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
-    ArpTable *arptbl = &slirp->arp_table;
-    int i;
-
-    DEBUG_CALL("arp_table_add");
-    DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){.s_addr = ip_addr}));
-    DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
-              ethaddr[0], ethaddr[1], ethaddr[2],
-              ethaddr[3], ethaddr[4], ethaddr[5]);
-
-    if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
-        /* Do not register broadcast addresses */
-        return;
-    }
-
-    /* Search for an entry */
-    for (i = 0; i < ARP_TABLE_SIZE; i++) {
-        if (arptbl->table[i].ar_sip == ip_addr) {
-            /* Update the entry */
-            memcpy(arptbl->table[i].ar_sha, ethaddr, ETH_ALEN);
-            return;
-        }
-    }
-
-    /* No entry found, create a new one */
-    arptbl->table[arptbl->next_victim].ar_sip = ip_addr;
-    memcpy(arptbl->table[arptbl->next_victim].ar_sha,  ethaddr, ETH_ALEN);
-    arptbl->next_victim = (arptbl->next_victim + 1) % ARP_TABLE_SIZE;
-}
-
-bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
-                      uint8_t out_ethaddr[ETH_ALEN])
-{
-    const uint32_t broadcast_addr =
-        ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
-    ArpTable *arptbl = &slirp->arp_table;
-    int i;
-
-    DEBUG_CALL("arp_table_search");
-    DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){.s_addr = ip_addr}));
-
-    /* If broadcast address */
-    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
-        /* return Ethernet broadcast address */
-        memset(out_ethaddr, 0xff, ETH_ALEN);
-        return 1;
-    }
-
-    for (i = 0; i < ARP_TABLE_SIZE; i++) {
-        if (arptbl->table[i].ar_sip == ip_addr) {
-            memcpy(out_ethaddr, arptbl->table[i].ar_sha,  ETH_ALEN);
-            DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
-                      out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
-                      out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
-            return 1;
-        }
-    }
-
-    return 0;
-}
diff --git a/slirp/bootp.c b/slirp/bootp.c
deleted file mode 100644 (file)
index d396849..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * QEMU BOOTP/DHCP server
- *
- * Copyright (c) 2004 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "slirp.h"
-
-#if defined(_WIN32)
-/* Windows ntohl() returns an u_long value.
- * Add a type cast to match the format strings. */
-# define ntohl(n) ((uint32_t)ntohl(n))
-#endif
-
-/* XXX: only DHCP is supported */
-
-#define LEASE_TIME (24 * 3600)
-
-static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
-
-#define DPRINTF(fmt, ...) DEBUG_CALL(fmt, ##__VA_ARGS__)
-
-static BOOTPClient *get_new_addr(Slirp *slirp, struct in_addr *paddr,
-                                 const uint8_t *macaddr)
-{
-    BOOTPClient *bc;
-    int i;
-
-    for(i = 0; i < NB_BOOTP_CLIENTS; i++) {
-        bc = &slirp->bootp_clients[i];
-        if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6))
-            goto found;
-    }
-    return NULL;
- found:
-    bc = &slirp->bootp_clients[i];
-    bc->allocated = 1;
-    paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
-    return bc;
-}
-
-static BOOTPClient *request_addr(Slirp *slirp, const struct in_addr *paddr,
-                                 const uint8_t *macaddr)
-{
-    uint32_t req_addr = ntohl(paddr->s_addr);
-    uint32_t dhcp_addr = ntohl(slirp->vdhcp_startaddr.s_addr);
-    BOOTPClient *bc;
-
-    if (req_addr >= dhcp_addr &&
-        req_addr < (dhcp_addr + NB_BOOTP_CLIENTS)) {
-        bc = &slirp->bootp_clients[req_addr - dhcp_addr];
-        if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
-            bc->allocated = 1;
-            return bc;
-        }
-    }
-    return NULL;
-}
-
-static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr,
-                              const uint8_t *macaddr)
-{
-    BOOTPClient *bc;
-    int i;
-
-    for(i = 0; i < NB_BOOTP_CLIENTS; i++) {
-        if (!memcmp(macaddr, slirp->bootp_clients[i].macaddr, 6))
-            goto found;
-    }
-    return NULL;
- found:
-    bc = &slirp->bootp_clients[i];
-    bc->allocated = 1;
-    paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
-    return bc;
-}
-
-static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
-                        struct in_addr *preq_addr)
-{
-    const uint8_t *p, *p_end;
-    int len, tag;
-
-    *pmsg_type = 0;
-    preq_addr->s_addr = htonl(0L);
-
-    p = bp->bp_vend;
-    p_end = p + DHCP_OPT_LEN;
-    if (memcmp(p, rfc1533_cookie, 4) != 0)
-        return;
-    p += 4;
-    while (p < p_end) {
-        tag = p[0];
-        if (tag == RFC1533_PAD) {
-            p++;
-        } else if (tag == RFC1533_END) {
-            break;
-        } else {
-            p++;
-            if (p >= p_end)
-                break;
-            len = *p++;
-            if (p + len > p_end) {
-                break;
-            }
-            DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
-
-            switch(tag) {
-            case RFC2132_MSG_TYPE:
-                if (len >= 1)
-                    *pmsg_type = p[0];
-                break;
-            case RFC2132_REQ_ADDR:
-                if (len >= 4) {
-                    memcpy(&(preq_addr->s_addr), p, 4);
-                }
-                break;
-            default:
-                break;
-            }
-            p += len;
-        }
-    }
-    if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) &&
-        bp->bp_ciaddr.s_addr) {
-        memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4);
-    }
-}
-
-static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
-{
-    BOOTPClient *bc = NULL;
-    struct mbuf *m;
-    struct bootp_t *rbp;
-    struct sockaddr_in saddr, daddr;
-    struct in_addr preq_addr;
-    int dhcp_msg_type, val;
-    uint8_t *q;
-    uint8_t *end;
-    uint8_t client_ethaddr[ETH_ALEN];
-
-    /* extract exact DHCP msg type */
-    dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
-    DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
-    if (preq_addr.s_addr != htonl(0L))
-        DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
-    else {
-        DPRINTF("\n");
-    }
-
-    if (dhcp_msg_type == 0)
-        dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
-
-    if (dhcp_msg_type != DHCPDISCOVER &&
-        dhcp_msg_type != DHCPREQUEST)
-        return;
-
-    /* Get client's hardware address from bootp request */
-    memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN);
-
-    m = m_get(slirp);
-    if (!m) {
-        return;
-    }
-    m->m_data += IF_MAXLINKHDR;
-    rbp = (struct bootp_t *)m->m_data;
-    m->m_data += sizeof(struct udpiphdr);
-    memset(rbp, 0, sizeof(struct bootp_t));
-
-    if (dhcp_msg_type == DHCPDISCOVER) {
-        if (preq_addr.s_addr != htonl(0L)) {
-            bc = request_addr(slirp, &preq_addr, client_ethaddr);
-            if (bc) {
-                daddr.sin_addr = preq_addr;
-            }
-        }
-        if (!bc) {
-         new_addr:
-            bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr);
-            if (!bc) {
-                DPRINTF("no address left\n");
-                return;
-            }
-        }
-        memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
-    } else if (preq_addr.s_addr != htonl(0L)) {
-        bc = request_addr(slirp, &preq_addr, client_ethaddr);
-        if (bc) {
-            daddr.sin_addr = preq_addr;
-            memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
-        } else {
-            /* DHCPNAKs should be sent to broadcast */
-            daddr.sin_addr.s_addr = 0xffffffff;
-        }
-    } else {
-        bc = find_addr(slirp, &daddr.sin_addr, bp->bp_hwaddr);
-        if (!bc) {
-            /* if never assigned, behaves as if it was already
-               assigned (windows fix because it remembers its address) */
-            goto new_addr;
-        }
-    }
-
-    /* Update ARP table for this IP address */
-    arp_table_add(slirp, daddr.sin_addr.s_addr, client_ethaddr);
-
-    saddr.sin_addr = slirp->vhost_addr;
-    saddr.sin_port = htons(BOOTP_SERVER);
-
-    daddr.sin_port = htons(BOOTP_CLIENT);
-
-    rbp->bp_op = BOOTP_REPLY;
-    rbp->bp_xid = bp->bp_xid;
-    rbp->bp_htype = 1;
-    rbp->bp_hlen = 6;
-    memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN);
-
-    rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
-    rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
-
-    q = rbp->bp_vend;
-    end = (uint8_t *)&rbp[1];
-    memcpy(q, rfc1533_cookie, 4);
-    q += 4;
-
-    if (bc) {
-        DPRINTF("%s addr=%08" PRIx32 "\n",
-                (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed",
-                ntohl(daddr.sin_addr.s_addr));
-
-        if (dhcp_msg_type == DHCPDISCOVER) {
-            *q++ = RFC2132_MSG_TYPE;
-            *q++ = 1;
-            *q++ = DHCPOFFER;
-        } else /* DHCPREQUEST */ {
-            *q++ = RFC2132_MSG_TYPE;
-            *q++ = 1;
-            *q++ = DHCPACK;
-        }
-
-        if (slirp->bootp_filename)
-            snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s",
-                     slirp->bootp_filename);
-
-        *q++ = RFC2132_SRV_ID;
-        *q++ = 4;
-        memcpy(q, &saddr.sin_addr, 4);
-        q += 4;
-
-        *q++ = RFC1533_NETMASK;
-        *q++ = 4;
-        memcpy(q, &slirp->vnetwork_mask, 4);
-        q += 4;
-
-        if (!slirp->restricted) {
-            *q++ = RFC1533_GATEWAY;
-            *q++ = 4;
-            memcpy(q, &saddr.sin_addr, 4);
-            q += 4;
-
-            *q++ = RFC1533_DNS;
-            *q++ = 4;
-            memcpy(q, &slirp->vnameserver_addr, 4);
-            q += 4;
-        }
-
-        *q++ = RFC2132_LEASE_TIME;
-        *q++ = 4;
-        val = htonl(LEASE_TIME);
-        memcpy(q, &val, 4);
-        q += 4;
-
-        if (*slirp->client_hostname) {
-            val = strlen(slirp->client_hostname);
-            if (q + val + 2 >= end) {
-                g_warning("DHCP packet size exceeded, "
-                    "omitting host name option.");
-            } else {
-                *q++ = RFC1533_HOSTNAME;
-                *q++ = val;
-                memcpy(q, slirp->client_hostname, val);
-                q += val;
-            }
-        }
-
-        if (slirp->vdomainname) {
-            val = strlen(slirp->vdomainname);
-            if (q + val + 2 >= end) {
-                g_warning("DHCP packet size exceeded, "
-                    "omitting domain name option.");
-            } else {
-                *q++ = RFC1533_DOMAINNAME;
-                *q++ = val;
-                memcpy(q, slirp->vdomainname, val);
-                q += val;
-            }
-        }
-
-        if (slirp->tftp_server_name) {
-            val = strlen(slirp->tftp_server_name);
-            if (q + val + 2 >= end) {
-                g_warning("DHCP packet size exceeded, "
-                    "omitting tftp-server-name option.");
-            } else {
-                *q++ = RFC2132_TFTP_SERVER_NAME;
-                *q++ = val;
-                memcpy(q, slirp->tftp_server_name, val);
-                q += val;
-            }
-        }
-
-        if (slirp->vdnssearch) {
-            val = slirp->vdnssearch_len;
-            if (q + val >= end) {
-                g_warning("DHCP packet size exceeded, "
-                    "omitting domain-search option.");
-            } else {
-                memcpy(q, slirp->vdnssearch, val);
-                q += val;
-            }
-        }
-    } else {
-        static const char nak_msg[] = "requested address not available";
-
-        DPRINTF("nak'ed addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
-
-        *q++ = RFC2132_MSG_TYPE;
-        *q++ = 1;
-        *q++ = DHCPNAK;
-
-        *q++ = RFC2132_MESSAGE;
-        *q++ = sizeof(nak_msg) - 1;
-        memcpy(q, nak_msg, sizeof(nak_msg) - 1);
-        q += sizeof(nak_msg) - 1;
-    }
-    assert(q < end);
-    *q = RFC1533_END;
-
-    daddr.sin_addr.s_addr = 0xffffffffu;
-
-    m->m_len = sizeof(struct bootp_t) -
-        sizeof(struct ip) - sizeof(struct udphdr);
-    udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
-}
-
-void bootp_input(struct mbuf *m)
-{
-    struct bootp_t *bp = mtod(m, struct bootp_t *);
-
-    if (bp->bp_op == BOOTP_REQUEST) {
-        bootp_reply(m->slirp, bp);
-    }
-}
diff --git a/slirp/bootp.h b/slirp/bootp.h
deleted file mode 100644 (file)
index 4043489..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/* bootp/dhcp defines */
-
-#ifndef SLIRP_BOOTP_H
-#define SLIRP_BOOTP_H
-
-#define BOOTP_SERVER   67
-#define BOOTP_CLIENT   68
-
-#define BOOTP_REQUEST  1
-#define BOOTP_REPLY    2
-
-#define RFC1533_COOKIE         99, 130, 83, 99
-#define RFC1533_PAD            0
-#define RFC1533_NETMASK                1
-#define RFC1533_TIMEOFFSET     2
-#define RFC1533_GATEWAY                3
-#define RFC1533_TIMESERVER     4
-#define RFC1533_IEN116NS       5
-#define RFC1533_DNS            6
-#define RFC1533_LOGSERVER      7
-#define RFC1533_COOKIESERVER   8
-#define RFC1533_LPRSERVER      9
-#define RFC1533_IMPRESSSERVER  10
-#define RFC1533_RESOURCESERVER 11
-#define RFC1533_HOSTNAME       12
-#define RFC1533_BOOTFILESIZE   13
-#define RFC1533_MERITDUMPFILE  14
-#define RFC1533_DOMAINNAME     15
-#define RFC1533_SWAPSERVER     16
-#define RFC1533_ROOTPATH       17
-#define RFC1533_EXTENSIONPATH  18
-#define RFC1533_IPFORWARDING   19
-#define RFC1533_IPSOURCEROUTING        20
-#define RFC1533_IPPOLICYFILTER 21
-#define RFC1533_IPMAXREASSEMBLY        22
-#define RFC1533_IPTTL          23
-#define RFC1533_IPMTU          24
-#define RFC1533_IPMTUPLATEAU   25
-#define RFC1533_INTMTU         26
-#define RFC1533_INTLOCALSUBNETS        27
-#define RFC1533_INTBROADCAST   28
-#define RFC1533_INTICMPDISCOVER        29
-#define RFC1533_INTICMPRESPOND 30
-#define RFC1533_INTROUTEDISCOVER 31
-#define RFC1533_INTROUTESOLICIT        32
-#define RFC1533_INTSTATICROUTES        33
-#define RFC1533_LLTRAILERENCAP 34
-#define RFC1533_LLARPCACHETMO  35
-#define RFC1533_LLETHERNETENCAP        36
-#define RFC1533_TCPTTL         37
-#define RFC1533_TCPKEEPALIVETMO        38
-#define RFC1533_TCPKEEPALIVEGB 39
-#define RFC1533_NISDOMAIN      40
-#define RFC1533_NISSERVER      41
-#define RFC1533_NTPSERVER      42
-#define RFC1533_VENDOR         43
-#define RFC1533_NBNS           44
-#define RFC1533_NBDD           45
-#define RFC1533_NBNT           46
-#define RFC1533_NBSCOPE                47
-#define RFC1533_XFS            48
-#define RFC1533_XDM            49
-
-#define RFC2132_REQ_ADDR       50
-#define RFC2132_LEASE_TIME      51
-#define RFC2132_MSG_TYPE       53
-#define RFC2132_SRV_ID         54
-#define RFC2132_PARAM_LIST     55
-#define RFC2132_MESSAGE                56
-#define RFC2132_MAX_SIZE       57
-#define RFC2132_RENEWAL_TIME    58
-#define RFC2132_REBIND_TIME     59
-#define RFC2132_TFTP_SERVER_NAME 66
-
-#define DHCPDISCOVER           1
-#define DHCPOFFER              2
-#define DHCPREQUEST            3
-#define DHCPACK                        5
-#define DHCPNAK                        6
-
-#define RFC1533_VENDOR_MAJOR   0
-#define RFC1533_VENDOR_MINOR   0
-
-#define RFC1533_VENDOR_MAGIC   128
-#define RFC1533_VENDOR_ADDPARM 129
-#define        RFC1533_VENDOR_ETHDEV   130
-#define RFC1533_VENDOR_HOWTO    132
-#define RFC1533_VENDOR_MNUOPTS 160
-#define RFC1533_VENDOR_SELECTION 176
-#define RFC1533_VENDOR_MOTD    184
-#define RFC1533_VENDOR_NUMOFMOTD 8
-#define RFC1533_VENDOR_IMG     192
-#define RFC1533_VENDOR_NUMOFIMG        16
-
-#define RFC1533_END            255
-#define BOOTP_VENDOR_LEN       64
-#define DHCP_OPT_LEN           312
-
-struct bootp_t {
-    struct ip ip;
-    struct udphdr udp;
-    uint8_t bp_op;
-    uint8_t bp_htype;
-    uint8_t bp_hlen;
-    uint8_t bp_hops;
-    uint32_t bp_xid;
-    uint16_t bp_secs;
-    uint16_t unused;
-    struct in_addr bp_ciaddr;
-    struct in_addr bp_yiaddr;
-    struct in_addr bp_siaddr;
-    struct in_addr bp_giaddr;
-    uint8_t bp_hwaddr[16];
-    uint8_t bp_sname[64];
-    uint8_t bp_file[128];
-    uint8_t bp_vend[DHCP_OPT_LEN];
-};
-
-typedef struct {
-    uint16_t allocated;
-    uint8_t macaddr[6];
-} BOOTPClient;
-
-#define NB_BOOTP_CLIENTS 16
-
-void bootp_input(struct mbuf *m);
-
-#endif
diff --git a/slirp/cksum.c b/slirp/cksum.c
deleted file mode 100644 (file)
index 25bfa67..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (c) 1988, 1992, 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. 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.
- *
- *     @(#)in_cksum.c  8.1 (Berkeley) 6/10/93
- * in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp
- */
-
-#include "slirp.h"
-
-/*
- * Checksum routine for Internet Protocol family headers (Portable Version).
- *
- * This routine is very heavily used in the network
- * code and should be modified for each CPU to be as fast as possible.
- *
- * XXX Since we will never span more than 1 mbuf, we can optimise this
- */
-
-#define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
-#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1];        \
-        (void)ADDCARRY(sum);}
-
-int cksum(struct mbuf *m, int len)
-{
-       register uint16_t *w;
-       register int sum = 0;
-       register int mlen = 0;
-       int byte_swapped = 0;
-
-       union {
-               uint8_t  c[2];
-               uint16_t s;
-       } s_util;
-       union {
-               uint16_t s[2];
-               uint32_t l;
-       } l_util;
-
-       if (m->m_len == 0)
-          goto cont;
-       w = mtod(m, uint16_t *);
-
-       mlen = m->m_len;
-
-       if (len < mlen)
-          mlen = len;
-       len -= mlen;
-       /*
-        * Force to even boundary.
-        */
-       if ((1 & (uintptr_t)w) && (mlen > 0)) {
-               REDUCE;
-               sum <<= 8;
-               s_util.c[0] = *(uint8_t *)w;
-               w = (uint16_t *)((int8_t *)w + 1);
-               mlen--;
-               byte_swapped = 1;
-       }
-       /*
-        * Unroll the loop to make overhead from
-        * branches &c small.
-        */
-       while ((mlen -= 32) >= 0) {
-               sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
-               sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
-               sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
-               sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
-               w += 16;
-       }
-       mlen += 32;
-       while ((mlen -= 8) >= 0) {
-               sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
-               w += 4;
-       }
-       mlen += 8;
-       if (mlen == 0 && byte_swapped == 0)
-          goto cont;
-       REDUCE;
-       while ((mlen -= 2) >= 0) {
-               sum += *w++;
-       }
-
-       if (byte_swapped) {
-               REDUCE;
-               sum <<= 8;
-               if (mlen == -1) {
-                       s_util.c[1] = *(uint8_t *)w;
-                       sum += s_util.s;
-                       mlen = 0;
-               } else
-
-                  mlen = -1;
-       } else if (mlen == -1)
-          s_util.c[0] = *(uint8_t *)w;
-
-cont:
-       if (len) {
-               DEBUG_ERROR("cksum: out of data");
-               DEBUG_ERROR(" len = %d", len);
-       }
-       if (mlen == -1) {
-               /* The last mbuf has odd # of bytes. Follow the
-                standard (the odd byte may be shifted left by 8 bits
-                          or not as determined by endian-ness of the machine) */
-               s_util.c[1] = 0;
-               sum += s_util.s;
-       }
-       REDUCE;
-       return (~sum & 0xffff);
-}
-
-int ip6_cksum(struct mbuf *m)
-{
-    /* TODO: Optimize this by being able to pass the ip6_pseudohdr to cksum
-     * separately from the mbuf */
-    struct ip6 save_ip, *ip = mtod(m, struct ip6 *);
-    struct ip6_pseudohdr *ih = mtod(m, struct ip6_pseudohdr *);
-    int sum;
-
-    save_ip = *ip;
-
-    ih->ih_src = save_ip.ip_src;
-    ih->ih_dst = save_ip.ip_dst;
-    ih->ih_pl = htonl((uint32_t)ntohs(save_ip.ip_pl));
-    ih->ih_zero_hi = 0;
-    ih->ih_zero_lo = 0;
-    ih->ih_nh = save_ip.ip_nh;
-
-    sum = cksum(m, ((int)sizeof(struct ip6_pseudohdr))
-                    + ntohl(ih->ih_pl));
-
-    *ip = save_ip;
-
-    return sum;
-}
diff --git a/slirp/debug.h b/slirp/debug.h
deleted file mode 100644 (file)
index 44d922d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#ifndef DEBUG_H_
-#define DEBUG_H_
-
-#define DBG_CALL (1 << 0)
-#define DBG_MISC (1 << 1)
-#define DBG_ERROR (1 << 2)
-#define DBG_TFTP (1 << 3)
-
-extern int slirp_debug;
-
-#define DEBUG_CALL(fmt, ...) do {               \
-    if (G_UNLIKELY(slirp_debug & DBG_CALL)) {   \
-        g_debug(fmt "...", ##__VA_ARGS__);      \
-    }                                           \
-} while (0)
-
-#define DEBUG_ARG(fmt, ...) do {                \
-    if (G_UNLIKELY(slirp_debug & DBG_CALL)) {   \
-        g_debug(" " fmt, ##__VA_ARGS__);        \
-    }                                           \
-} while (0)
-
-#define DEBUG_MISC(fmt, ...) do {               \
-    if (G_UNLIKELY(slirp_debug & DBG_MISC)) {   \
-        g_debug(fmt, ##__VA_ARGS__);            \
-    }                                           \
-} while (0)
-
-#define DEBUG_ERROR(fmt, ...) do {              \
-    if (G_UNLIKELY(slirp_debug & DBG_ERROR)) {  \
-        g_debug(fmt, ##__VA_ARGS__);            \
-    }                                           \
-} while (0)
-
-#define DEBUG_TFTP(fmt, ...) do {               \
-    if (G_UNLIKELY(slirp_debug & DBG_TFTP)) {   \
-        g_debug(fmt, ##__VA_ARGS__);            \
-    }                                           \
-} while (0)
-
-#endif /* DEBUG_H_ */
diff --git a/slirp/dhcpv6.c b/slirp/dhcpv6.c
deleted file mode 100644 (file)
index e655c7d..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * SLIRP stateless DHCPv6
- *
- * We only support stateless DHCPv6, e.g. for network booting.
- * See RFC 3315, RFC 3736, RFC 3646 and RFC 5970 for details.
- *
- * Copyright 2016 Thomas Huth, Red Hat Inc.
- *
- * 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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "slirp.h"
-#include "dhcpv6.h"
-
-/* DHCPv6 message types */
-#define MSGTYPE_REPLY        7
-#define MSGTYPE_INFO_REQUEST 11
-
-/* DHCPv6 option types */
-#define OPTION_CLIENTID      1
-#define OPTION_IAADDR        5
-#define OPTION_ORO           6
-#define OPTION_DNS_SERVERS   23
-#define OPTION_BOOTFILE_URL  59
-
-struct requested_infos {
-    uint8_t *client_id;
-    int client_id_len;
-    bool want_dns;
-    bool want_boot_url;
-};
-
-/**
- * Analyze the info request message sent by the client to see what data it
- * provided and what it wants to have. The information is gathered in the
- * "requested_infos" struct. Note that client_id (if provided) points into
- * the odata region, thus the caller must keep odata valid as long as it
- * needs to access the requested_infos struct.
- */
-static int dhcpv6_parse_info_request(Slirp *slirp, uint8_t *odata, int olen,
-                                     struct requested_infos *ri)
-{
-    int i, req_opt;
-
-    while (olen > 4) {
-        /* Parse one option */
-        int option = odata[0] << 8 | odata[1];
-        int len = odata[2] << 8 | odata[3];
-
-        if (len + 4 > olen) {
-            slirp->cb->guest_error("Guest sent bad DHCPv6 packet!", slirp->opaque);
-            return -E2BIG;
-        }
-
-        switch (option) {
-        case OPTION_IAADDR:
-            /* According to RFC3315, we must discard requests with IA option */
-            return -EINVAL;
-        case OPTION_CLIENTID:
-            if (len > 256) {
-                /* Avoid very long IDs which could cause problems later */
-                return -E2BIG;
-            }
-            ri->client_id = odata + 4;
-            ri->client_id_len = len;
-            break;
-        case OPTION_ORO:        /* Option request option */
-            if (len & 1) {
-                return -EINVAL;
-            }
-            /* Check which options the client wants to have */
-            for (i = 0; i < len; i += 2) {
-                req_opt = odata[4 + i] << 8 | odata[4 + i + 1];
-                switch (req_opt) {
-                case OPTION_DNS_SERVERS:
-                    ri->want_dns = true;
-                    break;
-                case OPTION_BOOTFILE_URL:
-                    ri->want_boot_url = true;
-                    break;
-                default:
-                    DEBUG_MISC("dhcpv6: Unsupported option request %d",
-                               req_opt);
-                }
-            }
-            break;
-        default:
-            DEBUG_MISC("dhcpv6 info req: Unsupported option %d, len=%d",
-                       option, len);
-        }
-
-        odata += len + 4;
-        olen -= len + 4;
-    }
-
-    return 0;
-}
-
-
-/**
- * Handle information request messages
- */
-static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas,
-                                uint32_t xid, uint8_t *odata, int olen)
-{
-    struct requested_infos ri = { NULL };
-    struct sockaddr_in6 sa6, da6;
-    struct mbuf *m;
-    uint8_t *resp;
-
-    if (dhcpv6_parse_info_request(slirp, odata, olen, &ri) < 0) {
-        return;
-    }
-
-    m = m_get(slirp);
-    if (!m) {
-        return;
-    }
-    memset(m->m_data, 0, m->m_size);
-    m->m_data += IF_MAXLINKHDR;
-    resp = (uint8_t *)m->m_data + sizeof(struct ip6) + sizeof(struct udphdr);
-
-    /* Fill in response */
-    *resp++ = MSGTYPE_REPLY;
-    *resp++ = (uint8_t)(xid >> 16);
-    *resp++ = (uint8_t)(xid >> 8);
-    *resp++ = (uint8_t)xid;
-
-    if (ri.client_id) {
-        *resp++ = OPTION_CLIENTID >> 8;         /* option-code high byte */
-        *resp++ = OPTION_CLIENTID;              /* option-code low byte */
-        *resp++ = ri.client_id_len >> 8;        /* option-len high byte */
-        *resp++ = ri.client_id_len;             /* option-len low byte */
-        memcpy(resp, ri.client_id, ri.client_id_len);
-        resp += ri.client_id_len;
-    }
-    if (ri.want_dns) {
-        *resp++ = OPTION_DNS_SERVERS >> 8;      /* option-code high byte */
-        *resp++ = OPTION_DNS_SERVERS;           /* option-code low byte */
-        *resp++ = 0;                            /* option-len high byte */
-        *resp++ = 16;                           /* option-len low byte */
-        memcpy(resp, &slirp->vnameserver_addr6, 16);
-        resp += 16;
-    }
-    if (ri.want_boot_url) {
-        uint8_t *sa = slirp->vhost_addr6.s6_addr;
-        int slen, smaxlen;
-
-        *resp++ = OPTION_BOOTFILE_URL >> 8;     /* option-code high byte */
-        *resp++ = OPTION_BOOTFILE_URL;          /* option-code low byte */
-        smaxlen = (uint8_t *)m->m_data + IF_MTU - (resp + 2);
-        slen = snprintf((char *)resp + 2, smaxlen,
-                        "tftp://[%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
-                                "%02x%02x:%02x%02x:%02x%02x:%02x%02x]/%s",
-                        sa[0], sa[1], sa[2], sa[3], sa[4], sa[5], sa[6], sa[7],
-                        sa[8], sa[9], sa[10], sa[11], sa[12], sa[13], sa[14],
-                        sa[15], slirp->bootp_filename);
-        slen = MIN(slen, smaxlen);
-        *resp++ = slen >> 8;                    /* option-len high byte */
-        *resp++ = slen;                         /* option-len low byte */
-        resp += slen;
-    }
-
-    sa6.sin6_addr = slirp->vhost_addr6;
-    sa6.sin6_port = DHCPV6_SERVER_PORT;
-    da6.sin6_addr = srcsas->sin6_addr;
-    da6.sin6_port = srcsas->sin6_port;
-    m->m_data += sizeof(struct ip6) + sizeof(struct udphdr);
-    m->m_len = resp - (uint8_t *)m->m_data;
-    udp6_output(NULL, m, &sa6, &da6);
-}
-
-/**
- * Handle DHCPv6 messages sent by the client
- */
-void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m)
-{
-    uint8_t *data = (uint8_t *)m->m_data + sizeof(struct udphdr);
-    int data_len = m->m_len - sizeof(struct udphdr);
-    uint32_t xid;
-
-    if (data_len < 4) {
-        return;
-    }
-
-    xid = ntohl(*(uint32_t *)data) & 0xffffff;
-
-    switch (data[0]) {
-    case MSGTYPE_INFO_REQUEST:
-        dhcpv6_info_request(m->slirp, srcsas, xid, &data[4], data_len - 4);
-        break;
-    default:
-        DEBUG_MISC("dhcpv6_input: Unsupported message type 0x%x", data[0]);
-    }
-}
diff --git a/slirp/dhcpv6.h b/slirp/dhcpv6.h
deleted file mode 100644 (file)
index 3373f6c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Definitions and prototypes for SLIRP stateless DHCPv6
- *
- * Copyright 2016 Thomas Huth, Red Hat Inc.
- *
- * This work is licensed under the terms of the GNU GPL, version 2
- * or later. See the COPYING file in the top-level directory.
- */
-#ifndef SLIRP_DHCPV6_H
-#define SLIRP_DHCPV6_H
-
-#define DHCPV6_SERVER_PORT 547
-
-#define ALLDHCP_MULTICAST { .s6_addr = \
-                            { 0xff, 0x02, 0x00, 0x00,\
-                            0x00, 0x00, 0x00, 0x00,\
-                            0x00, 0x00, 0x00, 0x00,\
-                            0x00, 0x01, 0x00, 0x02 } }
-
-#define in6_dhcp_multicast(a)\
-    in6_equal(a, &(struct in6_addr)ALLDHCP_MULTICAST)
-
-void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m);
-
-#endif
diff --git a/slirp/dnssearch.c b/slirp/dnssearch.c
deleted file mode 100644 (file)
index c459cec..0000000
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Domain search option for DHCP (RFC 3397)
- *
- * Copyright (c) 2012 Klaus Stengel
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "slirp.h"
-
-static const uint8_t RFC3397_OPT_DOMAIN_SEARCH = 119;
-static const uint8_t MAX_OPT_LEN = 255;
-static const uint8_t OPT_HEADER_LEN = 2;
-static const uint8_t REFERENCE_LEN = 2;
-
-struct compact_domain;
-
-typedef struct compact_domain {
-    struct compact_domain *self;
-    struct compact_domain *refdom;
-    uint8_t *labels;
-    size_t len;
-    size_t common_octets;
-} CompactDomain;
-
-static size_t
-domain_suffix_diffoff(const CompactDomain *a, const CompactDomain *b)
-{
-    size_t la = a->len, lb = b->len;
-    uint8_t *da = a->labels + la, *db = b->labels + lb;
-    size_t i, lm = (la < lb) ? la : lb;
-
-    for (i = 0; i < lm; i++) {
-        da--; db--;
-        if (*da != *db) {
-            break;
-        }
-    }
-    return i;
-}
-
-static int domain_suffix_ord(const void *cva, const void *cvb)
-{
-    const CompactDomain *a = cva, *b = cvb;
-    size_t la = a->len, lb = b->len;
-    size_t doff = domain_suffix_diffoff(a, b);
-    uint8_t ca = a->labels[la - doff];
-    uint8_t cb = b->labels[lb - doff];
-
-    if (ca < cb) {
-        return -1;
-    }
-    if (ca > cb) {
-        return 1;
-    }
-    if (la < lb) {
-        return -1;
-    }
-    if (la > lb) {
-        return 1;
-    }
-    return 0;
-}
-
-static size_t domain_common_label(CompactDomain *a, CompactDomain *b)
-{
-    size_t res, doff = domain_suffix_diffoff(a, b);
-    uint8_t *first_eq_pos = a->labels + (a->len - doff);
-    uint8_t *label = a->labels;
-
-    while (*label && label < first_eq_pos) {
-        label += *label + 1;
-    }
-    res = a->len - (label - a->labels);
-    /* only report if it can help to reduce the packet size */
-    return (res > REFERENCE_LEN) ? res : 0;
-}
-
-static void domain_fixup_order(CompactDomain *cd, size_t n)
-{
-    size_t i;
-
-    for (i = 0; i < n; i++) {
-        CompactDomain *cur = cd + i, *next = cd[i].self;
-
-        while (!cur->common_octets) {
-            CompactDomain *tmp = next->self; /* backup target value */
-
-            next->self = cur;
-            cur->common_octets++;
-
-            cur = next;
-            next = tmp;
-        }
-    }
-}
-
-static void domain_mklabels(CompactDomain *cd, const char *input)
-{
-    uint8_t *len_marker = cd->labels;
-    uint8_t *output = len_marker; /* pre-incremented */
-    const char *in = input;
-    char cur_chr;
-    size_t len = 0;
-
-    if (cd->len == 0) {
-        goto fail;
-    }
-    cd->len++;
-
-    do {
-        cur_chr = *in++;
-        if (cur_chr == '.' || cur_chr == '\0') {
-            len = output - len_marker;
-            if ((len == 0 && cur_chr == '.') || len >= 64) {
-                goto fail;
-            }
-            *len_marker = len;
-
-            output++;
-            len_marker = output;
-        } else {
-            output++;
-            *output = cur_chr;
-        }
-    } while (cur_chr != '\0');
-
-    /* ensure proper zero-termination */
-    if (len != 0) {
-        *len_marker = 0;
-        cd->len++;
-    }
-    return;
-
-fail:
-    g_warning("failed to parse domain name '%s'\n", input);
-    cd->len = 0;
-}
-
-static void
-domain_mkxrefs(CompactDomain *doms, CompactDomain *last, size_t depth)
-{
-    CompactDomain *i = doms, *target = doms;
-
-    do {
-        if (i->labels < target->labels) {
-            target = i;
-        }
-    } while (i++ != last);
-
-    for (i = doms; i != last; i++) {
-        CompactDomain *group_last;
-        size_t next_depth;
-
-        if (i->common_octets == depth) {
-            continue;
-        }
-
-        next_depth = -1;
-        for (group_last = i; group_last != last; group_last++) {
-            size_t co = group_last->common_octets;
-            if (co <= depth) {
-                break;
-            }
-            if (co < next_depth) {
-                next_depth = co;
-            }
-        }
-        domain_mkxrefs(i, group_last, next_depth);
-
-        i = group_last;
-        if (i == last) {
-            break;
-        }
-    }
-
-    if (depth == 0) {
-        return;
-    }
-
-    i = doms;
-    do {
-        if (i != target && i->refdom == NULL) {
-            i->refdom = target;
-            i->common_octets = depth;
-        }
-    } while (i++ != last);
-}
-
-static size_t domain_compactify(CompactDomain *domains, size_t n)
-{
-    uint8_t *start = domains->self->labels, *outptr = start;
-    size_t i;
-
-    for (i = 0; i < n; i++) {
-        CompactDomain *cd = domains[i].self;
-        CompactDomain *rd = cd->refdom;
-
-        if (rd != NULL) {
-            size_t moff = (rd->labels - start)
-                    + (rd->len - cd->common_octets);
-            if (moff < 0x3FFFu) {
-                cd->len -= cd->common_octets - 2;
-                cd->labels[cd->len - 1] = moff & 0xFFu;
-                cd->labels[cd->len - 2] = 0xC0u | (moff >> 8);
-            }
-        }
-
-        if (cd->labels != outptr) {
-            memmove(outptr, cd->labels, cd->len);
-            cd->labels = outptr;
-        }
-        outptr += cd->len;
-    }
-    return outptr - start;
-}
-
-int translate_dnssearch(Slirp *s, const char **names)
-{
-    size_t blocks, bsrc_start, bsrc_end, bdst_start;
-    size_t i, num_domains, memreq = 0;
-    uint8_t *result = NULL, *outptr;
-    CompactDomain *domains = NULL;
-    const char **nameptr = names;
-
-    while (*nameptr != NULL) {
-        nameptr++;
-    }
-
-    num_domains = nameptr - names;
-    if (num_domains == 0) {
-        return -2;
-    }
-
-    domains = g_malloc(num_domains * sizeof(*domains));
-
-    for (i = 0; i < num_domains; i++) {
-        size_t nlen = strlen(names[i]);
-        memreq += nlen + 2; /* 1 zero octet + 1 label length octet */
-        domains[i].self = domains + i;
-        domains[i].len = nlen;
-        domains[i].common_octets = 0;
-        domains[i].refdom = NULL;
-    }
-
-    /* reserve extra 2 header bytes for each 255 bytes of output */
-    memreq += DIV_ROUND_UP(memreq, MAX_OPT_LEN) * OPT_HEADER_LEN;
-    result = g_malloc(memreq * sizeof(*result));
-
-    outptr = result;
-    for (i = 0; i < num_domains; i++) {
-        domains[i].labels = outptr;
-        domain_mklabels(domains + i, names[i]);
-        outptr += domains[i].len;
-    }
-
-    if (outptr == result) {
-        g_free(domains);
-        g_free(result);
-        return -1;
-    }
-
-    qsort(domains, num_domains, sizeof(*domains), domain_suffix_ord);
-    domain_fixup_order(domains, num_domains);
-
-    for (i = 1; i < num_domains; i++) {
-        size_t cl = domain_common_label(domains + i - 1, domains + i);
-        domains[i - 1].common_octets = cl;
-    }
-
-    domain_mkxrefs(domains, domains + num_domains - 1, 0);
-    memreq = domain_compactify(domains, num_domains);
-
-    blocks = DIV_ROUND_UP(memreq, MAX_OPT_LEN);
-    bsrc_end = memreq;
-    bsrc_start = (blocks - 1) * MAX_OPT_LEN;
-    bdst_start = bsrc_start + blocks * OPT_HEADER_LEN;
-    memreq += blocks * OPT_HEADER_LEN;
-
-    while (blocks--) {
-        size_t len = bsrc_end - bsrc_start;
-        memmove(result + bdst_start, result + bsrc_start, len);
-        result[bdst_start - 2] = RFC3397_OPT_DOMAIN_SEARCH;
-        result[bdst_start - 1] = len;
-        bsrc_end = bsrc_start;
-        bsrc_start -= MAX_OPT_LEN;
-        bdst_start -= MAX_OPT_LEN + OPT_HEADER_LEN;
-    }
-
-    g_free(domains);
-    s->vdnssearch = result;
-    s->vdnssearch_len = memreq;
-    return 0;
-}
diff --git a/slirp/if.c b/slirp/if.c
deleted file mode 100644 (file)
index 1830cc3..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#include "slirp.h"
-
-static void
-ifs_insque(struct mbuf *ifm, struct mbuf *ifmhead)
-{
-       ifm->ifs_next = ifmhead->ifs_next;
-       ifmhead->ifs_next = ifm;
-       ifm->ifs_prev = ifmhead;
-       ifm->ifs_next->ifs_prev = ifm;
-}
-
-static void
-ifs_remque(struct mbuf *ifm)
-{
-       ifm->ifs_prev->ifs_next = ifm->ifs_next;
-       ifm->ifs_next->ifs_prev = ifm->ifs_prev;
-}
-
-void
-if_init(Slirp *slirp)
-{
-    slirp->if_fastq.qh_link = slirp->if_fastq.qh_rlink = &slirp->if_fastq;
-    slirp->if_batchq.qh_link = slirp->if_batchq.qh_rlink = &slirp->if_batchq;
-}
-
-/*
- * if_output: Queue packet into an output queue.
- * There are 2 output queue's, if_fastq and if_batchq.
- * Each output queue is a doubly linked list of double linked lists
- * of mbufs, each list belonging to one "session" (socket).  This
- * way, we can output packets fairly by sending one packet from each
- * session, instead of all the packets from one session, then all packets
- * from the next session, etc.  Packets on the if_fastq get absolute
- * priority, but if one session hogs the link, it gets "downgraded"
- * to the batchq until it runs out of packets, then it'll return
- * to the fastq (eg. if the user does an ls -alR in a telnet session,
- * it'll temporarily get downgraded to the batchq)
- */
-void
-if_output(struct socket *so, struct mbuf *ifm)
-{
-       Slirp *slirp = ifm->slirp;
-       struct mbuf *ifq;
-       int on_fastq = 1;
-
-       DEBUG_CALL("if_output");
-       DEBUG_ARG("so = %p", so);
-       DEBUG_ARG("ifm = %p", ifm);
-
-       /*
-        * First remove the mbuf from m_usedlist,
-        * since we're gonna use m_next and m_prev ourselves
-        * XXX Shouldn't need this, gotta change dtom() etc.
-        */
-       if (ifm->m_flags & M_USEDLIST) {
-               remque(ifm);
-               ifm->m_flags &= ~M_USEDLIST;
-       }
-
-       /*
-        * See if there's already a batchq list for this session.
-        * This can include an interactive session, which should go on fastq,
-        * but gets too greedy... hence it'll be downgraded from fastq to batchq.
-        * We mustn't put this packet back on the fastq (or we'll send it out of order)
-        * XXX add cache here?
-        */
-       if (so) {
-               for (ifq = (struct mbuf *) slirp->if_batchq.qh_rlink;
-                    (struct quehead *) ifq != &slirp->if_batchq;
-                    ifq = ifq->ifq_prev) {
-                       if (so == ifq->ifq_so) {
-                               /* A match! */
-                               ifm->ifq_so = so;
-                               ifs_insque(ifm, ifq->ifs_prev);
-                               goto diddit;
-                       }
-               }
-       }
-
-       /* No match, check which queue to put it on */
-       if (so && (so->so_iptos & IPTOS_LOWDELAY)) {
-               ifq = (struct mbuf *) slirp->if_fastq.qh_rlink;
-               on_fastq = 1;
-               /*
-                * Check if this packet is a part of the last
-                * packet's session
-                */
-               if (ifq->ifq_so == so) {
-                       ifm->ifq_so = so;
-                       ifs_insque(ifm, ifq->ifs_prev);
-                       goto diddit;
-               }
-        } else {
-               ifq = (struct mbuf *) slirp->if_batchq.qh_rlink;
-        }
-
-       /* Create a new doubly linked list for this session */
-       ifm->ifq_so = so;
-       ifs_init(ifm);
-       insque(ifm, ifq);
-
-diddit:
-       if (so) {
-               /* Update *_queued */
-               so->so_queued++;
-               so->so_nqueued++;
-               /*
-                * Check if the interactive session should be downgraded to
-                * the batchq.  A session is downgraded if it has queued 6
-                * packets without pausing, and at least 3 of those packets
-                * have been sent over the link
-                * (XXX These are arbitrary numbers, probably not optimal..)
-                */
-               if (on_fastq && ((so->so_nqueued >= 6) &&
-                                (so->so_nqueued - so->so_queued) >= 3)) {
-
-                       /* Remove from current queue... */
-                       remque(ifm->ifs_next);
-
-                       /* ...And insert in the new.  That'll teach ya! */
-                       insque(ifm->ifs_next, &slirp->if_batchq);
-               }
-       }
-
-       /*
-        * This prevents us from malloc()ing too many mbufs
-        */
-       if_start(ifm->slirp);
-}
-
-/*
- * Send one packet from each session.
- * If there are packets on the fastq, they are sent FIFO, before
- * everything else.  Then we choose the first packet from each
- * batchq session (socket) and send it.
- * For example, if there are 3 ftp sessions fighting for bandwidth,
- * one packet will be sent from the first session, then one packet
- * from the second session, then one packet from the third.
- */
-void if_start(Slirp *slirp)
-{
-    uint64_t now = slirp->cb->clock_get_ns(slirp->opaque);
-    bool from_batchq = false;
-    struct mbuf *ifm, *ifm_next, *ifqt;
-
-    DEBUG_CALL("if_start");
-
-    if (slirp->if_start_busy) {
-        return;
-    }
-    slirp->if_start_busy = true;
-
-    struct mbuf *batch_head = NULL;
-    if (slirp->if_batchq.qh_link != &slirp->if_batchq) {
-        batch_head = (struct mbuf *) slirp->if_batchq.qh_link;
-    }
-
-    if (slirp->if_fastq.qh_link != &slirp->if_fastq) {
-        ifm_next = (struct mbuf *) slirp->if_fastq.qh_link;
-    } else if (batch_head) {
-        /* Nothing on fastq, pick up from batchq */
-        ifm_next = batch_head;
-        from_batchq = true;
-    } else {
-        ifm_next = NULL;
-    }
-
-    while (ifm_next) {
-        ifm = ifm_next;
-
-        ifm_next = ifm->ifq_next;
-        if ((struct quehead *) ifm_next == &slirp->if_fastq) {
-            /* No more packets in fastq, switch to batchq */
-            ifm_next = batch_head;
-            from_batchq = true;
-        }
-        if ((struct quehead *) ifm_next == &slirp->if_batchq) {
-            /* end of batchq */
-            ifm_next = NULL;
-        }
-
-        /* Try to send packet unless it already expired */
-        if (ifm->expiration_date >= now && !if_encap(slirp, ifm)) {
-            /* Packet is delayed due to pending ARP or NDP resolution */
-            continue;
-        }
-
-        /* Remove it from the queue */
-        ifqt = ifm->ifq_prev;
-        remque(ifm);
-
-        /* If there are more packets for this session, re-queue them */
-        if (ifm->ifs_next != ifm) {
-            struct mbuf *next = ifm->ifs_next;
-
-            insque(next, ifqt);
-            ifs_remque(ifm);
-            if (!from_batchq) {
-                ifm_next = next;
-            }
-        }
-
-        /* Update so_queued */
-        if (ifm->ifq_so && --ifm->ifq_so->so_queued == 0) {
-            /* If there's no more queued, reset nqueued */
-            ifm->ifq_so->so_nqueued = 0;
-        }
-
-        m_free(ifm);
-    }
-
-    slirp->if_start_busy = false;
-}
diff --git a/slirp/if.h b/slirp/if.h
deleted file mode 100644 (file)
index 69569c1..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#ifndef IF_H
-#define IF_H
-
-#define IF_COMPRESS    0x01    /* We want compression */
-#define IF_NOCOMPRESS  0x02    /* Do not do compression */
-#define IF_AUTOCOMP    0x04    /* Autodetect (default) */
-#define IF_NOCIDCOMP   0x08    /* CID compression */
-
-#define IF_MTU 1500
-#define IF_MRU 1500
-#define        IF_COMP IF_AUTOCOMP     /* Flags for compression */
-
-/* 2 for alignment, 14 for ethernet */
-#define IF_MAXLINKHDR (2 + ETH_HLEN)
-
-#endif
diff --git a/slirp/ip.h b/slirp/ip.h
deleted file mode 100644 (file)
index 73a4d2a..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 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. 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.
- *
- *     @(#)ip.h        8.1 (Berkeley) 6/10/93
- * ip.h,v 1.3 1994/08/21 05:27:30 paul Exp
- */
-
-#ifndef IP_H
-#define IP_H
-
-#include <glib.h>
-
-#if G_BYTE_ORDER == G_BIG_ENDIAN
-# undef NTOHL
-# undef NTOHS
-# undef HTONL
-# undef HTONS
-# define NTOHL(d)
-# define NTOHS(d)
-# define HTONL(d)
-# define HTONS(d)
-#else
-# ifndef NTOHL
-#  define NTOHL(d) ((d) = ntohl((d)))
-# endif
-# ifndef NTOHS
-#  define NTOHS(d) ((d) = ntohs((uint16_t)(d)))
-# endif
-# ifndef HTONL
-#  define HTONL(d) ((d) = htonl((d)))
-# endif
-# ifndef HTONS
-#  define HTONS(d) ((d) = htons((uint16_t)(d)))
-# endif
-#endif
-
-typedef uint32_t n_long;                 /* long as received from the net */
-
-/*
- * Definitions for internet protocol version 4.
- * Per RFC 791, September 1981.
- */
-#define        IPVERSION       4
-
-/*
- * Structure of an internet header, naked of options.
- */
-struct ip {
-#if G_BYTE_ORDER == G_BIG_ENDIAN
-       uint8_t ip_v:4,                 /* version */
-               ip_hl:4;                /* header length */
-#else
-       uint8_t ip_hl:4,                /* header length */
-               ip_v:4;                 /* version */
-#endif
-       uint8_t         ip_tos;                 /* type of service */
-       uint16_t        ip_len;                 /* total length */
-       uint16_t        ip_id;                  /* identification */
-       uint16_t        ip_off;                 /* fragment offset field */
-#define        IP_DF 0x4000                    /* don't fragment flag */
-#define        IP_MF 0x2000                    /* more fragments flag */
-#define        IP_OFFMASK 0x1fff               /* mask for fragmenting bits */
-       uint8_t ip_ttl;                 /* time to live */
-       uint8_t ip_p;                   /* protocol */
-       uint16_t        ip_sum;                 /* checksum */
-       struct  in_addr ip_src,ip_dst;  /* source and dest address */
-} SLIRP_PACKED;
-
-#define        IP_MAXPACKET    65535           /* maximum packet size */
-
-/*
- * Definitions for IP type of service (ip_tos)
- */
-#define        IPTOS_LOWDELAY          0x10
-#define        IPTOS_THROUGHPUT        0x08
-#define        IPTOS_RELIABILITY       0x04
-
-/*
- * Definitions for options.
- */
-#define        IPOPT_COPIED(o)         ((o)&0x80)
-#define        IPOPT_CLASS(o)          ((o)&0x60)
-#define        IPOPT_NUMBER(o)         ((o)&0x1f)
-
-#define        IPOPT_CONTROL           0x00
-#define        IPOPT_RESERVED1         0x20
-#define        IPOPT_DEBMEAS           0x40
-#define        IPOPT_RESERVED2         0x60
-
-#define        IPOPT_EOL               0               /* end of option list */
-#define        IPOPT_NOP               1               /* no operation */
-
-#define        IPOPT_RR                7               /* record packet route */
-#define        IPOPT_TS                68              /* timestamp */
-#define        IPOPT_SECURITY          130             /* provide s,c,h,tcc */
-#define        IPOPT_LSRR              131             /* loose source route */
-#define        IPOPT_SATID             136             /* satnet id */
-#define        IPOPT_SSRR              137             /* strict source route */
-
-/*
- * Offsets to fields in options other than EOL and NOP.
- */
-#define        IPOPT_OPTVAL            0               /* option ID */
-#define        IPOPT_OLEN              1               /* option length */
-#define IPOPT_OFFSET           2               /* offset within option */
-#define        IPOPT_MINOFF            4               /* min value of above */
-
-/*
- * Time stamp option structure.
- */
-struct ip_timestamp {
-       uint8_t ipt_code;               /* IPOPT_TS */
-       uint8_t ipt_len;                /* size of structure (variable) */
-       uint8_t ipt_ptr;                /* index of current entry */
-#if G_BYTE_ORDER == G_BIG_ENDIAN
-       uint8_t ipt_oflw:4,             /* overflow counter */
-               ipt_flg:4;              /* flags, see below */
-#else
-       uint8_t ipt_flg:4,              /* flags, see below */
-               ipt_oflw:4;             /* overflow counter */
-#endif
-       union ipt_timestamp {
-               n_long  ipt_time[1];
-               struct  ipt_ta {
-                       struct in_addr ipt_addr;
-                       n_long ipt_time;
-               } ipt_ta[1];
-       } ipt_timestamp;
-} SLIRP_PACKED;
-
-/* flag bits for ipt_flg */
-#define        IPOPT_TS_TSONLY         0               /* timestamps only */
-#define        IPOPT_TS_TSANDADDR      1               /* timestamps and addresses */
-#define        IPOPT_TS_PRESPEC        3               /* specified modules only */
-
-/* bits for security (not byte swapped) */
-#define        IPOPT_SECUR_UNCLASS     0x0000
-#define        IPOPT_SECUR_CONFID      0xf135
-#define        IPOPT_SECUR_EFTO        0x789a
-#define        IPOPT_SECUR_MMMM        0xbc4d
-#define        IPOPT_SECUR_RESTR       0xaf13
-#define        IPOPT_SECUR_SECRET      0xd788
-#define        IPOPT_SECUR_TOPSECRET   0x6bc5
-
-/*
- * Internet implementation parameters.
- */
-#define        MAXTTL          255             /* maximum time to live (seconds) */
-#define        IPDEFTTL        64              /* default ttl, from RFC 1340 */
-#define        IPFRAGTTL       60              /* time to live for frags, slowhz */
-#define        IPTTLDEC        1               /* subtracted when forwarding */
-
-#define        IP_MSS          576             /* default maximum segment size */
-
-#if GLIB_SIZEOF_VOID_P == 4
-struct mbuf_ptr {
-       struct mbuf *mptr;
-       uint32_t dummy;
-} SLIRP_PACKED;
-#else
-struct mbuf_ptr {
-       struct mbuf *mptr;
-} SLIRP_PACKED;
-#endif
-struct qlink {
-       void *next, *prev;
-};
-
-/*
- * Overlay for ip header used by other protocols (tcp, udp).
- */
-struct ipovly {
-       struct mbuf_ptr ih_mbuf;        /* backpointer to mbuf */
-       uint8_t ih_x1;                  /* (unused) */
-       uint8_t ih_pr;                  /* protocol */
-       uint16_t        ih_len;                 /* protocol length */
-       struct  in_addr ih_src;         /* source internet address */
-       struct  in_addr ih_dst;         /* destination internet address */
-} SLIRP_PACKED;
-
-/*
- * Ip reassembly queue structure.  Each fragment
- * being reassembled is attached to one of these structures.
- * They are timed out after ipq_ttl drops to 0, and may also
- * be reclaimed if memory becomes tight.
- * size 28 bytes
- */
-struct ipq {
-        struct qlink frag_link;                        /* to ip headers of fragments */
-       struct qlink ip_link;                           /* to other reass headers */
-       uint8_t ipq_ttl;                /* time for reass q to live */
-       uint8_t ipq_p;                  /* protocol of this fragment */
-       uint16_t        ipq_id;                 /* sequence id for reassembly */
-       struct  in_addr ipq_src,ipq_dst;
-};
-
-/*
- * Ip header, when holding a fragment.
- *
- * Note: ipf_link must be at same offset as frag_link above
- */
-struct ipasfrag {
-       struct qlink ipf_link;
-       struct ip ipf_ip;
-};
-
-G_STATIC_ASSERT(offsetof(struct ipq, frag_link) ==
-                offsetof(struct ipasfrag, ipf_link));
-
-#define ipf_off      ipf_ip.ip_off
-#define ipf_tos      ipf_ip.ip_tos
-#define ipf_len      ipf_ip.ip_len
-#define ipf_next     ipf_link.next
-#define ipf_prev     ipf_link.prev
-
-#endif
diff --git a/slirp/ip6.h b/slirp/ip6.h
deleted file mode 100644 (file)
index 1b3364f..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (c) 2013
- * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
- */
-
-#ifndef SLIRP_IP6_H
-#define SLIRP_IP6_H
-
-#include <glib.h>
-#include <string.h>
-
-#define ALLNODES_MULTICAST  { .s6_addr = \
-                            { 0xff, 0x02, 0x00, 0x00,\
-                            0x00, 0x00, 0x00, 0x00,\
-                            0x00, 0x00, 0x00, 0x00,\
-                            0x00, 0x00, 0x00, 0x01 } }
-
-#define SOLICITED_NODE_PREFIX { .s6_addr = \
-                            { 0xff, 0x02, 0x00, 0x00,\
-                            0x00, 0x00, 0x00, 0x00,\
-                            0x00, 0x00, 0x00, 0x01,\
-                            0xff, 0x00, 0x00, 0x00 } }
-
-#define LINKLOCAL_ADDR  { .s6_addr = \
-                        { 0xfe, 0x80, 0x00, 0x00,\
-                        0x00, 0x00, 0x00, 0x00,\
-                        0x00, 0x00, 0x00, 0x00,\
-                        0x00, 0x00, 0x00, 0x02 } }
-
-#define ZERO_ADDR  { .s6_addr = \
-                        { 0x00, 0x00, 0x00, 0x00,\
-                        0x00, 0x00, 0x00, 0x00,\
-                        0x00, 0x00, 0x00, 0x00,\
-                        0x00, 0x00, 0x00, 0x00 } }
-
-static inline bool in6_equal(const struct in6_addr *a, const struct in6_addr *b)
-{
-    return memcmp(a, b, sizeof(*a)) == 0;
-}
-
-static inline bool in6_equal_net(const struct in6_addr *a,
-                                 const struct in6_addr *b,
-                                 int prefix_len)
-{
-    if (memcmp(a, b, prefix_len / 8) != 0) {
-        return 0;
-    }
-
-    if (prefix_len % 8 == 0) {
-        return 1;
-    }
-
-    return a->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8))
-        == b->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8));
-}
-
-static inline bool in6_equal_mach(const struct in6_addr *a,
-                                  const struct in6_addr *b,
-                                  int prefix_len)
-{
-    if (memcmp(&(a->s6_addr[DIV_ROUND_UP(prefix_len, 8)]),
-               &(b->s6_addr[DIV_ROUND_UP(prefix_len, 8)]),
-               16 - DIV_ROUND_UP(prefix_len, 8)) != 0) {
-        return 0;
-    }
-
-    if (prefix_len % 8 == 0) {
-        return 1;
-    }
-
-    return (a->s6_addr[prefix_len / 8] & ((1U << (8 - (prefix_len % 8))) - 1))
-        == (b->s6_addr[prefix_len / 8] & ((1U << (8 - (prefix_len % 8))) - 1));
-}
-
-
-#define in6_equal_router(a)\
-    ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len)\
-      && in6_equal_mach(a, &slirp->vhost_addr6, slirp->vprefix_len))\
-  || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64)\
-      && in6_equal_mach(a, &slirp->vhost_addr6, 64)))
-
-#define in6_equal_dns(a)\
-    ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len)\
-      && in6_equal_mach(a, &slirp->vnameserver_addr6, slirp->vprefix_len))\
-  || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64)\
-      && in6_equal_mach(a, &slirp->vnameserver_addr6, 64)))
-
-#define in6_equal_host(a)\
-    (in6_equal_router(a) || in6_equal_dns(a))
-
-#define in6_solicitednode_multicast(a)\
-    (in6_equal_net(a, &(struct in6_addr)SOLICITED_NODE_PREFIX, 104))
-
-#define in6_zero(a)\
-    (in6_equal(a, &(struct in6_addr)ZERO_ADDR))
-
-/* Compute emulated host MAC address from its ipv6 address */
-static inline void in6_compute_ethaddr(struct in6_addr ip,
-                                       uint8_t eth[ETH_ALEN])
-{
-    eth[0] = 0x52;
-    eth[1] = 0x56;
-    memcpy(&eth[2], &ip.s6_addr[16 - (ETH_ALEN - 2)], ETH_ALEN - 2);
-}
-
-/*
- * Definitions for internet protocol version 6.
- * Per RFC 2460, December 1998.
- */
-#define IP6VERSION      6
-#define IP6_HOP_LIMIT 255
-
-/*
- * Structure of an internet header, naked of options.
- */
-struct ip6 {
-#if G_BYTE_ORDER == G_BIG_ENDIAN
-    uint32_t
-        ip_v:4,         /* version */
-        ip_tc_hi:4,     /* traffic class */
-        ip_tc_lo:4,
-        ip_fl_hi:4,     /* flow label */
-        ip_fl_lo:16;
-#else
-    uint32_t
-        ip_tc_hi:4,
-        ip_v:4,
-        ip_fl_hi:4,
-        ip_tc_lo:4,
-        ip_fl_lo:16;
-#endif
-    uint16_t    ip_pl;               /* payload length */
-    uint8_t     ip_nh;               /* next header */
-    uint8_t     ip_hl;               /* hop limit */
-    struct in6_addr ip_src, ip_dst;  /* source and dest address */
-};
-
-/*
- * IPv6 pseudo-header used by upper-layer protocols
- */
-struct ip6_pseudohdr {
-    struct      in6_addr ih_src;  /* source internet address */
-    struct      in6_addr ih_dst;  /* destination internet address */
-    uint32_t    ih_pl;            /* upper-layer packet length */
-    uint16_t    ih_zero_hi;       /* zero */
-    uint8_t     ih_zero_lo;       /* zero */
-    uint8_t     ih_nh;            /* next header */
-};
-
-/*
- * We don't want to mark these ip6 structs as packed as they are naturally
- * correctly aligned; instead assert that there is no stray padding.
- * If we marked the struct as packed then we would be unable to take
- * the address of any of the fields in it.
- */
-G_STATIC_ASSERT(sizeof(struct ip6) == 40);
-G_STATIC_ASSERT(sizeof(struct ip6_pseudohdr) == 40);
-
-#endif
diff --git a/slirp/ip6_icmp.c b/slirp/ip6_icmp.c
deleted file mode 100644 (file)
index c1e3d30..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Copyright (c) 2013
- * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
- */
-
-#include "slirp.h"
-#include "ip6_icmp.h"
-
-#define NDP_Interval g_rand_int_range(slirp->grand, \
-        NDP_MinRtrAdvInterval, NDP_MaxRtrAdvInterval)
-
-static void ra_timer_handler(void *opaque)
-{
-    Slirp *slirp = opaque;
-
-    slirp->cb->timer_mod(slirp->ra_timer,
-        slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS + NDP_Interval,
-        slirp->opaque);
-    ndp_send_ra(slirp);
-}
-
-void icmp6_init(Slirp *slirp)
-{
-    if (!slirp->in6_enabled) {
-        return;
-    }
-
-    slirp->ra_timer = slirp->cb->timer_new(ra_timer_handler, slirp, slirp->opaque);
-    slirp->cb->timer_mod(slirp->ra_timer,
-        slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS + NDP_Interval,
-        slirp->opaque);
-}
-
-void icmp6_cleanup(Slirp *slirp)
-{
-    if (!slirp->in6_enabled) {
-        return;
-    }
-
-    slirp->cb->timer_free(slirp->ra_timer, slirp->opaque);
-}
-
-static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
-        struct icmp6 *icmp)
-{
-    struct mbuf *t = m_get(slirp);
-    t->m_len = sizeof(struct ip6) + ntohs(ip->ip_pl);
-    memcpy(t->m_data, m->m_data, t->m_len);
-
-    /* IPv6 Packet */
-    struct ip6 *rip = mtod(t, struct ip6 *);
-    rip->ip_dst = ip->ip_src;
-    rip->ip_src = ip->ip_dst;
-
-    /* ICMPv6 packet */
-    t->m_data += sizeof(struct ip6);
-    struct icmp6 *ricmp = mtod(t, struct icmp6 *);
-    ricmp->icmp6_type = ICMP6_ECHO_REPLY;
-    ricmp->icmp6_cksum = 0;
-
-    /* Checksum */
-    t->m_data -= sizeof(struct ip6);
-    ricmp->icmp6_cksum = ip6_cksum(t);
-
-    ip6_output(NULL, t, 0);
-}
-
-void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
-{
-    Slirp *slirp = m->slirp;
-    struct mbuf *t;
-    struct ip6 *ip = mtod(m, struct ip6 *);
-    char addrstr[INET6_ADDRSTRLEN];
-
-    DEBUG_CALL("icmp6_send_error");
-    DEBUG_ARG("type = %d, code = %d", type, code);
-
-    if (IN6_IS_ADDR_MULTICAST(&ip->ip_src) ||
-            in6_zero(&ip->ip_src)) {
-        /* TODO icmp error? */
-        return;
-    }
-
-    t = m_get(slirp);
-
-    /* IPv6 packet */
-    struct ip6 *rip = mtod(t, struct ip6 *);
-    rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
-    rip->ip_dst = ip->ip_src;
-    inet_ntop(AF_INET6, &rip->ip_dst, addrstr, INET6_ADDRSTRLEN);
-    DEBUG_ARG("target = %s", addrstr);
-
-    rip->ip_nh = IPPROTO_ICMPV6;
-    const int error_data_len = MIN(m->m_len,
-            IF_MTU - (sizeof(struct ip6) + ICMP6_ERROR_MINLEN));
-    rip->ip_pl = htons(ICMP6_ERROR_MINLEN + error_data_len);
-    t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
-
-    /* ICMPv6 packet */
-    t->m_data += sizeof(struct ip6);
-    struct icmp6 *ricmp = mtod(t, struct icmp6 *);
-    ricmp->icmp6_type = type;
-    ricmp->icmp6_code = code;
-    ricmp->icmp6_cksum = 0;
-
-    switch (type) {
-    case ICMP6_UNREACH:
-    case ICMP6_TIMXCEED:
-        ricmp->icmp6_err.unused = 0;
-        break;
-    case ICMP6_TOOBIG:
-        ricmp->icmp6_err.mtu = htonl(IF_MTU);
-        break;
-    case ICMP6_PARAMPROB:
-        /* TODO: Handle this case */
-        break;
-    default:
-        g_assert_not_reached();
-        break;
-    }
-    t->m_data += ICMP6_ERROR_MINLEN;
-    memcpy(t->m_data, m->m_data, error_data_len);
-
-    /* Checksum */
-    t->m_data -= ICMP6_ERROR_MINLEN;
-    t->m_data -= sizeof(struct ip6);
-    ricmp->icmp6_cksum = ip6_cksum(t);
-
-    ip6_output(NULL, t, 0);
-}
-
-/*
- * Send NDP Router Advertisement
- */
-void ndp_send_ra(Slirp *slirp)
-{
-    DEBUG_CALL("ndp_send_ra");
-
-    /* Build IPv6 packet */
-    struct mbuf *t = m_get(slirp);
-    struct ip6 *rip = mtod(t, struct ip6 *);
-    size_t pl_size = 0;
-    struct in6_addr addr;
-    uint32_t scope_id;
-
-    rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
-    rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
-    rip->ip_nh = IPPROTO_ICMPV6;
-
-    /* Build ICMPv6 packet */
-    t->m_data += sizeof(struct ip6);
-    struct icmp6 *ricmp = mtod(t, struct icmp6 *);
-    ricmp->icmp6_type = ICMP6_NDP_RA;
-    ricmp->icmp6_code = 0;
-    ricmp->icmp6_cksum = 0;
-
-    /* NDP */
-    ricmp->icmp6_nra.chl = NDP_AdvCurHopLimit;
-    ricmp->icmp6_nra.M = NDP_AdvManagedFlag;
-    ricmp->icmp6_nra.O = NDP_AdvOtherConfigFlag;
-    ricmp->icmp6_nra.reserved = 0;
-    ricmp->icmp6_nra.lifetime = htons(NDP_AdvDefaultLifetime);
-    ricmp->icmp6_nra.reach_time = htonl(NDP_AdvReachableTime);
-    ricmp->icmp6_nra.retrans_time = htonl(NDP_AdvRetransTime);
-    t->m_data += ICMP6_NDP_RA_MINLEN;
-    pl_size += ICMP6_NDP_RA_MINLEN;
-
-    /* Source link-layer address (NDP option) */
-    struct ndpopt *opt = mtod(t, struct ndpopt *);
-    opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
-    opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
-    in6_compute_ethaddr(rip->ip_src, opt->ndpopt_linklayer);
-    t->m_data += NDPOPT_LINKLAYER_LEN;
-    pl_size += NDPOPT_LINKLAYER_LEN;
-
-    /* Prefix information (NDP option) */
-    struct ndpopt *opt2 = mtod(t, struct ndpopt *);
-    opt2->ndpopt_type = NDPOPT_PREFIX_INFO;
-    opt2->ndpopt_len = NDPOPT_PREFIXINFO_LEN / 8;
-    opt2->ndpopt_prefixinfo.prefix_length = slirp->vprefix_len;
-    opt2->ndpopt_prefixinfo.L = 1;
-    opt2->ndpopt_prefixinfo.A = 1;
-    opt2->ndpopt_prefixinfo.reserved1 = 0;
-    opt2->ndpopt_prefixinfo.valid_lt = htonl(NDP_AdvValidLifetime);
-    opt2->ndpopt_prefixinfo.pref_lt = htonl(NDP_AdvPrefLifetime);
-    opt2->ndpopt_prefixinfo.reserved2 = 0;
-    opt2->ndpopt_prefixinfo.prefix = slirp->vprefix_addr6;
-    t->m_data += NDPOPT_PREFIXINFO_LEN;
-    pl_size += NDPOPT_PREFIXINFO_LEN;
-
-    /* Prefix information (NDP option) */
-    if (get_dns6_addr(&addr, &scope_id) >= 0) {
-        /* Host system does have an IPv6 DNS server, announce our proxy.  */
-        struct ndpopt *opt3 = mtod(t, struct ndpopt *);
-        opt3->ndpopt_type = NDPOPT_RDNSS;
-        opt3->ndpopt_len = NDPOPT_RDNSS_LEN / 8;
-        opt3->ndpopt_rdnss.reserved = 0;
-        opt3->ndpopt_rdnss.lifetime = htonl(2 * NDP_MaxRtrAdvInterval);
-        opt3->ndpopt_rdnss.addr = slirp->vnameserver_addr6;
-        t->m_data += NDPOPT_RDNSS_LEN;
-        pl_size += NDPOPT_RDNSS_LEN;
-    }
-
-    rip->ip_pl = htons(pl_size);
-    t->m_data -= sizeof(struct ip6) + pl_size;
-    t->m_len = sizeof(struct ip6) + pl_size;
-
-    /* ICMPv6 Checksum */
-    ricmp->icmp6_cksum = ip6_cksum(t);
-
-    ip6_output(NULL, t, 0);
-}
-
-/*
- * Send NDP Neighbor Solitication
- */
-void ndp_send_ns(Slirp *slirp, struct in6_addr addr)
-{
-    char addrstr[INET6_ADDRSTRLEN];
-
-    inet_ntop(AF_INET6, &addr, addrstr, INET6_ADDRSTRLEN);
-
-    DEBUG_CALL("ndp_send_ns");
-    DEBUG_ARG("target = %s", addrstr);
-
-    /* Build IPv6 packet */
-    struct mbuf *t = m_get(slirp);
-    struct ip6 *rip = mtod(t, struct ip6 *);
-    rip->ip_src = slirp->vhost_addr6;
-    rip->ip_dst = (struct in6_addr)SOLICITED_NODE_PREFIX;
-    memcpy(&rip->ip_dst.s6_addr[13], &addr.s6_addr[13], 3);
-    rip->ip_nh = IPPROTO_ICMPV6;
-    rip->ip_pl = htons(ICMP6_NDP_NS_MINLEN + NDPOPT_LINKLAYER_LEN);
-    t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
-
-    /* Build ICMPv6 packet */
-    t->m_data += sizeof(struct ip6);
-    struct icmp6 *ricmp = mtod(t, struct icmp6 *);
-    ricmp->icmp6_type = ICMP6_NDP_NS;
-    ricmp->icmp6_code = 0;
-    ricmp->icmp6_cksum = 0;
-
-    /* NDP */
-    ricmp->icmp6_nns.reserved = 0;
-    ricmp->icmp6_nns.target = addr;
-
-    /* Build NDP option */
-    t->m_data += ICMP6_NDP_NS_MINLEN;
-    struct ndpopt *opt = mtod(t, struct ndpopt *);
-    opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
-    opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
-    in6_compute_ethaddr(slirp->vhost_addr6, opt->ndpopt_linklayer);
-
-    /* ICMPv6 Checksum */
-    t->m_data -= ICMP6_NDP_NA_MINLEN;
-    t->m_data -= sizeof(struct ip6);
-    ricmp->icmp6_cksum = ip6_cksum(t);
-
-    ip6_output(NULL, t, 1);
-}
-
-/*
- * Send NDP Neighbor Advertisement
- */
-static void ndp_send_na(Slirp *slirp, struct ip6 *ip, struct icmp6 *icmp)
-{
-    /* Build IPv6 packet */
-    struct mbuf *t = m_get(slirp);
-    struct ip6 *rip = mtod(t, struct ip6 *);
-    rip->ip_src = icmp->icmp6_nns.target;
-    if (in6_zero(&ip->ip_src)) {
-        rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
-    } else {
-        rip->ip_dst = ip->ip_src;
-    }
-    rip->ip_nh = IPPROTO_ICMPV6;
-    rip->ip_pl = htons(ICMP6_NDP_NA_MINLEN
-                        + NDPOPT_LINKLAYER_LEN);
-    t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
-
-    /* Build ICMPv6 packet */
-    t->m_data += sizeof(struct ip6);
-    struct icmp6 *ricmp = mtod(t, struct icmp6 *);
-    ricmp->icmp6_type = ICMP6_NDP_NA;
-    ricmp->icmp6_code = 0;
-    ricmp->icmp6_cksum = 0;
-
-    /* NDP */
-    ricmp->icmp6_nna.R = NDP_IsRouter;
-    ricmp->icmp6_nna.S = !IN6_IS_ADDR_MULTICAST(&rip->ip_dst);
-    ricmp->icmp6_nna.O = 1;
-    ricmp->icmp6_nna.reserved_hi = 0;
-    ricmp->icmp6_nna.reserved_lo = 0;
-    ricmp->icmp6_nna.target = icmp->icmp6_nns.target;
-
-    /* Build NDP option */
-    t->m_data += ICMP6_NDP_NA_MINLEN;
-    struct ndpopt *opt = mtod(t, struct ndpopt *);
-    opt->ndpopt_type = NDPOPT_LINKLAYER_TARGET;
-    opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
-    in6_compute_ethaddr(ricmp->icmp6_nna.target,
-                    opt->ndpopt_linklayer);
-
-    /* ICMPv6 Checksum */
-    t->m_data -= ICMP6_NDP_NA_MINLEN;
-    t->m_data -= sizeof(struct ip6);
-    ricmp->icmp6_cksum = ip6_cksum(t);
-
-    ip6_output(NULL, t, 0);
-}
-
-/*
- * Process a NDP message
- */
-static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
-        struct icmp6 *icmp)
-{
-    m->m_len += ETH_HLEN;
-    m->m_data -= ETH_HLEN;
-    struct ethhdr *eth = mtod(m, struct ethhdr *);
-    m->m_len -= ETH_HLEN;
-    m->m_data += ETH_HLEN;
-
-    switch (icmp->icmp6_type) {
-    case ICMP6_NDP_RS:
-        DEBUG_CALL(" type = Router Solicitation");
-        if (ip->ip_hl == 255
-                && icmp->icmp6_code == 0
-                && ntohs(ip->ip_pl) >= ICMP6_NDP_RS_MINLEN) {
-            /* Gratuitous NDP */
-            ndp_table_add(slirp, ip->ip_src, eth->h_source);
-
-            ndp_send_ra(slirp);
-        }
-        break;
-
-    case ICMP6_NDP_RA:
-        DEBUG_CALL(" type = Router Advertisement");
-        slirp->cb->guest_error("Warning: guest sent NDP RA, but shouldn't",
-                               slirp->opaque);
-        break;
-
-    case ICMP6_NDP_NS:
-        DEBUG_CALL(" type = Neighbor Solicitation");
-        if (ip->ip_hl == 255
-                && icmp->icmp6_code == 0
-                && !IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nns.target)
-                && ntohs(ip->ip_pl) >= ICMP6_NDP_NS_MINLEN
-                && (!in6_zero(&ip->ip_src)
-                    || in6_solicitednode_multicast(&ip->ip_dst))) {
-            if (in6_equal_host(&icmp->icmp6_nns.target)) {
-                /* Gratuitous NDP */
-                ndp_table_add(slirp, ip->ip_src, eth->h_source);
-                ndp_send_na(slirp, ip, icmp);
-            }
-        }
-        break;
-
-    case ICMP6_NDP_NA:
-        DEBUG_CALL(" type = Neighbor Advertisement");
-        if (ip->ip_hl == 255
-                && icmp->icmp6_code == 0
-                && ntohs(ip->ip_pl) >= ICMP6_NDP_NA_MINLEN
-                && !IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nna.target)
-                && (!IN6_IS_ADDR_MULTICAST(&ip->ip_dst)
-                    || icmp->icmp6_nna.S == 0)) {
-            ndp_table_add(slirp, ip->ip_src, eth->h_source);
-        }
-        break;
-
-    case ICMP6_NDP_REDIRECT:
-        DEBUG_CALL(" type = Redirect");
-        slirp->cb->guest_error(
-            "Warning: guest sent NDP REDIRECT, but shouldn't", slirp->opaque);
-        break;
-    }
-}
-
-/*
- * Process a received ICMPv6 message.
- */
-void icmp6_input(struct mbuf *m)
-{
-    struct icmp6 *icmp;
-    struct ip6 *ip = mtod(m, struct ip6 *);
-    Slirp *slirp = m->slirp;
-    int hlen = sizeof(struct ip6);
-
-    DEBUG_CALL("icmp6_input");
-    DEBUG_ARG("m = %p", m);
-    DEBUG_ARG("m_len = %d", m->m_len);
-
-    if (ntohs(ip->ip_pl) < ICMP6_MINLEN) {
-        goto end;
-    }
-
-    if (ip6_cksum(m)) {
-        goto end;
-    }
-
-    m->m_len -= hlen;
-    m->m_data += hlen;
-    icmp = mtod(m, struct icmp6 *);
-    m->m_len += hlen;
-    m->m_data -= hlen;
-
-    DEBUG_ARG("icmp6_type = %d", icmp->icmp6_type);
-    switch (icmp->icmp6_type) {
-    case ICMP6_ECHO_REQUEST:
-        if (in6_equal_host(&ip->ip_dst)) {
-            icmp6_send_echoreply(m, slirp, ip, icmp);
-        } else {
-            /* TODO */
-            g_critical("external icmpv6 not supported yet");
-        }
-        break;
-
-    case ICMP6_NDP_RS:
-    case ICMP6_NDP_RA:
-    case ICMP6_NDP_NS:
-    case ICMP6_NDP_NA:
-    case ICMP6_NDP_REDIRECT:
-        ndp_input(m, slirp, ip, icmp);
-        break;
-
-    case ICMP6_UNREACH:
-    case ICMP6_TOOBIG:
-    case ICMP6_TIMXCEED:
-    case ICMP6_PARAMPROB:
-        /* XXX? report error? close socket? */
-    default:
-        break;
-    }
-
-end:
-    m_free(m);
-}
diff --git a/slirp/ip6_icmp.h b/slirp/ip6_icmp.h
deleted file mode 100644 (file)
index e8ed753..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright (c) 2013
- * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
- */
-
-#ifndef SLIRP_IP6_ICMP_H
-#define SLIRP_IP6_ICMP_H
-
-/*
- * Interface Control Message Protocol version 6 Definitions.
- * Per RFC 4443, March 2006.
- *
- * Network Discover Protocol Definitions.
- * Per RFC 4861, September 2007.
- */
-
-struct icmp6_echo { /* Echo Messages */
-    uint16_t id;
-    uint16_t seq_num;
-};
-
-union icmp6_error_body {
-    uint32_t unused;
-    uint32_t pointer;
-    uint32_t mtu;
-};
-
-/*
- * NDP Messages
- */
-struct ndp_rs {     /* Router Solicitation Message */
-    uint32_t reserved;
-};
-
-struct ndp_ra {     /* Router Advertisement Message */
-    uint8_t chl;    /* Cur Hop Limit */
-#if G_BYTE_ORDER == G_BIG_ENDIAN
-    uint8_t
-        M:1,
-        O:1,
-        reserved:6;
-#else
-    uint8_t
-        reserved:6,
-        O:1,
-        M:1;
-#endif
-    uint16_t lifetime;      /* Router Lifetime */
-    uint32_t reach_time;    /* Reachable Time */
-    uint32_t retrans_time;  /* Retrans Timer */
-};
-
-G_STATIC_ASSERT(sizeof(struct ndp_ra) == 12);
-
-struct ndp_ns {     /* Neighbor Solicitation Message */
-    uint32_t reserved;
-    struct in6_addr target; /* Target Address */
-};
-
-G_STATIC_ASSERT(sizeof(struct ndp_ns) == 20);
-
-struct ndp_na {     /* Neighbor Advertisement Message */
-#if G_BYTE_ORDER == G_BIG_ENDIAN
-    uint32_t
-        R:1,                /* Router Flag */
-        S:1,                /* Solicited Flag */
-        O:1,                /* Override Flag */
-        reserved_hi:5,
-        reserved_lo:24;
-#else
-    uint32_t
-        reserved_hi:5,
-        O:1,
-        S:1,
-        R:1,
-        reserved_lo:24;
-#endif
-    struct in6_addr target; /* Target Address */
-};
-
-G_STATIC_ASSERT(sizeof(struct ndp_na) == 20);
-
-struct ndp_redirect {
-    uint32_t reserved;
-    struct in6_addr target; /* Target Address */
-    struct in6_addr dest;   /* Destination Address */
-};
-
-G_STATIC_ASSERT(sizeof(struct ndp_redirect) == 36);
-
-/*
- * Structure of an icmpv6 header.
- */
-struct icmp6 {
-    uint8_t     icmp6_type;         /* type of message, see below */
-    uint8_t     icmp6_code;         /* type sub code */
-    uint16_t    icmp6_cksum;        /* ones complement cksum of struct */
-    union {
-        union icmp6_error_body error_body;
-        struct icmp6_echo echo;
-        struct ndp_rs ndp_rs;
-        struct ndp_ra ndp_ra;
-        struct ndp_ns ndp_ns;
-        struct ndp_na ndp_na;
-        struct ndp_redirect ndp_redirect;
-    } icmp6_body;
-#define icmp6_err icmp6_body.error_body
-#define icmp6_echo icmp6_body.echo
-#define icmp6_nrs icmp6_body.ndp_rs
-#define icmp6_nra icmp6_body.ndp_ra
-#define icmp6_nns icmp6_body.ndp_ns
-#define icmp6_nna icmp6_body.ndp_na
-#define icmp6_redirect icmp6_body.ndp_redirect
-};
-
-G_STATIC_ASSERT(sizeof(struct icmp6) == 40);
-
-#define ICMP6_MINLEN    4
-#define ICMP6_ERROR_MINLEN  8
-#define ICMP6_ECHO_MINLEN   8
-#define ICMP6_NDP_RS_MINLEN 8
-#define ICMP6_NDP_RA_MINLEN 16
-#define ICMP6_NDP_NS_MINLEN 24
-#define ICMP6_NDP_NA_MINLEN 24
-#define ICMP6_NDP_REDIRECT_MINLEN 40
-
-/*
- * NDP Options
- */
-struct ndpopt {
-    uint8_t     ndpopt_type;                    /* Option type */
-    uint8_t     ndpopt_len;                     /* /!\ In units of 8 octets */
-    union {
-        unsigned char   linklayer_addr[6];      /* Source/Target Link-layer */
-#define ndpopt_linklayer ndpopt_body.linklayer_addr
-        struct prefixinfo {                     /* Prefix Information */
-            uint8_t     prefix_length;
-#if G_BYTE_ORDER == G_BIG_ENDIAN
-            uint8_t     L:1, A:1, reserved1:6;
-#else
-            uint8_t     reserved1:6, A:1, L:1;
-#endif
-            uint32_t    valid_lt;               /* Valid Lifetime */
-            uint32_t    pref_lt;                /* Preferred Lifetime */
-            uint32_t    reserved2;
-            struct in6_addr prefix;
-        } SLIRP_PACKED prefixinfo;
-#define ndpopt_prefixinfo ndpopt_body.prefixinfo
-        struct rdnss {
-            uint16_t reserved;
-            uint32_t lifetime;
-            struct in6_addr addr;
-        } SLIRP_PACKED rdnss;
-#define ndpopt_rdnss ndpopt_body.rdnss
-    } ndpopt_body;
-} SLIRP_PACKED;
-
-/* NDP options type */
-#define NDPOPT_LINKLAYER_SOURCE     1   /* Source Link-Layer Address */
-#define NDPOPT_LINKLAYER_TARGET     2   /* Target Link-Layer Address */
-#define NDPOPT_PREFIX_INFO          3   /* Prefix Information */
-#define NDPOPT_RDNSS                25  /* Recursive DNS Server Address */
-
-/* NDP options size, in octets. */
-#define NDPOPT_LINKLAYER_LEN    8
-#define NDPOPT_PREFIXINFO_LEN   32
-#define NDPOPT_RDNSS_LEN        24
-
-/*
- * Definition of type and code field values.
- * Per https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xml
- * Last Updated 2012-11-12
- */
-
-/* Errors */
-#define ICMP6_UNREACH   1   /* Destination Unreachable */
-#define     ICMP6_UNREACH_NO_ROUTE      0   /* no route to dest */
-#define     ICMP6_UNREACH_DEST_PROHIB   1   /* com with dest prohibited */
-#define     ICMP6_UNREACH_SCOPE         2   /* beyond scope of src addr */
-#define     ICMP6_UNREACH_ADDRESS       3   /* address unreachable */
-#define     ICMP6_UNREACH_PORT          4   /* port unreachable */
-#define     ICMP6_UNREACH_SRC_FAIL      5   /* src addr failed */
-#define     ICMP6_UNREACH_REJECT_ROUTE  6   /* reject route to dest */
-#define     ICMP6_UNREACH_SRC_HDR_ERROR 7   /* error in src routing header */
-#define ICMP6_TOOBIG    2   /* Packet Too Big */
-#define ICMP6_TIMXCEED  3   /* Time Exceeded */
-#define     ICMP6_TIMXCEED_INTRANS      0   /* hop limit exceeded in transit */
-#define     ICMP6_TIMXCEED_REASS        1   /* ttl=0 in reass */
-#define ICMP6_PARAMPROB 4   /* Parameter Problem */
-#define     ICMP6_PARAMPROB_HDR_FIELD   0   /* err header field */
-#define     ICMP6_PARAMPROB_NXTHDR_TYPE 1   /* unrecognized Next Header type */
-#define     ICMP6_PARAMPROB_IPV6_OPT    2   /* unrecognized IPv6 option */
-
-/* Informational Messages */
-#define ICMP6_ECHO_REQUEST      128 /* Echo Request */
-#define ICMP6_ECHO_REPLY        129 /* Echo Reply */
-#define ICMP6_NDP_RS            133 /* Router Solicitation (NDP) */
-#define ICMP6_NDP_RA            134 /* Router Advertisement (NDP) */
-#define ICMP6_NDP_NS            135 /* Neighbor Solicitation (NDP) */
-#define ICMP6_NDP_NA            136 /* Neighbor Advertisement (NDP) */
-#define ICMP6_NDP_REDIRECT      137 /* Redirect Message (NDP) */
-
-/*
- * Router Configuration Variables (rfc4861#section-6)
- */
-#define NDP_IsRouter                1
-#define NDP_AdvSendAdvertisements   1
-#define NDP_MaxRtrAdvInterval       600000
-#define NDP_MinRtrAdvInterval       ((NDP_MaxRtrAdvInterval >= 9) ? \
-                                        NDP_MaxRtrAdvInterval / 3 : \
-                                        NDP_MaxRtrAdvInterval)
-#define NDP_AdvManagedFlag          0
-#define NDP_AdvOtherConfigFlag      0
-#define NDP_AdvLinkMTU              0
-#define NDP_AdvReachableTime        0
-#define NDP_AdvRetransTime          0
-#define NDP_AdvCurHopLimit          64
-#define NDP_AdvDefaultLifetime      ((3 * NDP_MaxRtrAdvInterval) / 1000)
-#define NDP_AdvValidLifetime        86400
-#define NDP_AdvOnLinkFlag           1
-#define NDP_AdvPrefLifetime         14400
-#define NDP_AdvAutonomousFlag       1
-
-void icmp6_init(Slirp *slirp);
-void icmp6_cleanup(Slirp *slirp);
-void icmp6_input(struct mbuf *);
-void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code);
-void ndp_send_ra(Slirp *slirp);
-void ndp_send_ns(Slirp *slirp, struct in6_addr addr);
-
-#endif
diff --git a/slirp/ip6_input.c b/slirp/ip6_input.c
deleted file mode 100644 (file)
index 1b8c003..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2013
- * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
- */
-
-#include "slirp.h"
-#include "ip6_icmp.h"
-
-/*
- * IP initialization: fill in IP protocol switch table.
- * All protocols not implemented in kernel go to raw IP protocol handler.
- */
-void ip6_init(Slirp *slirp)
-{
-    icmp6_init(slirp);
-}
-
-void ip6_cleanup(Slirp *slirp)
-{
-    icmp6_cleanup(slirp);
-}
-
-void ip6_input(struct mbuf *m)
-{
-    struct ip6 *ip6;
-    Slirp *slirp = m->slirp;
-
-    if (!slirp->in6_enabled) {
-        goto bad;
-    }
-
-    DEBUG_CALL("ip6_input");
-    DEBUG_ARG("m = %p", m);
-    DEBUG_ARG("m_len = %d", m->m_len);
-
-    if (m->m_len < sizeof(struct ip6)) {
-        goto bad;
-    }
-
-    ip6 = mtod(m, struct ip6 *);
-
-    if (ip6->ip_v != IP6VERSION) {
-        goto bad;
-    }
-
-    if (ntohs(ip6->ip_pl) > IF_MTU) {
-        icmp6_send_error(m, ICMP6_TOOBIG, 0);
-        goto bad;
-    }
-
-    /* check ip_ttl for a correct ICMP reply */
-    if (ip6->ip_hl == 0) {
-        icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS);
-        goto bad;
-    }
-
-    /*
-     * Switch out to protocol's input routine.
-     */
-    switch (ip6->ip_nh) {
-    case IPPROTO_TCP:
-        NTOHS(ip6->ip_pl);
-        tcp_input(m, sizeof(struct ip6), (struct socket *)NULL, AF_INET6);
-        break;
-    case IPPROTO_UDP:
-        udp6_input(m);
-        break;
-    case IPPROTO_ICMPV6:
-        icmp6_input(m);
-        break;
-    default:
-        m_free(m);
-    }
-    return;
-bad:
-    m_free(m);
-}
diff --git a/slirp/ip6_output.c b/slirp/ip6_output.c
deleted file mode 100644 (file)
index 19d1ae7..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2013
- * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
- */
-
-#include "slirp.h"
-
-/* Number of packets queued before we start sending
- * (to prevent allocing too many mbufs) */
-#define IF6_THRESH 10
-
-/*
- * IPv6 output. The packet in mbuf chain m contains a IP header
- */
-int ip6_output(struct socket *so, struct mbuf *m, int fast)
-{
-    struct ip6 *ip = mtod(m, struct ip6 *);
-
-    DEBUG_CALL("ip6_output");
-    DEBUG_ARG("so = %p", so);
-    DEBUG_ARG("m = %p", m);
-
-    /* Fill IPv6 header */
-    ip->ip_v = IP6VERSION;
-    ip->ip_hl = IP6_HOP_LIMIT;
-    ip->ip_tc_hi = 0;
-    ip->ip_tc_lo = 0;
-    ip->ip_fl_hi = 0;
-    ip->ip_fl_lo = 0;
-
-    if (fast) {
-        if_encap(m->slirp, m);
-    } else {
-        if_output(so, m);
-    }
-
-    return 0;
-}
diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c
deleted file mode 100644 (file)
index 120108f..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 1988, 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. 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.
- *
- *     @(#)ip_icmp.c   8.2 (Berkeley) 1/4/94
- * ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp
- */
-
-#include "slirp.h"
-#include "ip_icmp.h"
-
-#ifndef WITH_ICMP_ERROR_MSG
-#define WITH_ICMP_ERROR_MSG 0
-#endif
-
-/* The message sent when emulating PING */
-/* Be nice and tell them it's just a pseudo-ping packet */
-static const char icmp_ping_msg[] = "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n";
-
-/* list of actions for icmp_send_error() on RX of an icmp message */
-static const int icmp_flush[19] = {
-/*  ECHO REPLY (0)  */   0,
-                        1,
-                        1,
-/* DEST UNREACH (3) */   1,
-/* SOURCE QUENCH (4)*/   1,
-/* REDIRECT (5) */       1,
-                        1,
-                        1,
-/* ECHO (8) */           0,
-/* ROUTERADVERT (9) */   1,
-/* ROUTERSOLICIT (10) */ 1,
-/* TIME EXCEEDED (11) */ 1,
-/* PARAMETER PROBLEM (12) */ 1,
-/* TIMESTAMP (13) */     0,
-/* TIMESTAMP REPLY (14) */ 0,
-/* INFO (15) */          0,
-/* INFO REPLY (16) */    0,
-/* ADDR MASK (17) */     0,
-/* ADDR MASK REPLY (18) */ 0
-};
-
-void icmp_init(Slirp *slirp)
-{
-    slirp->icmp.so_next = slirp->icmp.so_prev = &slirp->icmp;
-    slirp->icmp_last_so = &slirp->icmp;
-}
-
-void icmp_cleanup(Slirp *slirp)
-{
-    while (slirp->icmp.so_next != &slirp->icmp) {
-        icmp_detach(slirp->icmp.so_next);
-    }
-}
-
-static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
-{
-    struct ip *ip = mtod(m, struct ip *);
-    struct sockaddr_in addr;
-
-    so->s = slirp_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
-    if (so->s == -1) {
-        return -1;
-    }
-
-    so->so_m = m;
-    so->so_faddr = ip->ip_dst;
-    so->so_laddr = ip->ip_src;
-    so->so_iptos = ip->ip_tos;
-    so->so_type = IPPROTO_ICMP;
-    so->so_state = SS_ISFCONNECTED;
-    so->so_expire = curtime + SO_EXPIRE;
-
-    addr.sin_family = AF_INET;
-    addr.sin_addr = so->so_faddr;
-
-    insque(so, &so->slirp->icmp);
-
-    if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0,
-               (struct sockaddr *)&addr, sizeof(addr)) == -1) {
-        DEBUG_MISC("icmp_input icmp sendto tx errno = %d-%s",
-                   errno, strerror(errno));
-        icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
-        icmp_detach(so);
-    }
-
-    return 0;
-}
-
-void icmp_detach(struct socket *so)
-{
-    so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
-    closesocket(so->s);
-    sofree(so);
-}
-
-/*
- * Process a received ICMP message.
- */
-void
-icmp_input(struct mbuf *m, int hlen)
-{
-  register struct icmp *icp;
-  register struct ip *ip=mtod(m, struct ip *);
-  int icmplen=ip->ip_len;
-  Slirp *slirp = m->slirp;
-
-  DEBUG_CALL("icmp_input");
-  DEBUG_ARG("m = %p", m);
-  DEBUG_ARG("m_len = %d", m->m_len);
-
-  /*
-   * Locate icmp structure in mbuf, and check
-   * that its not corrupted and of at least minimum length.
-   */
-  if (icmplen < ICMP_MINLEN) {          /* min 8 bytes payload */
-  freeit:
-    m_free(m);
-    goto end_error;
-  }
-
-  m->m_len -= hlen;
-  m->m_data += hlen;
-  icp = mtod(m, struct icmp *);
-  if (cksum(m, icmplen)) {
-    goto freeit;
-  }
-  m->m_len += hlen;
-  m->m_data -= hlen;
-
-  DEBUG_ARG("icmp_type = %d", icp->icmp_type);
-  switch (icp->icmp_type) {
-  case ICMP_ECHO:
-    ip->ip_len += hlen;                     /* since ip_input subtracts this */
-    if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
-        ip->ip_dst.s_addr == slirp->vnameserver_addr.s_addr) {
-        icmp_reflect(m);
-    } else if (slirp->restricted) {
-        goto freeit;
-    } else {
-      struct socket *so;
-      struct sockaddr_storage addr;
-      so = socreate(slirp);
-      if (icmp_send(so, m, hlen) == 0) {
-        return;
-      }
-      if (udp_attach(so, AF_INET) == -1) {
-       DEBUG_MISC("icmp_input udp_attach errno = %d-%s",
-               errno,strerror(errno));
-       sofree(so);
-       m_free(m);
-       goto end_error;
-      }
-      so->so_m = m;
-      so->so_ffamily = AF_INET;
-      so->so_faddr = ip->ip_dst;
-      so->so_fport = htons(7);
-      so->so_lfamily = AF_INET;
-      so->so_laddr = ip->ip_src;
-      so->so_lport = htons(9);
-      so->so_iptos = ip->ip_tos;
-      so->so_type = IPPROTO_ICMP;
-      so->so_state = SS_ISFCONNECTED;
-
-      /* Send the packet */
-      addr = so->fhost.ss;
-      sotranslate_out(so, &addr);
-
-      if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
-               (struct sockaddr *)&addr, sockaddr_size(&addr)) == -1) {
-       DEBUG_MISC("icmp_input udp sendto tx errno = %d-%s",
-               errno,strerror(errno));
-       icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
-       udp_detach(so);
-      }
-    } /* if ip->ip_dst.s_addr == alias_addr.s_addr */
-    break;
-  case ICMP_UNREACH:
-    /* XXX? report error? close socket? */
-  case ICMP_TIMXCEED:
-  case ICMP_PARAMPROB:
-  case ICMP_SOURCEQUENCH:
-  case ICMP_TSTAMP:
-  case ICMP_MASKREQ:
-  case ICMP_REDIRECT:
-    m_free(m);
-    break;
-
-  default:
-    m_free(m);
-  } /* swith */
-
-end_error:
-  /* m is m_free()'d xor put in a socket xor or given to ip_send */
-  return;
-}
-
-
-/*
- *     Send an ICMP message in response to a situation
- *
- *     RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do).
- *                     MUST NOT change this header information.
- *                     MUST NOT reply to a multicast/broadcast IP address.
- *                     MUST NOT reply to a multicast/broadcast MAC address.
- *                     MUST reply to only the first fragment.
- */
-/*
- * Send ICMP_UNREACH back to the source regarding msrc.
- * mbuf *msrc is used as a template, but is NOT m_free()'d.
- * It is reported as the bad ip packet.  The header should
- * be fully correct and in host byte order.
- * ICMP fragmentation is illegal.  All machines must accept 576 bytes in one
- * packet.  The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548
- */
-
-#define ICMP_MAXDATALEN (IP_MSS-28)
-void
-icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
-           const char *message)
-{
-  unsigned hlen, shlen, s_ip_len;
-  register struct ip *ip;
-  register struct icmp *icp;
-  register struct mbuf *m;
-
-  DEBUG_CALL("icmp_send_error");
-  DEBUG_ARG("msrc = %p", msrc);
-  DEBUG_ARG("msrc_len = %d", msrc->m_len);
-
-  if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error;
-
-  /* check msrc */
-  if(!msrc) goto end_error;
-  ip = mtod(msrc, struct ip *);
-  if (slirp_debug & DBG_MISC) {
-    char bufa[20], bufb[20];
-    strcpy(bufa, inet_ntoa(ip->ip_src));
-    strcpy(bufb, inet_ntoa(ip->ip_dst));
-    DEBUG_MISC(" %.16s to %.16s", bufa, bufb);
-  }
-  if(ip->ip_off & IP_OFFMASK) goto end_error;    /* Only reply to fragment 0 */
-
-  /* Do not reply to source-only IPs */
-  if ((ip->ip_src.s_addr & htonl(~(0xf << 28))) == 0) {
-      goto end_error;
-  }
-
-  shlen=ip->ip_hl << 2;
-  s_ip_len=ip->ip_len;
-  if(ip->ip_p == IPPROTO_ICMP) {
-    icp = (struct icmp *)((char *)ip + shlen);
-    /*
-     * Assume any unknown ICMP type is an error. This isn't
-     * specified by the RFC, but think about it..
-     */
-    if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error;
-  }
-
-  /* make a copy */
-  m = m_get(msrc->slirp);
-  if (!m) {
-      goto end_error;
-  }
-
-  { int new_m_size;
-    new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN;
-    if(new_m_size>m->m_size) m_inc(m, new_m_size);
-  }
-  memcpy(m->m_data, msrc->m_data, msrc->m_len);
-  m->m_len = msrc->m_len;                        /* copy msrc to m */
-
-  /* make the header of the reply packet */
-  ip  = mtod(m, struct ip *);
-  hlen= sizeof(struct ip );     /* no options in reply */
-
-  /* fill in icmp */
-  m->m_data += hlen;
-  m->m_len -= hlen;
-
-  icp = mtod(m, struct icmp *);
-
-  if(minsize) s_ip_len=shlen+ICMP_MINLEN;   /* return header+8b only */
-  else if(s_ip_len>ICMP_MAXDATALEN)         /* maximum size */
-    s_ip_len=ICMP_MAXDATALEN;
-
-  m->m_len=ICMP_MINLEN+s_ip_len;        /* 8 bytes ICMP header */
-
-  /* min. size = 8+sizeof(struct ip)+8 */
-
-  icp->icmp_type = type;
-  icp->icmp_code = code;
-  icp->icmp_id = 0;
-  icp->icmp_seq = 0;
-
-  memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len);   /* report the ip packet */
-  HTONS(icp->icmp_ip.ip_len);
-  HTONS(icp->icmp_ip.ip_id);
-  HTONS(icp->icmp_ip.ip_off);
-
-  if (message && WITH_ICMP_ERROR_MSG) { /* append message to ICMP packet */
-    int message_len;
-    char *cpnt;
-    message_len=strlen(message);
-    if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN;
-    cpnt=(char *)m->m_data+m->m_len;
-    memcpy(cpnt, message, message_len);
-    m->m_len+=message_len;
-  }
-
-  icp->icmp_cksum = 0;
-  icp->icmp_cksum = cksum(m, m->m_len);
-
-  m->m_data -= hlen;
-  m->m_len += hlen;
-
-  /* fill in ip */
-  ip->ip_hl = hlen >> 2;
-  ip->ip_len = m->m_len;
-
-  ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0);  /* high priority for errors */
-
-  ip->ip_ttl = MAXTTL;
-  ip->ip_p = IPPROTO_ICMP;
-  ip->ip_dst = ip->ip_src;    /* ip addresses */
-  ip->ip_src = m->slirp->vhost_addr;
-
-  (void ) ip_output((struct socket *)NULL, m);
-
-end_error:
-  return;
-}
-#undef ICMP_MAXDATALEN
-
-/*
- * Reflect the ip packet back to the source
- */
-void
-icmp_reflect(struct mbuf *m)
-{
-  register struct ip *ip = mtod(m, struct ip *);
-  int hlen = ip->ip_hl << 2;
-  int optlen = hlen - sizeof(struct ip );
-  register struct icmp *icp;
-
-  /*
-   * Send an icmp packet back to the ip level,
-   * after supplying a checksum.
-   */
-  m->m_data += hlen;
-  m->m_len -= hlen;
-  icp = mtod(m, struct icmp *);
-
-  icp->icmp_type = ICMP_ECHOREPLY;
-  icp->icmp_cksum = 0;
-  icp->icmp_cksum = cksum(m, ip->ip_len - hlen);
-
-  m->m_data -= hlen;
-  m->m_len += hlen;
-
-  /* fill in ip */
-  if (optlen > 0) {
-    /*
-     * Strip out original options by copying rest of first
-     * mbuf's data back, and adjust the IP length.
-     */
-    memmove((char *)(ip + 1), (char *)ip + hlen,
-           (unsigned )(m->m_len - hlen));
-    hlen -= optlen;
-    ip->ip_hl = hlen >> 2;
-    ip->ip_len -= optlen;
-    m->m_len -= optlen;
-  }
-
-  ip->ip_ttl = MAXTTL;
-  { /* swap */
-    struct in_addr icmp_dst;
-    icmp_dst = ip->ip_dst;
-    ip->ip_dst = ip->ip_src;
-    ip->ip_src = icmp_dst;
-  }
-
-  (void ) ip_output((struct socket *)NULL, m);
-}
-
-void icmp_receive(struct socket *so)
-{
-    struct mbuf *m = so->so_m;
-    struct ip *ip = mtod(m, struct ip *);
-    int hlen = ip->ip_hl << 2;
-    uint8_t error_code;
-    struct icmp *icp;
-    int id, len;
-
-    m->m_data += hlen;
-    m->m_len -= hlen;
-    icp = mtod(m, struct icmp *);
-
-    id = icp->icmp_id;
-    len = recv(so->s, icp, M_ROOM(m), 0);
-    /*
-     * The behavior of reading SOCK_DGRAM+IPPROTO_ICMP sockets is inconsistent
-     * between host OSes.  On Linux, only the ICMP header and payload is
-     * included.  On macOS/Darwin, the socket acts like a raw socket and
-     * includes the IP header as well.  On other BSDs, SOCK_DGRAM+IPPROTO_ICMP
-     * sockets aren't supported at all, so we treat them like raw sockets.  It
-     * isn't possible to detect this difference at runtime, so we must use an
-     * #ifdef to determine if we need to remove the IP header.
-     */
-#ifdef CONFIG_BSD
-    if (len >= sizeof(struct ip)) {
-        struct ip *inner_ip = mtod(m, struct ip *);
-        int inner_hlen = inner_ip->ip_hl << 2;
-        if (inner_hlen > len) {
-            len = -1;
-            errno = -EINVAL;
-        } else {
-            len -= inner_hlen;
-            memmove(icp, (unsigned char *)icp + inner_hlen, len);
-        }
-    } else {
-      len = -1;
-      errno = -EINVAL;
-    }
-#endif
-    icp->icmp_id = id;
-
-    m->m_data -= hlen;
-    m->m_len += hlen;
-
-    if (len == -1 || len == 0) {
-        if (errno == ENETUNREACH) {
-            error_code = ICMP_UNREACH_NET;
-        } else {
-            error_code = ICMP_UNREACH_HOST;
-        }
-        DEBUG_MISC(" udp icmp rx errno = %d-%s", errno,
-                   strerror(errno));
-        icmp_send_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno));
-    } else {
-        icmp_reflect(so->so_m);
-        so->so_m = NULL; /* Don't m_free() it again! */
-    }
-    icmp_detach(so);
-}
diff --git a/slirp/ip_icmp.h b/slirp/ip_icmp.h
deleted file mode 100644 (file)
index a4e5b8b..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 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. 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.
- *
- *     @(#)ip_icmp.h   8.1 (Berkeley) 6/10/93
- * ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp
- */
-
-#ifndef NETINET_IP_ICMP_H
-#define NETINET_IP_ICMP_H
-
-/*
- * Interface Control Message Protocol Definitions.
- * Per RFC 792, September 1981.
- */
-
-typedef uint32_t n_time;
-
-/*
- * Structure of an icmp header.
- */
-struct icmp {
-       uint8_t icmp_type;              /* type of message, see below */
-       uint8_t icmp_code;              /* type sub code */
-       uint16_t        icmp_cksum;             /* ones complement cksum of struct */
-       union {
-               uint8_t ih_pptr;                        /* ICMP_PARAMPROB */
-               struct in_addr ih_gwaddr;       /* ICMP_REDIRECT */
-               struct ih_idseq {
-                       uint16_t        icd_id;
-                       uint16_t        icd_seq;
-               } ih_idseq;
-               int ih_void;
-
-               /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
-               struct ih_pmtu {
-                       uint16_t ipm_void;
-                       uint16_t ipm_nextmtu;
-               } ih_pmtu;
-       } icmp_hun;
-#define        icmp_pptr       icmp_hun.ih_pptr
-#define        icmp_gwaddr     icmp_hun.ih_gwaddr
-#define        icmp_id         icmp_hun.ih_idseq.icd_id
-#define        icmp_seq        icmp_hun.ih_idseq.icd_seq
-#define        icmp_void       icmp_hun.ih_void
-#define        icmp_pmvoid     icmp_hun.ih_pmtu.ipm_void
-#define        icmp_nextmtu    icmp_hun.ih_pmtu.ipm_nextmtu
-       union {
-               struct id_ts {
-                       n_time its_otime;
-                       n_time its_rtime;
-                       n_time its_ttime;
-               } id_ts;
-               struct id_ip  {
-                       struct ip idi_ip;
-                       /* options and then 64 bits of data */
-               } id_ip;
-               uint32_t        id_mask;
-               char            id_data[1];
-       } icmp_dun;
-#define        icmp_otime      icmp_dun.id_ts.its_otime
-#define        icmp_rtime      icmp_dun.id_ts.its_rtime
-#define        icmp_ttime      icmp_dun.id_ts.its_ttime
-#define        icmp_ip         icmp_dun.id_ip.idi_ip
-#define        icmp_mask       icmp_dun.id_mask
-#define        icmp_data       icmp_dun.id_data
-};
-
-/*
- * Lower bounds on packet lengths for various types.
- * For the error advice packets must first ensure that the
- * packet is large enough to contain the returned ip header.
- * Only then can we do the check to see if 64 bits of packet
- * data have been returned, since we need to check the returned
- * ip header length.
- */
-#define        ICMP_MINLEN     8                               /* abs minimum */
-#define        ICMP_TSLEN      (8 + 3 * sizeof (n_time))       /* timestamp */
-#define        ICMP_MASKLEN    12                              /* address mask */
-#define        ICMP_ADVLENMIN  (8 + sizeof (struct ip) + 8)    /* min */
-#define        ICMP_ADVLEN(p)  (8 + ((p)->icmp_ip.ip_hl << 2) + 8)
-       /* N.B.: must separately check that ip_hl >= 5 */
-
-/*
- * Definition of type and code field values.
- */
-#define        ICMP_ECHOREPLY          0               /* echo reply */
-#define        ICMP_UNREACH            3               /* dest unreachable, codes: */
-#define                ICMP_UNREACH_NET        0               /* bad net */
-#define                ICMP_UNREACH_HOST       1               /* bad host */
-#define                ICMP_UNREACH_PROTOCOL   2               /* bad protocol */
-#define                ICMP_UNREACH_PORT       3               /* bad port */
-#define                ICMP_UNREACH_NEEDFRAG   4               /* IP_DF caused drop */
-#define                ICMP_UNREACH_SRCFAIL    5               /* src route failed */
-#define                ICMP_UNREACH_NET_UNKNOWN 6              /* unknown net */
-#define                ICMP_UNREACH_HOST_UNKNOWN 7             /* unknown host */
-#define                ICMP_UNREACH_ISOLATED   8               /* src host isolated */
-#define                ICMP_UNREACH_NET_PROHIB 9               /* prohibited access */
-#define                ICMP_UNREACH_HOST_PROHIB 10             /* ditto */
-#define                ICMP_UNREACH_TOSNET     11              /* bad tos for net */
-#define                ICMP_UNREACH_TOSHOST    12              /* bad tos for host */
-#define        ICMP_SOURCEQUENCH       4               /* packet lost, slow down */
-#define        ICMP_REDIRECT           5               /* shorter route, codes: */
-#define                ICMP_REDIRECT_NET       0               /* for network */
-#define                ICMP_REDIRECT_HOST      1               /* for host */
-#define                ICMP_REDIRECT_TOSNET    2               /* for tos and net */
-#define                ICMP_REDIRECT_TOSHOST   3               /* for tos and host */
-#define        ICMP_ECHO               8               /* echo service */
-#define        ICMP_ROUTERADVERT       9               /* router advertisement */
-#define        ICMP_ROUTERSOLICIT      10              /* router solicitation */
-#define        ICMP_TIMXCEED           11              /* time exceeded, code: */
-#define                ICMP_TIMXCEED_INTRANS   0               /* ttl==0 in transit */
-#define                ICMP_TIMXCEED_REASS     1               /* ttl==0 in reass */
-#define        ICMP_PARAMPROB          12              /* ip header bad */
-#define                ICMP_PARAMPROB_OPTABSENT 1              /* req. opt. absent */
-#define        ICMP_TSTAMP             13              /* timestamp request */
-#define        ICMP_TSTAMPREPLY        14              /* timestamp reply */
-#define        ICMP_IREQ               15              /* information request */
-#define        ICMP_IREQREPLY          16              /* information reply */
-#define        ICMP_MASKREQ            17              /* address mask request */
-#define        ICMP_MASKREPLY          18              /* address mask reply */
-
-#define        ICMP_MAXTYPE            18
-
-#define        ICMP_INFOTYPE(type) \
-       ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
-       (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \
-       (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
-       (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
-       (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
-
-void icmp_init(Slirp *slirp);
-void icmp_cleanup(Slirp *slirp);
-void icmp_input(struct mbuf *, int);
-void icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
-                     const char *message);
-void icmp_reflect(struct mbuf *);
-void icmp_receive(struct socket *so);
-void icmp_detach(struct socket *so);
-
-#endif
diff --git a/slirp/ip_input.c b/slirp/ip_input.c
deleted file mode 100644 (file)
index e0b94b0..0000000
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 1988, 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. 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.
- *
- *     @(#)ip_input.c  8.2 (Berkeley) 1/4/94
- * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp
- */
-
-/*
- * Changes and additions relating to SLiRP are
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#include "slirp.h"
-#include "ip_icmp.h"
-
-static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp);
-static void ip_freef(Slirp *slirp, struct ipq *fp);
-static void ip_enq(register struct ipasfrag *p,
-                   register struct ipasfrag *prev);
-static void ip_deq(register struct ipasfrag *p);
-
-/*
- * IP initialization: fill in IP protocol switch table.
- * All protocols not implemented in kernel go to raw IP protocol handler.
- */
-void
-ip_init(Slirp *slirp)
-{
-    slirp->ipq.ip_link.next = slirp->ipq.ip_link.prev = &slirp->ipq.ip_link;
-    udp_init(slirp);
-    tcp_init(slirp);
-    icmp_init(slirp);
-}
-
-void ip_cleanup(Slirp *slirp)
-{
-    udp_cleanup(slirp);
-    tcp_cleanup(slirp);
-    icmp_cleanup(slirp);
-}
-
-/*
- * Ip input routine.  Checksum and byte swap header.  If fragmented
- * try to reassemble.  Process options.  Pass to next level.
- */
-void
-ip_input(struct mbuf *m)
-{
-       Slirp *slirp = m->slirp;
-       register struct ip *ip;
-       int hlen;
-
-       if (!slirp->in_enabled) {
-               goto bad;
-       }
-
-       DEBUG_CALL("ip_input");
-       DEBUG_ARG("m = %p", m);
-       DEBUG_ARG("m_len = %d", m->m_len);
-
-       if (m->m_len < sizeof (struct ip)) {
-               goto bad;
-       }
-
-       ip = mtod(m, struct ip *);
-
-       if (ip->ip_v != IPVERSION) {
-               goto bad;
-       }
-
-       hlen = ip->ip_hl << 2;
-       if (hlen<sizeof(struct ip ) || hlen>m->m_len) {/* min header length */
-         goto bad;                                  /* or packet too short */
-       }
-
-        /* keep ip header intact for ICMP reply
-        * ip->ip_sum = cksum(m, hlen);
-        * if (ip->ip_sum) {
-        */
-       if(cksum(m,hlen)) {
-         goto bad;
-       }
-
-       /*
-        * Convert fields to host representation.
-        */
-       NTOHS(ip->ip_len);
-       if (ip->ip_len < hlen) {
-               goto bad;
-       }
-       NTOHS(ip->ip_id);
-       NTOHS(ip->ip_off);
-
-       /*
-        * Check that the amount of data in the buffers
-        * is as at least much as the IP header would have us expect.
-        * Trim mbufs if longer than we expect.
-        * Drop packet if shorter than we expect.
-        */
-       if (m->m_len < ip->ip_len) {
-               goto bad;
-       }
-
-       /* Should drop packet if mbuf too long? hmmm... */
-       if (m->m_len > ip->ip_len)
-          m_adj(m, ip->ip_len - m->m_len);
-
-       /* check ip_ttl for a correct ICMP reply */
-       if (ip->ip_ttl == 0) {
-           icmp_send_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, "ttl");
-           goto bad;
-       }
-
-       /*
-        * If offset or IP_MF are set, must reassemble.
-        * Otherwise, nothing need be done.
-        * (We could look in the reassembly queue to see
-        * if the packet was previously fragmented,
-        * but it's not worth the time; just let them time out.)
-        *
-        * XXX This should fail, don't fragment yet
-        */
-       if (ip->ip_off &~ IP_DF) {
-         register struct ipq *fp;
-      struct qlink *l;
-               /*
-                * Look for queue of fragments
-                * of this datagram.
-                */
-               for (l = slirp->ipq.ip_link.next; l != &slirp->ipq.ip_link;
-                    l = l->next) {
-            fp = container_of(l, struct ipq, ip_link);
-            if (ip->ip_id == fp->ipq_id &&
-                    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
-                    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
-                    ip->ip_p == fp->ipq_p)
-                   goto found;
-        }
-        fp = NULL;
-       found:
-
-               /*
-                * Adjust ip_len to not reflect header,
-                * set ip_mff if more fragments are expected,
-                * convert offset of this to bytes.
-                */
-               ip->ip_len -= hlen;
-               if (ip->ip_off & IP_MF)
-                 ip->ip_tos |= 1;
-               else
-                 ip->ip_tos &= ~1;
-
-               ip->ip_off <<= 3;
-
-               /*
-                * If datagram marked as having more fragments
-                * or if this is not the first fragment,
-                * attempt reassembly; if it succeeds, proceed.
-                */
-               if (ip->ip_tos & 1 || ip->ip_off) {
-                       ip = ip_reass(slirp, ip, fp);
-                        if (ip == NULL)
-                               return;
-                       m = dtom(slirp, ip);
-               } else
-                       if (fp)
-                          ip_freef(slirp, fp);
-
-       } else
-               ip->ip_len -= hlen;
-
-       /*
-        * Switch out to protocol's input routine.
-        */
-       switch (ip->ip_p) {
-        case IPPROTO_TCP:
-               tcp_input(m, hlen, (struct socket *)NULL, AF_INET);
-               break;
-        case IPPROTO_UDP:
-               udp_input(m, hlen);
-               break;
-        case IPPROTO_ICMP:
-               icmp_input(m, hlen);
-               break;
-        default:
-               m_free(m);
-       }
-       return;
-bad:
-       m_free(m);
-}
-
-#define iptofrag(P) ((struct ipasfrag *)(((char*)(P)) - sizeof(struct qlink)))
-#define fragtoip(P) ((struct ip*)(((char*)(P)) + sizeof(struct qlink)))
-/*
- * Take incoming datagram fragment and try to
- * reassemble it into whole datagram.  If a chain for
- * reassembly of this datagram already exists, then it
- * is given as fp; otherwise have to make a chain.
- */
-static struct ip *
-ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)
-{
-       register struct mbuf *m = dtom(slirp, ip);
-       register struct ipasfrag *q;
-       int hlen = ip->ip_hl << 2;
-       int i, next;
-
-       DEBUG_CALL("ip_reass");
-       DEBUG_ARG("ip = %p", ip);
-       DEBUG_ARG("fp = %p", fp);
-       DEBUG_ARG("m = %p", m);
-
-       /*
-        * Presence of header sizes in mbufs
-        * would confuse code below.
-         * Fragment m_data is concatenated.
-        */
-       m->m_data += hlen;
-       m->m_len -= hlen;
-
-       /*
-        * If first fragment to arrive, create a reassembly queue.
-        */
-        if (fp == NULL) {
-         struct mbuf *t = m_get(slirp);
-
-         if (t == NULL) {
-             goto dropfrag;
-         }
-         fp = mtod(t, struct ipq *);
-         insque(&fp->ip_link, &slirp->ipq.ip_link);
-         fp->ipq_ttl = IPFRAGTTL;
-         fp->ipq_p = ip->ip_p;
-         fp->ipq_id = ip->ip_id;
-         fp->frag_link.next = fp->frag_link.prev = &fp->frag_link;
-         fp->ipq_src = ip->ip_src;
-         fp->ipq_dst = ip->ip_dst;
-         q = (struct ipasfrag *)fp;
-         goto insert;
-       }
-
-       /*
-        * Find a segment which begins after this one does.
-        */
-       for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
-            q = q->ipf_next)
-               if (q->ipf_off > ip->ip_off)
-                       break;
-
-       /*
-        * If there is a preceding segment, it may provide some of
-        * our data already.  If so, drop the data from the incoming
-        * segment.  If it provides all of our data, drop us.
-        */
-       if (q->ipf_prev != &fp->frag_link) {
-        struct ipasfrag *pq = q->ipf_prev;
-               i = pq->ipf_off + pq->ipf_len - ip->ip_off;
-               if (i > 0) {
-                       if (i >= ip->ip_len)
-                               goto dropfrag;
-                       m_adj(dtom(slirp, ip), i);
-                       ip->ip_off += i;
-                       ip->ip_len -= i;
-               }
-       }
-
-       /*
-        * While we overlap succeeding segments trim them or,
-        * if they are completely covered, dequeue them.
-        */
-       while (q != (struct ipasfrag*)&fp->frag_link &&
-            ip->ip_off + ip->ip_len > q->ipf_off) {
-               i = (ip->ip_off + ip->ip_len) - q->ipf_off;
-               if (i < q->ipf_len) {
-                       q->ipf_len -= i;
-                       q->ipf_off += i;
-                       m_adj(dtom(slirp, q), i);
-                       break;
-               }
-               q = q->ipf_next;
-               m_free(dtom(slirp, q->ipf_prev));
-               ip_deq(q->ipf_prev);
-       }
-
-insert:
-       /*
-        * Stick new segment in its place;
-        * check for complete reassembly.
-        */
-       ip_enq(iptofrag(ip), q->ipf_prev);
-       next = 0;
-       for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link;
-            q = q->ipf_next) {
-               if (q->ipf_off != next)
-                        return NULL;
-               next += q->ipf_len;
-       }
-       if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1)
-                return NULL;
-
-       /*
-        * Reassembly is complete; concatenate fragments.
-        */
-    q = fp->frag_link.next;
-       m = dtom(slirp, q);
-
-       q = (struct ipasfrag *) q->ipf_next;
-       while (q != (struct ipasfrag*)&fp->frag_link) {
-         struct mbuf *t = dtom(slirp, q);
-         q = (struct ipasfrag *) q->ipf_next;
-         m_cat(m, t);
-       }
-
-       /*
-        * Create header for new ip packet by
-        * modifying header of first packet;
-        * dequeue and discard fragment reassembly header.
-        * Make header visible.
-        */
-       q = fp->frag_link.next;
-
-       /*
-        * If the fragments concatenated to an mbuf that's
-        * bigger than the total size of the fragment, then and
-        * m_ext buffer was alloced. But fp->ipq_next points to
-        * the old buffer (in the mbuf), so we must point ip
-        * into the new buffer.
-        */
-       if (m->m_flags & M_EXT) {
-         int delta = (char *)q - m->m_dat;
-         q = (struct ipasfrag *)(m->m_ext + delta);
-       }
-
-    ip = fragtoip(q);
-       ip->ip_len = next;
-       ip->ip_tos &= ~1;
-       ip->ip_src = fp->ipq_src;
-       ip->ip_dst = fp->ipq_dst;
-       remque(&fp->ip_link);
-       (void) m_free(dtom(slirp, fp));
-       m->m_len += (ip->ip_hl << 2);
-       m->m_data -= (ip->ip_hl << 2);
-
-       return ip;
-
-dropfrag:
-       m_free(m);
-        return NULL;
-}
-
-/*
- * Free a fragment reassembly header and all
- * associated datagrams.
- */
-static void
-ip_freef(Slirp *slirp, struct ipq *fp)
-{
-       register struct ipasfrag *q, *p;
-
-       for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link; q = p) {
-               p = q->ipf_next;
-               ip_deq(q);
-               m_free(dtom(slirp, q));
-       }
-       remque(&fp->ip_link);
-       (void) m_free(dtom(slirp, fp));
-}
-
-/*
- * Put an ip fragment on a reassembly chain.
- * Like insque, but pointers in middle of structure.
- */
-static void
-ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev)
-{
-       DEBUG_CALL("ip_enq");
-       DEBUG_ARG("prev = %p", prev);
-       p->ipf_prev =  prev;
-       p->ipf_next = prev->ipf_next;
-       ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p;
-       prev->ipf_next = p;
-}
-
-/*
- * To ip_enq as remque is to insque.
- */
-static void
-ip_deq(register struct ipasfrag *p)
-{
-       ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next;
-       ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev;
-}
-
-/*
- * IP timer processing;
- * if a timer expires on a reassembly
- * queue, discard it.
- */
-void
-ip_slowtimo(Slirp *slirp)
-{
-    struct qlink *l;
-
-       DEBUG_CALL("ip_slowtimo");
-
-    l = slirp->ipq.ip_link.next;
-
-        if (l == NULL)
-          return;
-
-    while (l != &slirp->ipq.ip_link) {
-        struct ipq *fp = container_of(l, struct ipq, ip_link);
-        l = l->next;
-               if (--fp->ipq_ttl == 0) {
-                       ip_freef(slirp, fp);
-               }
-    }
-}
-
-/*
- * Strip out IP options, at higher
- * level protocol in the kernel.
- * Second argument is buffer to which options
- * will be moved, and return value is their length.
- * (XXX) should be deleted; last arg currently ignored.
- */
-void
-ip_stripoptions(register struct mbuf *m, struct mbuf *mopt)
-{
-       register int i;
-       struct ip *ip = mtod(m, struct ip *);
-       register char *opts;
-       int olen;
-
-       olen = (ip->ip_hl<<2) - sizeof (struct ip);
-       opts = (char *)(ip + 1);
-       i = m->m_len - (sizeof (struct ip) + olen);
-       memcpy(opts, opts  + olen, (unsigned)i);
-       m->m_len -= olen;
-
-       ip->ip_hl = sizeof(struct ip) >> 2;
-}
diff --git a/slirp/ip_output.c b/slirp/ip_output.c
deleted file mode 100644 (file)
index f6ec141..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 1988, 1990, 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. 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.
- *
- *     @(#)ip_output.c 8.3 (Berkeley) 1/21/94
- * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp
- */
-
-/*
- * Changes and additions relating to SLiRP are
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#include "slirp.h"
-
-/* Number of packets queued before we start sending
- * (to prevent allocing too many mbufs) */
-#define IF_THRESH 10
-
-/*
- * IP output.  The packet in mbuf chain m contains a skeletal IP
- * header (with len, off, ttl, proto, tos, src, dst).
- * The mbuf chain containing the packet will be freed.
- * The mbuf opt, if present, will not be freed.
- */
-int
-ip_output(struct socket *so, struct mbuf *m0)
-{
-       Slirp *slirp = m0->slirp;
-       register struct ip *ip;
-       register struct mbuf *m = m0;
-       register int hlen = sizeof(struct ip );
-       int len, off, error = 0;
-
-       DEBUG_CALL("ip_output");
-       DEBUG_ARG("so = %p", so);
-       DEBUG_ARG("m0 = %p", m0);
-
-       ip = mtod(m, struct ip *);
-       /*
-        * Fill in IP header.
-        */
-       ip->ip_v = IPVERSION;
-       ip->ip_off &= IP_DF;
-       ip->ip_id = htons(slirp->ip_id++);
-       ip->ip_hl = hlen >> 2;
-
-       /*
-        * If small enough for interface, can just send directly.
-        */
-       if ((uint16_t)ip->ip_len <= IF_MTU) {
-               ip->ip_len = htons((uint16_t)ip->ip_len);
-               ip->ip_off = htons((uint16_t)ip->ip_off);
-               ip->ip_sum = 0;
-               ip->ip_sum = cksum(m, hlen);
-
-               if_output(so, m);
-               goto done;
-       }
-
-       /*
-        * Too large for interface; fragment if possible.
-        * Must be able to put at least 8 bytes per fragment.
-        */
-       if (ip->ip_off & IP_DF) {
-               error = -1;
-               goto bad;
-       }
-
-       len = (IF_MTU - hlen) &~ 7;       /* ip databytes per packet */
-       if (len < 8) {
-               error = -1;
-               goto bad;
-       }
-
-    {
-       int mhlen, firstlen = len;
-       struct mbuf **mnext = &m->m_nextpkt;
-
-       /*
-        * Loop through length of segment after first fragment,
-        * make new header and copy data of each part and link onto chain.
-        */
-       m0 = m;
-       mhlen = sizeof (struct ip);
-       for (off = hlen + len; off < (uint16_t)ip->ip_len; off += len) {
-         register struct ip *mhip;
-         m = m_get(slirp);
-          if (m == NULL) {
-           error = -1;
-           goto sendorfree;
-         }
-         m->m_data += IF_MAXLINKHDR;
-         mhip = mtod(m, struct ip *);
-         *mhip = *ip;
-
-         m->m_len = mhlen;
-         mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
-         if (ip->ip_off & IP_MF)
-           mhip->ip_off |= IP_MF;
-         if (off + len >= (uint16_t)ip->ip_len)
-           len = (uint16_t)ip->ip_len - off;
-         else
-           mhip->ip_off |= IP_MF;
-         mhip->ip_len = htons((uint16_t)(len + mhlen));
-
-         if (m_copy(m, m0, off, len) < 0) {
-           error = -1;
-           goto sendorfree;
-         }
-
-         mhip->ip_off = htons((uint16_t)mhip->ip_off);
-         mhip->ip_sum = 0;
-         mhip->ip_sum = cksum(m, mhlen);
-         *mnext = m;
-         mnext = &m->m_nextpkt;
-       }
-       /*
-        * Update first fragment by trimming what's been copied out
-        * and updating header, then send each fragment (in order).
-        */
-       m = m0;
-       m_adj(m, hlen + firstlen - (uint16_t)ip->ip_len);
-       ip->ip_len = htons((uint16_t)m->m_len);
-       ip->ip_off = htons((uint16_t)(ip->ip_off | IP_MF));
-       ip->ip_sum = 0;
-       ip->ip_sum = cksum(m, hlen);
-sendorfree:
-       for (m = m0; m; m = m0) {
-               m0 = m->m_nextpkt;
-                m->m_nextpkt = NULL;
-               if (error == 0)
-                       if_output(so, m);
-               else
-                       m_free(m);
-       }
-    }
-
-done:
-       return (error);
-
-bad:
-       m_free(m0);
-       goto done;
-}
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
deleted file mode 100644 (file)
index fccab42..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef LIBSLIRP_H
-#define LIBSLIRP_H
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#ifdef _WIN32
-#include <winsock2.h>
-#include <in6addr.h>
-#else
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct Slirp Slirp;
-
-enum {
-    SLIRP_POLL_IN  = 1 << 0,
-    SLIRP_POLL_OUT = 1 << 1,
-    SLIRP_POLL_PRI = 1 << 2,
-    SLIRP_POLL_ERR = 1 << 3,
-    SLIRP_POLL_HUP = 1 << 4,
-};
-
-typedef ssize_t (*SlirpWriteCb)(const void *buf, size_t len, void *opaque);
-typedef void (*SlirpTimerCb)(void *opaque);
-typedef int (*SlirpAddPollCb)(int fd, int events, void *opaque);
-typedef int (*SlirpGetREventsCb)(int idx, void *opaque);
-
-/*
- * Callbacks from slirp
- */
-typedef struct SlirpCb {
-    /*
-     * Send an ethernet frame to the guest network. The opaque
-     * parameter is the one given to slirp_init(). The function
-     * doesn't need to send all the data and may return <len (no
-     * buffering is done on libslirp side, so the data will be dropped
-     * in this case). <0 reports an IO error.
-     */
-    SlirpWriteCb send_packet;
-    /* Print a message for an error due to guest misbehavior.  */
-    void (*guest_error)(const char *msg, void *opaque);
-    /* Return the virtual clock value in nanoseconds */
-    int64_t (*clock_get_ns)(void *opaque);
-    /* Create a new timer with the given callback and opaque data */
-    void *(*timer_new)(SlirpTimerCb cb, void *cb_opaque, void *opaque);
-    /* Remove and free a timer */
-    void (*timer_free)(void *timer, void *opaque);
-    /* Modify a timer to expire at @expire_time */
-    void (*timer_mod)(void *timer, int64_t expire_time, void *opaque);
-    /* Register a fd for future polling */
-    void (*register_poll_fd)(int fd, void *opaque);
-    /* Unregister a fd */
-    void (*unregister_poll_fd)(int fd, void *opaque);
-    /* Kick the io-thread, to signal that new events may be processed */
-    void (*notify)(void *opaque);
-} SlirpCb;
-
-
-Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
-                  struct in_addr vnetmask, struct in_addr vhost,
-                  bool in6_enabled,
-                  struct in6_addr vprefix_addr6, uint8_t vprefix_len,
-                  struct in6_addr vhost6, const char *vhostname,
-                  const char *tftp_server_name,
-                  const char *tftp_path, const char *bootfile,
-                  struct in_addr vdhcp_start, struct in_addr vnameserver,
-                  struct in6_addr vnameserver6, const char **vdnssearch,
-                  const char *vdomainname,
-                  const SlirpCb *callbacks,
-                  void *opaque);
-void slirp_cleanup(Slirp *slirp);
-
-void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
-                        SlirpAddPollCb add_poll, void *opaque);
-
-void slirp_pollfds_poll(Slirp *slirp, int select_error,
-                        SlirpGetREventsCb get_revents, void *opaque);
-
-void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
-
-int slirp_add_hostfwd(Slirp *slirp, int is_udp,
-                      struct in_addr host_addr, int host_port,
-                      struct in_addr guest_addr, int guest_port);
-int slirp_remove_hostfwd(Slirp *slirp, int is_udp,
-                         struct in_addr host_addr, int host_port);
-int slirp_add_exec(Slirp *slirp, const char *cmdline,
-                   struct in_addr *guest_addr, int guest_port);
-int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
-                   struct in_addr *guest_addr, int guest_port);
-
-char *slirp_connection_info(Slirp *slirp);
-
-void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr,
-                       int guest_port, const uint8_t *buf, int size);
-size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
-                             int guest_port);
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* LIBSLIRP_H */
diff --git a/slirp/main.h b/slirp/main.h
deleted file mode 100644 (file)
index f11d457..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#ifndef SLIRP_MAIN_H
-#define SLIRP_MAIN_H
-
-extern unsigned curtime;
-extern struct in_addr loopback_addr;
-extern unsigned long loopback_mask;
-
-int if_encap(Slirp *slirp, struct mbuf *ifm);
-ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags);
-
-#endif
diff --git a/slirp/mbuf.c b/slirp/mbuf.c
deleted file mode 100644 (file)
index 521c02c..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-/*
- * mbuf's in SLiRP are much simpler than the real mbufs in
- * FreeBSD.  They are fixed size, determined by the MTU,
- * so that one whole packet can fit.  Mbuf's cannot be
- * chained together.  If there's more data than the mbuf
- * could hold, an external g_malloced buffer is pointed to
- * by m_ext (and the data pointers) and M_EXT is set in
- * the flags
- */
-
-#include "slirp.h"
-
-#define MBUF_THRESH 30
-
-/*
- * Find a nice value for msize
- */
-#define SLIRP_MSIZE\
-    (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + IF_MTU)
-
-void
-m_init(Slirp *slirp)
-{
-    slirp->m_freelist.qh_link = slirp->m_freelist.qh_rlink = &slirp->m_freelist;
-    slirp->m_usedlist.qh_link = slirp->m_usedlist.qh_rlink = &slirp->m_usedlist;
-}
-
-void m_cleanup(Slirp *slirp)
-{
-    struct mbuf *m, *next;
-
-    m = (struct mbuf *) slirp->m_usedlist.qh_link;
-    while ((struct quehead *) m != &slirp->m_usedlist) {
-        next = m->m_next;
-        if (m->m_flags & M_EXT) {
-            g_free(m->m_ext);
-        }
-        g_free(m);
-        m = next;
-    }
-    m = (struct mbuf *) slirp->m_freelist.qh_link;
-    while ((struct quehead *) m != &slirp->m_freelist) {
-        next = m->m_next;
-        g_free(m);
-        m = next;
-    }
-}
-
-/*
- * Get an mbuf from the free list, if there are none
- * allocate one
- *
- * Because fragmentation can occur if we alloc new mbufs and
- * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE,
- * which tells m_free to actually g_free() it
- */
-struct mbuf *
-m_get(Slirp *slirp)
-{
-       register struct mbuf *m;
-       int flags = 0;
-
-       DEBUG_CALL("m_get");
-
-       if (slirp->m_freelist.qh_link == &slirp->m_freelist) {
-                m = g_malloc(SLIRP_MSIZE);
-               slirp->mbuf_alloced++;
-               if (slirp->mbuf_alloced > MBUF_THRESH)
-                       flags = M_DOFREE;
-               m->slirp = slirp;
-       } else {
-               m = (struct mbuf *) slirp->m_freelist.qh_link;
-               remque(m);
-       }
-
-       /* Insert it in the used list */
-       insque(m,&slirp->m_usedlist);
-       m->m_flags = (flags | M_USEDLIST);
-
-       /* Initialise it */
-       m->m_size = SLIRP_MSIZE - offsetof(struct mbuf, m_dat);
-       m->m_data = m->m_dat;
-       m->m_len = 0;
-        m->m_nextpkt = NULL;
-        m->m_prevpkt = NULL;
-        m->resolution_requested = false;
-        m->expiration_date = (uint64_t)-1;
-       DEBUG_ARG("m = %p", m);
-       return m;
-}
-
-void
-m_free(struct mbuf *m)
-{
-
-  DEBUG_CALL("m_free");
-  DEBUG_ARG("m = %p", m);
-
-  if(m) {
-       /* Remove from m_usedlist */
-       if (m->m_flags & M_USEDLIST)
-          remque(m);
-
-       /* If it's M_EXT, free() it */
-        if (m->m_flags & M_EXT) {
-                g_free(m->m_ext);
-        }
-       /*
-        * Either free() it or put it on the free list
-        */
-       if (m->m_flags & M_DOFREE) {
-               m->slirp->mbuf_alloced--;
-                g_free(m);
-       } else if ((m->m_flags & M_FREELIST) == 0) {
-               insque(m,&m->slirp->m_freelist);
-               m->m_flags = M_FREELIST; /* Clobber other flags */
-       }
-  } /* if(m) */
-}
-
-/*
- * Copy data from one mbuf to the end of
- * the other.. if result is too big for one mbuf, allocate
- * an M_EXT data segment
- */
-void
-m_cat(struct mbuf *m, struct mbuf *n)
-{
-       /*
-        * If there's no room, realloc
-        */
-       if (M_FREEROOM(m) < n->m_len)
-               m_inc(m, m->m_len + n->m_len);
-
-       memcpy(m->m_data+m->m_len, n->m_data, n->m_len);
-       m->m_len += n->m_len;
-
-       m_free(n);
-}
-
-
-/* make m 'size' bytes large from m_data */
-void
-m_inc(struct mbuf *m, int size)
-{
-    int gapsize;
-
-    /* some compilers throw up on gotos.  This one we can fake. */
-    if (M_ROOM(m) > size) {
-        return;
-    }
-
-    if (m->m_flags & M_EXT) {
-        gapsize = m->m_data - m->m_ext;
-        m->m_ext = g_realloc(m->m_ext, size + gapsize);
-    } else {
-        gapsize = m->m_data - m->m_dat;
-        m->m_ext = g_malloc(size + gapsize);
-        memcpy(m->m_ext, m->m_dat, m->m_size);
-        m->m_flags |= M_EXT;
-    }
-
-    m->m_data = m->m_ext + gapsize;
-    m->m_size = size + gapsize;
-}
-
-
-
-void
-m_adj(struct mbuf *m, int len)
-{
-       if (m == NULL)
-               return;
-       if (len >= 0) {
-               /* Trim from head */
-               m->m_data += len;
-               m->m_len -= len;
-       } else {
-               /* Trim from tail */
-               len = -len;
-               m->m_len -= len;
-       }
-}
-
-
-/*
- * Copy len bytes from m, starting off bytes into n
- */
-int
-m_copy(struct mbuf *n, struct mbuf *m, int off, int len)
-{
-       if (len > M_FREEROOM(n))
-               return -1;
-
-       memcpy((n->m_data + n->m_len), (m->m_data + off), len);
-       n->m_len += len;
-       return 0;
-}
-
-
-/*
- * Given a pointer into an mbuf, return the mbuf
- * XXX This is a kludge, I should eliminate the need for it
- * Fortunately, it's not used often
- */
-struct mbuf *
-dtom(Slirp *slirp, void *dat)
-{
-       struct mbuf *m;
-
-       DEBUG_CALL("dtom");
-       DEBUG_ARG("dat = %p", dat);
-
-       /* bug corrected for M_EXT buffers */
-       for (m = (struct mbuf *) slirp->m_usedlist.qh_link;
-            (struct quehead *) m != &slirp->m_usedlist;
-            m = m->m_next) {
-         if (m->m_flags & M_EXT) {
-           if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) )
-             return m;
-         } else {
-           if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) )
-             return m;
-         }
-       }
-
-       DEBUG_ERROR("dtom failed");
-
-       return (struct mbuf *)0;
-}
diff --git a/slirp/mbuf.h b/slirp/mbuf.h
deleted file mode 100644 (file)
index e2d4434..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 1988, 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. 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.
- *
- *     @(#)mbuf.h      8.3 (Berkeley) 1/21/94
- * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp
- */
-
-#ifndef MBUF_H
-#define MBUF_H
-
-/*
- * Macros for type conversion
- * mtod(m,t) - convert mbuf pointer to data pointer of correct type
- */
-#define mtod(m,t)      ((t)(m)->m_data)
-
-/* XXX About mbufs for slirp:
- * Only one mbuf is ever used in a chain, for each "cell" of data.
- * m_nextpkt points to the next packet, if fragmented.
- * If the data is too large, the M_EXT is used, and a larger block
- * is alloced.  Therefore, m_free[m] must check for M_EXT and if set
- * free the m_ext.  This is inefficient memory-wise, but who cares.
- */
-
-/*
- * mbufs allow to have a gap between the start of the allocated buffer (m_ext if
- * M_EXT is set, m_dat otherwise) and the in-use data:
- *
- *  |--gapsize----->|---m_len------->
- *  |----------m_size------------------------------>
- *                  |----M_ROOM-------------------->
- *                                   |-M_FREEROOM-->
- *
- *  ^               ^                               ^
- *  m_dat/m_ext     m_data                          end of buffer
- */
-
-/*
- * How much room is in the mbuf, from m_data to the end of the mbuf
- */
-#define M_ROOM(m) ((m->m_flags & M_EXT)? \
-                       (((m)->m_ext + (m)->m_size) - (m)->m_data) \
-                  : \
-                       (((m)->m_dat + (m)->m_size) - (m)->m_data))
-
-/*
- * How much free room there is
- */
-#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len)
-
-struct mbuf {
-       /* XXX should union some of these! */
-       /* header at beginning of each mbuf: */
-       struct  mbuf *m_next;           /* Linked list of mbufs */
-       struct  mbuf *m_prev;
-       struct  mbuf *m_nextpkt;        /* Next packet in queue/record */
-       struct  mbuf *m_prevpkt;        /* Flags aren't used in the output queue */
-       int     m_flags;                /* Misc flags */
-
-       int     m_size;                 /* Size of mbuf, from m_dat or m_ext */
-       struct  socket *m_so;
-
-       char *m_data;                   /* Current location of data */
-       int     m_len;                  /* Amount of data in this mbuf, from m_data */
-
-       Slirp *slirp;
-       bool    resolution_requested;
-       uint64_t expiration_date;
-       char   *m_ext;
-       /* start of dynamic buffer area, must be last element */
-       char    m_dat[];
-};
-
-#define ifq_prev m_prev
-#define ifq_next m_next
-#define ifs_prev m_prevpkt
-#define ifs_next m_nextpkt
-#define ifq_so m_so
-
-#define M_EXT                  0x01    /* m_ext points to more (malloced) data */
-#define M_FREELIST             0x02    /* mbuf is on free list */
-#define M_USEDLIST             0x04    /* XXX mbuf is on used list (for dtom()) */
-#define M_DOFREE               0x08    /* when m_free is called on the mbuf, free()
-                                        * it rather than putting it on the free list */
-
-void m_init(Slirp *);
-void m_cleanup(Slirp *slirp);
-struct mbuf * m_get(Slirp *);
-void m_free(struct mbuf *);
-void m_cat(register struct mbuf *, register struct mbuf *);
-void m_inc(struct mbuf *, int);
-void m_adj(struct mbuf *, int);
-int m_copy(struct mbuf *, struct mbuf *, int, int);
-struct mbuf * dtom(Slirp *, void *);
-
-static inline void ifs_init(struct mbuf *ifm)
-{
-    ifm->ifs_next = ifm->ifs_prev = ifm;
-}
-
-#endif
diff --git a/slirp/misc.c b/slirp/misc.c
deleted file mode 100644 (file)
index d9fc586..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#include "slirp.h"
-
-inline void
-insque(void *a, void *b)
-{
-       register struct quehead *element = (struct quehead *) a;
-       register struct quehead *head = (struct quehead *) b;
-       element->qh_link = head->qh_link;
-       head->qh_link = (struct quehead *)element;
-       element->qh_rlink = (struct quehead *)head;
-       ((struct quehead *)(element->qh_link))->qh_rlink
-       = (struct quehead *)element;
-}
-
-inline void
-remque(void *a)
-{
-  register struct quehead *element = (struct quehead *) a;
-  ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
-  ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
-  element->qh_rlink = NULL;
-}
-
-struct gfwd_list *
-add_guestfwd(struct gfwd_list **ex_ptr,
-             SlirpWriteCb write_cb, void *opaque,
-             struct in_addr addr, int port)
-{
-    struct gfwd_list *f = g_new0(struct gfwd_list, 1);
-
-    f->write_cb = write_cb;
-    f->opaque = opaque;
-    f->ex_fport = port;
-    f->ex_addr = addr;
-    f->ex_next = *ex_ptr;
-    *ex_ptr = f;
-
-    return f;
-}
-
-struct gfwd_list *
-add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
-         struct in_addr addr, int port)
-{
-    struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port);
-
-    f->ex_exec = g_strdup(cmdline);
-
-    return f;
-}
-
-static int
-slirp_socketpair_with_oob(int sv[2])
-{
-    struct sockaddr_in addr = {
-        .sin_family = AF_INET,
-        .sin_port = 0,
-        .sin_addr.s_addr = INADDR_ANY,
-    };
-    socklen_t addrlen = sizeof(addr);
-    int ret, s;
-
-    sv[1] = -1;
-    s = slirp_socket(AF_INET, SOCK_STREAM, 0);
-    if (s < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
-        listen(s, 1) < 0 ||
-        getsockname(s, (struct sockaddr *)&addr, &addrlen) < 0) {
-        goto err;
-    }
-
-    sv[1] = slirp_socket(AF_INET, SOCK_STREAM, 0);
-    if (sv[1] < 0) {
-        goto err;
-    }
-    /*
-     * This connect won't block because we've already listen()ed on
-     * the server end (even though we won't accept() the connection
-     * until later on).
-     */
-    do {
-        ret = connect(sv[1], (struct sockaddr *)&addr, addrlen);
-    } while (ret < 0 && errno == EINTR);
-    if (ret < 0) {
-        goto err;
-    }
-
-    do {
-        sv[0] = accept(s, (struct sockaddr *)&addr, &addrlen);
-    } while (sv[0] < 0 && errno == EINTR);
-    if (sv[0] < 0) {
-        goto err;
-    }
-
-    closesocket(s);
-    return 0;
-
-err:
-    g_critical("slirp_socketpair(): %s", strerror(errno));
-    if (s >= 0) {
-        closesocket(s);
-    }
-    if (sv[1] >= 0) {
-        closesocket(sv[1]);
-    }
-    return -1;
-}
-
-static void
-fork_exec_child_setup(gpointer data)
-{
-#ifndef _WIN32
-    setsid();
-#endif
-}
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-
-#if !GLIB_CHECK_VERSION(2, 58, 0)
-typedef struct SlirpGSpawnFds {
-    GSpawnChildSetupFunc child_setup;
-    gpointer user_data;
-    gint stdin_fd;
-    gint stdout_fd;
-    gint stderr_fd;
-} SlirpGSpawnFds;
-
-static inline void
-slirp_gspawn_fds_setup(gpointer user_data)
-{
-    SlirpGSpawnFds *q = (SlirpGSpawnFds *)user_data;
-
-    dup2(q->stdin_fd, 0);
-    dup2(q->stdout_fd, 1);
-    dup2(q->stderr_fd, 2);
-    q->child_setup(q->user_data);
-}
-#endif
-
-static inline gboolean
-g_spawn_async_with_fds_slirp(const gchar *working_directory,
-                            gchar **argv,
-                            gchar **envp,
-                            GSpawnFlags flags,
-                            GSpawnChildSetupFunc child_setup,
-                            gpointer user_data,
-                            GPid *child_pid,
-                            gint stdin_fd,
-                            gint stdout_fd,
-                            gint stderr_fd,
-                            GError **error)
-{
-#if GLIB_CHECK_VERSION(2, 58, 0)
-    return g_spawn_async_with_fds(working_directory, argv, envp, flags,
-                                  child_setup, user_data,
-                                  child_pid, stdin_fd, stdout_fd, stderr_fd,
-                                  error);
-#else
-    SlirpGSpawnFds setup = {
-        .child_setup = child_setup,
-        .user_data = user_data,
-        .stdin_fd = stdin_fd,
-        .stdout_fd = stdout_fd,
-        .stderr_fd = stderr_fd,
-    };
-
-    return g_spawn_async(working_directory, argv, envp, flags,
-                         slirp_gspawn_fds_setup, &setup,
-                         child_pid, error);
-#endif
-}
-
-#define g_spawn_async_with_fds(wd, argv, env, f, c, d, p, ifd, ofd, efd, err) \
-    g_spawn_async_with_fds_slirp(wd, argv, env, f, c, d, p, ifd, ofd, efd, err)
-
-#pragma GCC diagnostic pop
-
-int
-fork_exec(struct socket *so, const char *ex)
-{
-    GError *err = NULL;
-    char **argv;
-    int opt, sp[2];
-
-    DEBUG_CALL("fork_exec");
-    DEBUG_ARG("so = %p", so);
-    DEBUG_ARG("ex = %p", ex);
-
-    if (slirp_socketpair_with_oob(sp) < 0) {
-        return 0;
-    }
-
-    argv = g_strsplit(ex, " ", -1);
-    g_spawn_async_with_fds(NULL /* cwd */,
-                           argv,
-                           NULL /* env */,
-                           G_SPAWN_SEARCH_PATH,
-                           fork_exec_child_setup, NULL /* data */,
-                           NULL /* child_pid */,
-                           sp[1], sp[1], sp[1],
-                           &err);
-    g_strfreev(argv);
-
-    if (err) {
-        g_critical("fork_exec: %s", err->message);
-        g_error_free(err);
-        closesocket(sp[0]);
-        closesocket(sp[1]);
-        return 0;
-    }
-
-    so->s = sp[0];
-    closesocket(sp[1]);
-    slirp_socket_set_fast_reuse(so->s);
-    opt = 1;
-    setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
-    slirp_set_nonblock(so->s);
-    so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
-    return 1;
-}
-
-char *slirp_connection_info(Slirp *slirp)
-{
-    GString *str = g_string_new(NULL);
-    const char * const tcpstates[] = {
-        [TCPS_CLOSED]       = "CLOSED",
-        [TCPS_LISTEN]       = "LISTEN",
-        [TCPS_SYN_SENT]     = "SYN_SENT",
-        [TCPS_SYN_RECEIVED] = "SYN_RCVD",
-        [TCPS_ESTABLISHED]  = "ESTABLISHED",
-        [TCPS_CLOSE_WAIT]   = "CLOSE_WAIT",
-        [TCPS_FIN_WAIT_1]   = "FIN_WAIT_1",
-        [TCPS_CLOSING]      = "CLOSING",
-        [TCPS_LAST_ACK]     = "LAST_ACK",
-        [TCPS_FIN_WAIT_2]   = "FIN_WAIT_2",
-        [TCPS_TIME_WAIT]    = "TIME_WAIT",
-    };
-    struct in_addr dst_addr;
-    struct sockaddr_in src;
-    socklen_t src_len;
-    uint16_t dst_port;
-    struct socket *so;
-    const char *state;
-    char buf[20];
-
-    g_string_append_printf(str,
-        "  Protocol[State]    FD  Source Address  Port   "
-        "Dest. Address  Port RecvQ SendQ\n");
-
-    for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
-        if (so->so_state & SS_HOSTFWD) {
-            state = "HOST_FORWARD";
-        } else if (so->so_tcpcb) {
-            state = tcpstates[so->so_tcpcb->t_state];
-        } else {
-            state = "NONE";
-        }
-        if (so->so_state & (SS_HOSTFWD | SS_INCOMING)) {
-            src_len = sizeof(src);
-            getsockname(so->s, (struct sockaddr *)&src, &src_len);
-            dst_addr = so->so_laddr;
-            dst_port = so->so_lport;
-        } else {
-            src.sin_addr = so->so_laddr;
-            src.sin_port = so->so_lport;
-            dst_addr = so->so_faddr;
-            dst_port = so->so_fport;
-        }
-        snprintf(buf, sizeof(buf), "  TCP[%s]", state);
-        g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s,
-                       src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
-                       ntohs(src.sin_port));
-        g_string_append_printf(str, "%15s %5d %5d %5d\n",
-                       inet_ntoa(dst_addr), ntohs(dst_port),
-                       so->so_rcv.sb_cc, so->so_snd.sb_cc);
-    }
-
-    for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) {
-        if (so->so_state & SS_HOSTFWD) {
-            snprintf(buf, sizeof(buf), "  UDP[HOST_FORWARD]");
-            src_len = sizeof(src);
-            getsockname(so->s, (struct sockaddr *)&src, &src_len);
-            dst_addr = so->so_laddr;
-            dst_port = so->so_lport;
-        } else {
-            snprintf(buf, sizeof(buf), "  UDP[%d sec]",
-                         (so->so_expire - curtime) / 1000);
-            src.sin_addr = so->so_laddr;
-            src.sin_port = so->so_lport;
-            dst_addr = so->so_faddr;
-            dst_port = so->so_fport;
-        }
-        g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s,
-                       src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
-                       ntohs(src.sin_port));
-        g_string_append_printf(str, "%15s %5d %5d %5d\n",
-                       inet_ntoa(dst_addr), ntohs(dst_port),
-                       so->so_rcv.sb_cc, so->so_snd.sb_cc);
-    }
-
-    for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) {
-        snprintf(buf, sizeof(buf), "  ICMP[%d sec]",
-                     (so->so_expire - curtime) / 1000);
-        src.sin_addr = so->so_laddr;
-        dst_addr = so->so_faddr;
-        g_string_append_printf(str, "%-19s %3d %15s  -    ", buf, so->s,
-                       src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*");
-        g_string_append_printf(str, "%15s  -    %5d %5d\n", inet_ntoa(dst_addr),
-                       so->so_rcv.sb_cc, so->so_snd.sb_cc);
-    }
-
-    return g_string_free(str, FALSE);
-}
diff --git a/slirp/misc.h b/slirp/misc.h
deleted file mode 100644 (file)
index c2ceadb..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#ifndef MISC_H
-#define MISC_H
-
-#include "libslirp.h"
-
-struct gfwd_list {
-       SlirpWriteCb write_cb;
-       void *opaque;
-       struct in_addr ex_addr;         /* Server address */
-       int ex_fport;                   /* Port to telnet to */
-       char *ex_exec;                  /* Command line of what to exec */
-       struct gfwd_list *ex_next;
-};
-
-#define EMU_NONE 0x0
-
-/* TCP emulations */
-#define EMU_CTL 0x1
-#define EMU_FTP 0x2
-#define EMU_KSH 0x3
-#define EMU_IRC 0x4
-#define EMU_REALAUDIO 0x5
-#define EMU_RLOGIN 0x6
-#define EMU_IDENT 0x7
-
-#define EMU_NOCONNECT 0x10     /* Don't connect */
-
-struct tos_t {
-    uint16_t lport;
-    uint16_t fport;
-    uint8_t tos;
-    uint8_t emu;
-};
-
-struct emu_t {
-    uint16_t lport;
-    uint16_t fport;
-    uint8_t tos;
-    uint8_t emu;
-    struct emu_t *next;
-};
-
-struct slirp_quehead {
-    struct slirp_quehead *qh_link;
-    struct slirp_quehead *qh_rlink;
-};
-
-void slirp_insque(void *, void *);
-void slirp_remque(void *);
-int fork_exec(struct socket *so, const char *ex);
-
-struct gfwd_list *
-add_guestfwd(struct gfwd_list **ex_ptr,
-             SlirpWriteCb write_cb, void *opaque,
-             struct in_addr addr, int port);
-
-struct gfwd_list *
-add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
-         struct in_addr addr, int port);
-
-#endif
diff --git a/slirp/ncsi-pkt.h b/slirp/ncsi-pkt.h
deleted file mode 100644 (file)
index ea07d1c..0000000
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Copyright Gavin Shan, IBM Corporation 2016.
- *
- * 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.
- */
-
-#ifndef NCSI_PKT_H
-#define NCSI_PKT_H
-
-/* from linux/net/ncsi/ncsi-pkt.h */
-#define __be32 uint32_t
-#define __be16 uint16_t
-
-struct ncsi_pkt_hdr {
-        unsigned char mc_id;        /* Management controller ID */
-        unsigned char revision;     /* NCSI version - 0x01      */
-        unsigned char reserved;     /* Reserved                 */
-        unsigned char id;           /* Packet sequence number   */
-        unsigned char type;         /* Packet type              */
-        unsigned char channel;      /* Network controller ID    */
-        __be16        length;       /* Payload length           */
-        __be32        reserved1[2]; /* Reserved                 */
-};
-
-struct ncsi_cmd_pkt_hdr {
-        struct ncsi_pkt_hdr common; /* Common NCSI packet header */
-};
-
-struct ncsi_rsp_pkt_hdr {
-        struct ncsi_pkt_hdr common; /* Common NCSI packet header */
-        __be16              code;   /* Response code             */
-        __be16              reason; /* Response reason           */
-};
-
-struct ncsi_aen_pkt_hdr {
-        struct ncsi_pkt_hdr common;       /* Common NCSI packet header */
-        unsigned char       reserved2[3]; /* Reserved                  */
-        unsigned char       type;         /* AEN packet type           */
-};
-
-/* NCSI common command packet */
-struct ncsi_cmd_pkt {
-        struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
-        __be32                  checksum; /* Checksum       */
-        unsigned char           pad[26];
-};
-
-struct ncsi_rsp_pkt {
-        struct ncsi_rsp_pkt_hdr rsp;      /* Response header */
-        __be32                  checksum; /* Checksum        */
-        unsigned char           pad[22];
-};
-
-/* Select Package */
-struct ncsi_cmd_sp_pkt {
-        struct ncsi_cmd_pkt_hdr cmd;            /* Command header */
-        unsigned char           reserved[3];    /* Reserved       */
-        unsigned char           hw_arbitration; /* HW arbitration */
-        __be32                  checksum;       /* Checksum       */
-        unsigned char           pad[22];
-};
-
-/* Disable Channel */
-struct ncsi_cmd_dc_pkt {
-        struct ncsi_cmd_pkt_hdr cmd;         /* Command header  */
-        unsigned char           reserved[3]; /* Reserved        */
-        unsigned char           ald;         /* Allow link down */
-        __be32                  checksum;    /* Checksum        */
-        unsigned char           pad[22];
-};
-
-/* Reset Channel */
-struct ncsi_cmd_rc_pkt {
-        struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
-        __be32                  reserved; /* Reserved       */
-        __be32                  checksum; /* Checksum       */
-        unsigned char           pad[22];
-};
-
-/* AEN Enable */
-struct ncsi_cmd_ae_pkt {
-        struct ncsi_cmd_pkt_hdr cmd;         /* Command header   */
-        unsigned char           reserved[3]; /* Reserved         */
-        unsigned char           mc_id;       /* MC ID            */
-        __be32                  mode;        /* AEN working mode */
-        __be32                  checksum;    /* Checksum         */
-        unsigned char           pad[18];
-};
-
-/* Set Link */
-struct ncsi_cmd_sl_pkt {
-        struct ncsi_cmd_pkt_hdr cmd;      /* Command header    */
-        __be32                  mode;     /* Link working mode */
-        __be32                  oem_mode; /* OEM link mode     */
-        __be32                  checksum; /* Checksum          */
-        unsigned char           pad[18];
-};
-
-/* Set VLAN Filter */
-struct ncsi_cmd_svf_pkt {
-        struct ncsi_cmd_pkt_hdr cmd;       /* Command header    */
-        __be16                  reserved;  /* Reserved          */
-        __be16                  vlan;      /* VLAN ID           */
-        __be16                  reserved1; /* Reserved          */
-        unsigned char           index;     /* VLAN table index  */
-        unsigned char           enable;    /* Enable or disable */
-        __be32                  checksum;  /* Checksum          */
-        unsigned char           pad[14];
-};
-
-/* Enable VLAN */
-struct ncsi_cmd_ev_pkt {
-        struct ncsi_cmd_pkt_hdr cmd;         /* Command header   */
-        unsigned char           reserved[3]; /* Reserved         */
-        unsigned char           mode;        /* VLAN filter mode */
-        __be32                  checksum;    /* Checksum         */
-        unsigned char           pad[22];
-};
-
-/* Set MAC Address */
-struct ncsi_cmd_sma_pkt {
-        struct ncsi_cmd_pkt_hdr cmd;      /* Command header          */
-        unsigned char           mac[6];   /* MAC address             */
-        unsigned char           index;    /* MAC table index         */
-        unsigned char           at_e;     /* Addr type and operation */
-        __be32                  checksum; /* Checksum                */
-        unsigned char           pad[18];
-};
-
-/* Enable Broadcast Filter */
-struct ncsi_cmd_ebf_pkt {
-        struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
-        __be32                  mode;     /* Filter mode    */
-        __be32                  checksum; /* Checksum       */
-        unsigned char           pad[22];
-};
-
-/* Enable Global Multicast Filter */
-struct ncsi_cmd_egmf_pkt {
-        struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
-        __be32                  mode;     /* Global MC mode */
-        __be32                  checksum; /* Checksum       */
-        unsigned char           pad[22];
-};
-
-/* Set NCSI Flow Control */
-struct ncsi_cmd_snfc_pkt {
-        struct ncsi_cmd_pkt_hdr cmd;         /* Command header    */
-        unsigned char           reserved[3]; /* Reserved          */
-        unsigned char           mode;        /* Flow control mode */
-        __be32                  checksum;    /* Checksum          */
-        unsigned char           pad[22];
-};
-
-/* Get Link Status */
-struct ncsi_rsp_gls_pkt {
-        struct ncsi_rsp_pkt_hdr rsp;        /* Response header   */
-        __be32                  status;     /* Link status       */
-        __be32                  other;      /* Other indications */
-        __be32                  oem_status; /* OEM link status   */
-        __be32                  checksum;
-        unsigned char           pad[10];
-};
-
-/* Get Version ID */
-struct ncsi_rsp_gvi_pkt {
-        struct ncsi_rsp_pkt_hdr rsp;          /* Response header */
-        __be32                  ncsi_version; /* NCSI version    */
-        unsigned char           reserved[3];  /* Reserved        */
-        unsigned char           alpha2;       /* NCSI version    */
-        unsigned char           fw_name[12];  /* f/w name string */
-        __be32                  fw_version;   /* f/w version     */
-        __be16                  pci_ids[4];   /* PCI IDs         */
-        __be32                  mf_id;        /* Manufacture ID  */
-        __be32                  checksum;
-};
-
-/* Get Capabilities */
-struct ncsi_rsp_gc_pkt {
-        struct ncsi_rsp_pkt_hdr rsp;         /* Response header   */
-        __be32                  cap;         /* Capabilities      */
-        __be32                  bc_cap;      /* Broadcast cap     */
-        __be32                  mc_cap;      /* Multicast cap     */
-        __be32                  buf_cap;     /* Buffering cap     */
-        __be32                  aen_cap;     /* AEN cap           */
-        unsigned char           vlan_cnt;    /* VLAN filter count */
-        unsigned char           mixed_cnt;   /* Mix filter count  */
-        unsigned char           mc_cnt;      /* MC filter count   */
-        unsigned char           uc_cnt;      /* UC filter count   */
-        unsigned char           reserved[2]; /* Reserved          */
-        unsigned char           vlan_mode;   /* VLAN mode         */
-        unsigned char           channel_cnt; /* Channel count     */
-        __be32                  checksum;    /* Checksum          */
-};
-
-/* Get Parameters */
-struct ncsi_rsp_gp_pkt {
-        struct ncsi_rsp_pkt_hdr rsp;          /* Response header       */
-        unsigned char           mac_cnt;      /* Number of MAC addr    */
-        unsigned char           reserved[2];  /* Reserved              */
-        unsigned char           mac_enable;   /* MAC addr enable flags */
-        unsigned char           vlan_cnt;     /* VLAN tag count        */
-        unsigned char           reserved1;    /* Reserved              */
-        __be16                  vlan_enable;  /* VLAN tag enable flags */
-        __be32                  link_mode;    /* Link setting          */
-        __be32                  bc_mode;      /* BC filter mode        */
-        __be32                  valid_modes;  /* Valid mode parameters */
-        unsigned char           vlan_mode;    /* VLAN mode             */
-        unsigned char           fc_mode;      /* Flow control mode     */
-        unsigned char           reserved2[2]; /* Reserved              */
-        __be32                  aen_mode;     /* AEN mode              */
-        unsigned char           mac[6];       /* Supported MAC addr    */
-        __be16                  vlan;         /* Supported VLAN tags   */
-        __be32                  checksum;     /* Checksum              */
-};
-
-/* Get Controller Packet Statistics */
-struct ncsi_rsp_gcps_pkt {
-        struct ncsi_rsp_pkt_hdr rsp;            /* Response header            */
-        __be32                  cnt_hi;         /* Counter cleared            */
-        __be32                  cnt_lo;         /* Counter cleared            */
-        __be32                  rx_bytes;       /* Rx bytes                   */
-        __be32                  tx_bytes;       /* Tx bytes                   */
-        __be32                  rx_uc_pkts;     /* Rx UC packets              */
-        __be32                  rx_mc_pkts;     /* Rx MC packets              */
-        __be32                  rx_bc_pkts;     /* Rx BC packets              */
-        __be32                  tx_uc_pkts;     /* Tx UC packets              */
-        __be32                  tx_mc_pkts;     /* Tx MC packets              */
-        __be32                  tx_bc_pkts;     /* Tx BC packets              */
-        __be32                  fcs_err;        /* FCS errors                 */
-        __be32                  align_err;      /* Alignment errors           */
-        __be32                  false_carrier;  /* False carrier detection    */
-        __be32                  runt_pkts;      /* Rx runt packets            */
-        __be32                  jabber_pkts;    /* Rx jabber packets          */
-        __be32                  rx_pause_xon;   /* Rx pause XON frames        */
-        __be32                  rx_pause_xoff;  /* Rx XOFF frames             */
-        __be32                  tx_pause_xon;   /* Tx XON frames              */
-        __be32                  tx_pause_xoff;  /* Tx XOFF frames             */
-        __be32                  tx_s_collision; /* Single collision frames    */
-        __be32                  tx_m_collision; /* Multiple collision frames  */
-        __be32                  l_collision;    /* Late collision frames      */
-        __be32                  e_collision;    /* Excessive collision frames */
-        __be32                  rx_ctl_frames;  /* Rx control frames          */
-        __be32                  rx_64_frames;   /* Rx 64-bytes frames         */
-        __be32                  rx_127_frames;  /* Rx 65-127 bytes frames     */
-        __be32                  rx_255_frames;  /* Rx 128-255 bytes frames    */
-        __be32                  rx_511_frames;  /* Rx 256-511 bytes frames    */
-        __be32                  rx_1023_frames; /* Rx 512-1023 bytes frames   */
-        __be32                  rx_1522_frames; /* Rx 1024-1522 bytes frames  */
-        __be32                  rx_9022_frames; /* Rx 1523-9022 bytes frames  */
-        __be32                  tx_64_frames;   /* Tx 64-bytes frames         */
-        __be32                  tx_127_frames;  /* Tx 65-127 bytes frames     */
-        __be32                  tx_255_frames;  /* Tx 128-255 bytes frames    */
-        __be32                  tx_511_frames;  /* Tx 256-511 bytes frames    */
-        __be32                  tx_1023_frames; /* Tx 512-1023 bytes frames   */
-        __be32                  tx_1522_frames; /* Tx 1024-1522 bytes frames  */
-        __be32                  tx_9022_frames; /* Tx 1523-9022 bytes frames  */
-        __be32                  rx_valid_bytes; /* Rx valid bytes             */
-        __be32                  rx_runt_pkts;   /* Rx error runt packets      */
-        __be32                  rx_jabber_pkts; /* Rx error jabber packets    */
-        __be32                  checksum;       /* Checksum                   */
-};
-
-/* Get NCSI Statistics */
-struct ncsi_rsp_gns_pkt {
-        struct ncsi_rsp_pkt_hdr rsp;           /* Response header         */
-        __be32                  rx_cmds;       /* Rx NCSI commands        */
-        __be32                  dropped_cmds;  /* Dropped commands        */
-        __be32                  cmd_type_errs; /* Command type errors     */
-        __be32                  cmd_csum_errs; /* Command checksum errors */
-        __be32                  rx_pkts;       /* Rx NCSI packets         */
-        __be32                  tx_pkts;       /* Tx NCSI packets         */
-        __be32                  tx_aen_pkts;   /* Tx AEN packets          */
-        __be32                  checksum;      /* Checksum                */
-};
-
-/* Get NCSI Pass-through Statistics */
-struct ncsi_rsp_gnpts_pkt {
-        struct ncsi_rsp_pkt_hdr rsp;            /* Response header     */
-        __be32                  tx_pkts;        /* Tx packets          */
-        __be32                  tx_dropped;     /* Tx dropped packets  */
-        __be32                  tx_channel_err; /* Tx channel errors   */
-        __be32                  tx_us_err;      /* Tx undersize errors */
-        __be32                  rx_pkts;        /* Rx packets          */
-        __be32                  rx_dropped;     /* Rx dropped packets  */
-        __be32                  rx_channel_err; /* Rx channel errors   */
-        __be32                  rx_us_err;      /* Rx undersize errors */
-        __be32                  rx_os_err;      /* Rx oversize errors  */
-        __be32                  checksum;       /* Checksum            */
-};
-
-/* Get package status */
-struct ncsi_rsp_gps_pkt {
-        struct ncsi_rsp_pkt_hdr rsp;      /* Response header             */
-        __be32                  status;   /* Hardware arbitration status */
-        __be32                  checksum;
-};
-
-/* Get package UUID */
-struct ncsi_rsp_gpuuid_pkt {
-        struct ncsi_rsp_pkt_hdr rsp;      /* Response header */
-        unsigned char           uuid[16]; /* UUID            */
-        __be32                  checksum;
-};
-
-/* AEN: Link State Change */
-struct ncsi_aen_lsc_pkt {
-        struct ncsi_aen_pkt_hdr aen;        /* AEN header      */
-        __be32                  status;     /* Link status     */
-        __be32                  oem_status; /* OEM link status */
-        __be32                  checksum;   /* Checksum        */
-        unsigned char           pad[14];
-};
-
-/* AEN: Configuration Required */
-struct ncsi_aen_cr_pkt {
-        struct ncsi_aen_pkt_hdr aen;      /* AEN header */
-        __be32                  checksum; /* Checksum   */
-        unsigned char           pad[22];
-};
-
-/* AEN: Host Network Controller Driver Status Change */
-struct ncsi_aen_hncdsc_pkt {
-        struct ncsi_aen_pkt_hdr aen;      /* AEN header */
-        __be32                  status;   /* Status     */
-        __be32                  checksum; /* Checksum   */
-        unsigned char           pad[18];
-};
-
-/* NCSI packet revision */
-#define NCSI_PKT_REVISION       0x01
-
-/* NCSI packet commands */
-#define NCSI_PKT_CMD_CIS        0x00 /* Clear Initial State              */
-#define NCSI_PKT_CMD_SP         0x01 /* Select Package                   */
-#define NCSI_PKT_CMD_DP         0x02 /* Deselect Package                 */
-#define NCSI_PKT_CMD_EC         0x03 /* Enable Channel                   */
-#define NCSI_PKT_CMD_DC         0x04 /* Disable Channel                  */
-#define NCSI_PKT_CMD_RC         0x05 /* Reset Channel                    */
-#define NCSI_PKT_CMD_ECNT       0x06 /* Enable Channel Network Tx        */
-#define NCSI_PKT_CMD_DCNT       0x07 /* Disable Channel Network Tx       */
-#define NCSI_PKT_CMD_AE         0x08 /* AEN Enable                       */
-#define NCSI_PKT_CMD_SL         0x09 /* Set Link                         */
-#define NCSI_PKT_CMD_GLS        0x0a /* Get Link                         */
-#define NCSI_PKT_CMD_SVF        0x0b /* Set VLAN Filter                  */
-#define NCSI_PKT_CMD_EV         0x0c /* Enable VLAN                      */
-#define NCSI_PKT_CMD_DV         0x0d /* Disable VLAN                     */
-#define NCSI_PKT_CMD_SMA        0x0e /* Set MAC address                  */
-#define NCSI_PKT_CMD_EBF        0x10 /* Enable Broadcast Filter          */
-#define NCSI_PKT_CMD_DBF        0x11 /* Disable Broadcast Filter         */
-#define NCSI_PKT_CMD_EGMF       0x12 /* Enable Global Multicast Filter   */
-#define NCSI_PKT_CMD_DGMF       0x13 /* Disable Global Multicast Filter  */
-#define NCSI_PKT_CMD_SNFC       0x14 /* Set NCSI Flow Control            */
-#define NCSI_PKT_CMD_GVI        0x15 /* Get Version ID                   */
-#define NCSI_PKT_CMD_GC         0x16 /* Get Capabilities                 */
-#define NCSI_PKT_CMD_GP         0x17 /* Get Parameters                   */
-#define NCSI_PKT_CMD_GCPS       0x18 /* Get Controller Packet Statistics */
-#define NCSI_PKT_CMD_GNS        0x19 /* Get NCSI Statistics              */
-#define NCSI_PKT_CMD_GNPTS      0x1a /* Get NCSI Pass-throu Statistics   */
-#define NCSI_PKT_CMD_GPS        0x1b /* Get package status               */
-#define NCSI_PKT_CMD_OEM        0x50 /* OEM                              */
-#define NCSI_PKT_CMD_PLDM       0x51 /* PLDM request over NCSI over RBT  */
-#define NCSI_PKT_CMD_GPUUID     0x52 /* Get package UUID                 */
-
-/* NCSI packet responses */
-#define NCSI_PKT_RSP_CIS        (NCSI_PKT_CMD_CIS    + 0x80)
-#define NCSI_PKT_RSP_SP         (NCSI_PKT_CMD_SP     + 0x80)
-#define NCSI_PKT_RSP_DP         (NCSI_PKT_CMD_DP     + 0x80)
-#define NCSI_PKT_RSP_EC         (NCSI_PKT_CMD_EC     + 0x80)
-#define NCSI_PKT_RSP_DC         (NCSI_PKT_CMD_DC     + 0x80)
-#define NCSI_PKT_RSP_RC         (NCSI_PKT_CMD_RC     + 0x80)
-#define NCSI_PKT_RSP_ECNT       (NCSI_PKT_CMD_ECNT   + 0x80)
-#define NCSI_PKT_RSP_DCNT       (NCSI_PKT_CMD_DCNT   + 0x80)
-#define NCSI_PKT_RSP_AE         (NCSI_PKT_CMD_AE     + 0x80)
-#define NCSI_PKT_RSP_SL         (NCSI_PKT_CMD_SL     + 0x80)
-#define NCSI_PKT_RSP_GLS        (NCSI_PKT_CMD_GLS    + 0x80)
-#define NCSI_PKT_RSP_SVF        (NCSI_PKT_CMD_SVF    + 0x80)
-#define NCSI_PKT_RSP_EV         (NCSI_PKT_CMD_EV     + 0x80)
-#define NCSI_PKT_RSP_DV         (NCSI_PKT_CMD_DV     + 0x80)
-#define NCSI_PKT_RSP_SMA        (NCSI_PKT_CMD_SMA    + 0x80)
-#define NCSI_PKT_RSP_EBF        (NCSI_PKT_CMD_EBF    + 0x80)
-#define NCSI_PKT_RSP_DBF        (NCSI_PKT_CMD_DBF    + 0x80)
-#define NCSI_PKT_RSP_EGMF       (NCSI_PKT_CMD_EGMF   + 0x80)
-#define NCSI_PKT_RSP_DGMF       (NCSI_PKT_CMD_DGMF   + 0x80)
-#define NCSI_PKT_RSP_SNFC       (NCSI_PKT_CMD_SNFC   + 0x80)
-#define NCSI_PKT_RSP_GVI        (NCSI_PKT_CMD_GVI    + 0x80)
-#define NCSI_PKT_RSP_GC         (NCSI_PKT_CMD_GC     + 0x80)
-#define NCSI_PKT_RSP_GP         (NCSI_PKT_CMD_GP     + 0x80)
-#define NCSI_PKT_RSP_GCPS       (NCSI_PKT_CMD_GCPS   + 0x80)
-#define NCSI_PKT_RSP_GNS        (NCSI_PKT_CMD_GNS    + 0x80)
-#define NCSI_PKT_RSP_GNPTS      (NCSI_PKT_CMD_GNPTS  + 0x80)
-#define NCSI_PKT_RSP_GPS        (NCSI_PKT_CMD_GPS    + 0x80)
-#define NCSI_PKT_RSP_OEM        (NCSI_PKT_CMD_OEM    + 0x80)
-#define NCSI_PKT_RSP_PLDM       (NCSI_PKT_CMD_PLDM   + 0x80)
-#define NCSI_PKT_RSP_GPUUID     (NCSI_PKT_CMD_GPUUID + 0x80)
-
-/* NCSI response code/reason */
-#define NCSI_PKT_RSP_C_COMPLETED        0x0000 /* Command Completed        */
-#define NCSI_PKT_RSP_C_FAILED           0x0001 /* Command Failed           */
-#define NCSI_PKT_RSP_C_UNAVAILABLE      0x0002 /* Command Unavailable      */
-#define NCSI_PKT_RSP_C_UNSUPPORTED      0x0003 /* Command Unsupported      */
-#define NCSI_PKT_RSP_R_NO_ERROR         0x0000 /* No Error                 */
-#define NCSI_PKT_RSP_R_INTERFACE        0x0001 /* Interface not ready      */
-#define NCSI_PKT_RSP_R_PARAM            0x0002 /* Invalid Parameter        */
-#define NCSI_PKT_RSP_R_CHANNEL          0x0003 /* Channel not Ready        */
-#define NCSI_PKT_RSP_R_PACKAGE          0x0004 /* Package not Ready        */
-#define NCSI_PKT_RSP_R_LENGTH           0x0005 /* Invalid payload length   */
-#define NCSI_PKT_RSP_R_UNKNOWN          0x7fff /* Command type unsupported */
-
-/* NCSI AEN packet type */
-#define NCSI_PKT_AEN            0xFF /* AEN Packet               */
-#define NCSI_PKT_AEN_LSC        0x00 /* Link status change       */
-#define NCSI_PKT_AEN_CR         0x01 /* Configuration required   */
-#define NCSI_PKT_AEN_HNCDSC     0x02 /* HNC driver status change */
-
-#endif /* NCSI_PKT_H */
diff --git a/slirp/ncsi.c b/slirp/ncsi.c
deleted file mode 100644 (file)
index 359f52c..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * NC-SI (Network Controller Sideband Interface) "echo" model
- *
- * Copyright (C) 2016-2018 IBM Corp.
- *
- * This code is licensed under the GPL version 2 or later. See the
- * COPYING file in the top-level directory.
- */
-#include "slirp.h"
-
-#include "ncsi-pkt.h"
-
-static uint32_t ncsi_calculate_checksum(uint16_t *data, int len)
-{
-    uint32_t checksum = 0;
-    int i;
-
-    /*
-     * 32-bit unsigned sum of the NC-SI packet header and NC-SI packet
-     * payload interpreted as a series of 16-bit unsigned integer values.
-     */
-    for (i = 0; i < len; i++) {
-        checksum += htons(data[i]);
-    }
-
-    checksum = (~checksum + 1);
-    return checksum;
-}
-
-/* Get Capabilities */
-static int ncsi_rsp_handler_gc(struct ncsi_rsp_pkt_hdr *rnh)
-{
-    struct ncsi_rsp_gc_pkt *rsp = (struct ncsi_rsp_gc_pkt *) rnh;
-
-    rsp->cap = htonl(~0);
-    rsp->bc_cap = htonl(~0);
-    rsp->mc_cap = htonl(~0);
-    rsp->buf_cap = htonl(~0);
-    rsp->aen_cap = htonl(~0);
-    rsp->vlan_mode = 0xff;
-    rsp->uc_cnt = 2;
-    return 0;
-}
-
-/* Get Link status */
-static int ncsi_rsp_handler_gls(struct ncsi_rsp_pkt_hdr *rnh)
-{
-    struct ncsi_rsp_gls_pkt *rsp = (struct ncsi_rsp_gls_pkt *) rnh;
-
-    rsp->status = htonl(0x1);
-    return 0;
-}
-
-/* Get Parameters */
-static int ncsi_rsp_handler_gp(struct ncsi_rsp_pkt_hdr *rnh)
-{
-    struct ncsi_rsp_gp_pkt *rsp = (struct ncsi_rsp_gp_pkt *) rnh;
-
-    /* no MAC address filters or VLAN filters on the channel */
-    rsp->mac_cnt = 0;
-    rsp->mac_enable = 0;
-    rsp->vlan_cnt = 0;
-    rsp->vlan_enable = 0;
-
-    return 0;
-}
-
-static const struct ncsi_rsp_handler {
-        unsigned char   type;
-        int             payload;
-        int             (*handler)(struct ncsi_rsp_pkt_hdr *rnh);
-} ncsi_rsp_handlers[] = {
-        { NCSI_PKT_RSP_CIS,     4, NULL },
-        { NCSI_PKT_RSP_SP,      4, NULL },
-        { NCSI_PKT_RSP_DP,      4, NULL },
-        { NCSI_PKT_RSP_EC,      4, NULL },
-        { NCSI_PKT_RSP_DC,      4, NULL },
-        { NCSI_PKT_RSP_RC,      4, NULL },
-        { NCSI_PKT_RSP_ECNT,    4, NULL },
-        { NCSI_PKT_RSP_DCNT,    4, NULL },
-        { NCSI_PKT_RSP_AE,      4, NULL },
-        { NCSI_PKT_RSP_SL,      4, NULL },
-        { NCSI_PKT_RSP_GLS,    16, ncsi_rsp_handler_gls },
-        { NCSI_PKT_RSP_SVF,     4, NULL },
-        { NCSI_PKT_RSP_EV,      4, NULL },
-        { NCSI_PKT_RSP_DV,      4, NULL },
-        { NCSI_PKT_RSP_SMA,     4, NULL },
-        { NCSI_PKT_RSP_EBF,     4, NULL },
-        { NCSI_PKT_RSP_DBF,     4, NULL },
-        { NCSI_PKT_RSP_EGMF,    4, NULL },
-        { NCSI_PKT_RSP_DGMF,    4, NULL },
-        { NCSI_PKT_RSP_SNFC,    4, NULL },
-        { NCSI_PKT_RSP_GVI,    40, NULL },
-        { NCSI_PKT_RSP_GC,     32, ncsi_rsp_handler_gc },
-        { NCSI_PKT_RSP_GP,     40, ncsi_rsp_handler_gp },
-        { NCSI_PKT_RSP_GCPS,  172, NULL },
-        { NCSI_PKT_RSP_GNS,   172, NULL },
-        { NCSI_PKT_RSP_GNPTS, 172, NULL },
-        { NCSI_PKT_RSP_GPS,     8, NULL },
-        { NCSI_PKT_RSP_OEM,     0, NULL },
-        { NCSI_PKT_RSP_PLDM,    0, NULL },
-        { NCSI_PKT_RSP_GPUUID, 20, NULL }
-};
-
-/*
- * packet format : ncsi header + payload + checksum
- */
-#define NCSI_MAX_PAYLOAD 172
-#define NCSI_MAX_LEN     (sizeof(struct ncsi_pkt_hdr) + NCSI_MAX_PAYLOAD + 4)
-
-void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
-{
-    struct ncsi_pkt_hdr *nh = (struct ncsi_pkt_hdr *)(pkt + ETH_HLEN);
-    uint8_t ncsi_reply[ETH_HLEN + NCSI_MAX_LEN];
-    struct ethhdr *reh = (struct ethhdr *)ncsi_reply;
-    struct ncsi_rsp_pkt_hdr *rnh = (struct ncsi_rsp_pkt_hdr *)
-        (ncsi_reply + ETH_HLEN);
-    const struct ncsi_rsp_handler *handler = NULL;
-    int i;
-    int ncsi_rsp_len = sizeof(*nh);
-    uint32_t checksum;
-    uint32_t *pchecksum;
-
-    memset(ncsi_reply, 0, sizeof(ncsi_reply));
-
-    memset(reh->h_dest, 0xff, ETH_ALEN);
-    memset(reh->h_source, 0xff, ETH_ALEN);
-    reh->h_proto = htons(ETH_P_NCSI);
-
-    for (i = 0; i < G_N_ELEMENTS(ncsi_rsp_handlers); i++) {
-        if (ncsi_rsp_handlers[i].type == nh->type + 0x80) {
-            handler = &ncsi_rsp_handlers[i];
-            break;
-        }
-    }
-
-    rnh->common.mc_id      = nh->mc_id;
-    rnh->common.revision   = NCSI_PKT_REVISION;
-    rnh->common.id         = nh->id;
-    rnh->common.type       = nh->type + 0x80;
-    rnh->common.channel    = nh->channel;
-
-    if (handler) {
-        rnh->common.length = htons(handler->payload);
-        rnh->code          = htons(NCSI_PKT_RSP_C_COMPLETED);
-        rnh->reason        = htons(NCSI_PKT_RSP_R_NO_ERROR);
-
-        if (handler->handler) {
-            /* TODO: handle errors */
-            handler->handler(rnh);
-        }
-        ncsi_rsp_len += handler->payload;
-    } else {
-        rnh->common.length = 0;
-        rnh->code          = htons(NCSI_PKT_RSP_C_UNAVAILABLE);
-        rnh->reason        = htons(NCSI_PKT_RSP_R_UNKNOWN);
-    }
-
-    /* Add the optional checksum at the end of the frame. */
-    checksum = ncsi_calculate_checksum((uint16_t *) rnh, ncsi_rsp_len);
-    pchecksum = (uint32_t *)((void *) rnh + ncsi_rsp_len);
-    *pchecksum = htonl(checksum);
-    ncsi_rsp_len += 4;
-
-    slirp_send_packet_all(slirp, ncsi_reply, ETH_HLEN + ncsi_rsp_len);
-}
diff --git a/slirp/ndp_table.c b/slirp/ndp_table.c
deleted file mode 100644 (file)
index 34ea4fd..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2013
- * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
- */
-
-#include "slirp.h"
-
-void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
-                    uint8_t ethaddr[ETH_ALEN])
-{
-    char addrstr[INET6_ADDRSTRLEN];
-    NdpTable *ndp_table = &slirp->ndp_table;
-    int i;
-
-    inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
-
-    DEBUG_CALL("ndp_table_add");
-    DEBUG_ARG("ip = %s", addrstr);
-    DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
-              ethaddr[0], ethaddr[1], ethaddr[2],
-              ethaddr[3], ethaddr[4], ethaddr[5]);
-
-    if (IN6_IS_ADDR_MULTICAST(&ip_addr) || in6_zero(&ip_addr)) {
-        /* Do not register multicast or unspecified addresses */
-        DEBUG_CALL(" abort: do not register multicast or unspecified address");
-        return;
-    }
-
-    /* Search for an entry */
-    for (i = 0; i < NDP_TABLE_SIZE; i++) {
-        if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) {
-            DEBUG_CALL(" already in table: update the entry");
-            /* Update the entry */
-            memcpy(ndp_table->table[i].eth_addr, ethaddr, ETH_ALEN);
-            return;
-        }
-    }
-
-    /* No entry found, create a new one */
-    DEBUG_CALL(" create new entry");
-    ndp_table->table[ndp_table->next_victim].ip_addr = ip_addr;
-    memcpy(ndp_table->table[ndp_table->next_victim].eth_addr,
-            ethaddr, ETH_ALEN);
-    ndp_table->next_victim = (ndp_table->next_victim + 1) % NDP_TABLE_SIZE;
-}
-
-bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
-                      uint8_t out_ethaddr[ETH_ALEN])
-{
-    char addrstr[INET6_ADDRSTRLEN];
-    NdpTable *ndp_table = &slirp->ndp_table;
-    int i;
-
-    inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
-
-    DEBUG_CALL("ndp_table_search");
-    DEBUG_ARG("ip = %s", addrstr);
-
-    assert(!in6_zero(&ip_addr));
-
-    /* Multicast address: fec0::abcd:efgh/8 -> 33:33:ab:cd:ef:gh */
-    if (IN6_IS_ADDR_MULTICAST(&ip_addr)) {
-        out_ethaddr[0] = 0x33; out_ethaddr[1] = 0x33;
-        out_ethaddr[2] = ip_addr.s6_addr[12];
-        out_ethaddr[3] = ip_addr.s6_addr[13];
-        out_ethaddr[4] = ip_addr.s6_addr[14];
-        out_ethaddr[5] = ip_addr.s6_addr[15];
-        DEBUG_ARG("multicast addr = %02x:%02x:%02x:%02x:%02x:%02x",
-                  out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
-                  out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
-        return 1;
-    }
-
-    for (i = 0; i < NDP_TABLE_SIZE; i++) {
-        if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) {
-            memcpy(out_ethaddr, ndp_table->table[i].eth_addr,  ETH_ALEN);
-            DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
-                      out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
-                      out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
-            return 1;
-        }
-    }
-
-    DEBUG_CALL(" ip not found in table");
-    return 0;
-}
diff --git a/slirp/qtailq.h b/slirp/qtailq.h
deleted file mode 100644 (file)
index a89b0c4..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-/*      $NetBSD: queue.h,v 1.52 2009/04/20 09:56:08 mschuett Exp $ */
-
-/*
- * slirp version: Copy from QEMU, removed all but tail queues.
- */
-
-/*
- * Copyright (c) 1991, 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. 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.
- *
- *      @(#)queue.h     8.5 (Berkeley) 8/20/94
- */
-
-#ifndef QTAILQ_H
-#define QTAILQ_H
-
-/*
- * A tail queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are doubly
- * linked so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before or
- * after an existing element, at the head of the list, or at the end of
- * the list. A tail queue may be traversed in either direction.
- */
-typedef struct QTailQLink {
-    void *tql_next;
-    struct QTailQLink *tql_prev;
-} QTailQLink;
-
-/*
- * Tail queue definitions.  The union acts as a poor man template, as if
- * it were QTailQLink<type>.
- */
-#define QTAILQ_HEAD(name, type)                                         \
-    union name {                                                        \
-        struct type *tqh_first;       /* first element */               \
-        QTailQLink tqh_circ;          /* link for circular backwards list */ \
-    }
-
-#define QTAILQ_HEAD_INITIALIZER(head)           \
-    { .tqh_circ = { NULL, &(head).tqh_circ } }
-
-#define QTAILQ_ENTRY(type)                                              \
-    union {                                                             \
-        struct type *tqe_next;        /* next element */                \
-        QTailQLink tqe_circ;          /* link for circular backwards list */ \
-    }
-
-#define QTAILQ_INIT(head) do {                                          \
-        (head)->tqh_first = NULL;                                       \
-        (head)->tqh_circ.tql_prev = &(head)->tqh_circ;                  \
-} while (/*CONSTCOND*/0)
-
-#define QTAILQ_INSERT_HEAD(head, elm, field) do {                       \
-        if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)        \
-            (head)->tqh_first->field.tqe_circ.tql_prev =                \
-                &(elm)->field.tqe_circ;                                 \
-        else                                                            \
-            (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ;         \
-        (head)->tqh_first = (elm);                                      \
-        (elm)->field.tqe_circ.tql_prev = &(head)->tqh_circ;             \
-} while (/*CONSTCOND*/0)
-
-#define QTAILQ_INSERT_TAIL(head, elm, field) do {                       \
-        (elm)->field.tqe_next = NULL;                                   \
-        (elm)->field.tqe_circ.tql_prev = (head)->tqh_circ.tql_prev;     \
-        (head)->tqh_circ.tql_prev->tql_next = (elm);                    \
-        (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ;             \
-} while (/*CONSTCOND*/0)
-
-#define QTAILQ_INSERT_AFTER(head, listelm, elm, field) do {             \
-        if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
-            (elm)->field.tqe_next->field.tqe_circ.tql_prev =            \
-                &(elm)->field.tqe_circ;                                 \
-        else                                                            \
-            (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ;         \
-        (listelm)->field.tqe_next = (elm);                              \
-        (elm)->field.tqe_circ.tql_prev = &(listelm)->field.tqe_circ;    \
-} while (/*CONSTCOND*/0)
-
-#define QTAILQ_INSERT_BEFORE(listelm, elm, field) do {                       \
-        (elm)->field.tqe_circ.tql_prev = (listelm)->field.tqe_circ.tql_prev; \
-        (elm)->field.tqe_next = (listelm);                                   \
-        (listelm)->field.tqe_circ.tql_prev->tql_next = (elm);                \
-        (listelm)->field.tqe_circ.tql_prev = &(elm)->field.tqe_circ;         \
-} while (/*CONSTCOND*/0)
-
-#define QTAILQ_REMOVE(head, elm, field) do {                            \
-        if (((elm)->field.tqe_next) != NULL)                            \
-            (elm)->field.tqe_next->field.tqe_circ.tql_prev =            \
-                (elm)->field.tqe_circ.tql_prev;                         \
-        else                                                            \
-            (head)->tqh_circ.tql_prev = (elm)->field.tqe_circ.tql_prev; \
-        (elm)->field.tqe_circ.tql_prev->tql_next = (elm)->field.tqe_next; \
-        (elm)->field.tqe_circ.tql_prev = NULL;                          \
-} while (/*CONSTCOND*/0)
-
-#define QTAILQ_FOREACH(var, head, field)                                \
-        for ((var) = ((head)->tqh_first);                               \
-                (var);                                                  \
-                (var) = ((var)->field.tqe_next))
-
-#define QTAILQ_FOREACH_SAFE(var, head, field, next_var)                 \
-        for ((var) = ((head)->tqh_first);                               \
-                (var) && ((next_var) = ((var)->field.tqe_next), 1);     \
-                (var) = (next_var))
-
-#define QTAILQ_FOREACH_REVERSE(var, head, field)                        \
-        for ((var) = QTAILQ_LAST(head);                                 \
-                (var);                                                  \
-                (var) = QTAILQ_PREV(var, field))
-
-#define QTAILQ_FOREACH_REVERSE_SAFE(var, head, field, prev_var)         \
-        for ((var) = QTAILQ_LAST(head);                                 \
-             (var) && ((prev_var) = QTAILQ_PREV(var, field));           \
-             (var) = (prev_var))
-
-/*
- * Tail queue access methods.
- */
-#define QTAILQ_EMPTY(head)               ((head)->tqh_first == NULL)
-#define QTAILQ_FIRST(head)               ((head)->tqh_first)
-#define QTAILQ_NEXT(elm, field)          ((elm)->field.tqe_next)
-#define QTAILQ_IN_USE(elm, field)        ((elm)->field.tqe_circ.tql_prev != NULL)
-
-#define QTAILQ_LINK_PREV(link)                                          \
-        ((link).tql_prev->tql_prev->tql_next)
-#define QTAILQ_LAST(head)                                               \
-        ((typeof((head)->tqh_first)) QTAILQ_LINK_PREV((head)->tqh_circ))
-#define QTAILQ_PREV(elm, field)                                         \
-        ((typeof((elm)->field.tqe_next)) QTAILQ_LINK_PREV((elm)->field.tqe_circ))
-
-#define field_at_offset(base, offset, type)                                    \
-        ((type *) (((char *) (base)) + (offset)))
-
-/*
- * Raw access of elements of a tail queue head.  Offsets are all zero
- * because it's a union.
- */
-#define QTAILQ_RAW_FIRST(head)                                                 \
-        field_at_offset(head, 0, void *)
-#define QTAILQ_RAW_TQH_CIRC(head)                                              \
-        field_at_offset(head, 0, QTailQLink)
-
-/*
- * Raw access of elements of a tail entry
- */
-#define QTAILQ_RAW_NEXT(elm, entry)                                            \
-        field_at_offset(elm, entry, void *)
-#define QTAILQ_RAW_TQE_CIRC(elm, entry)                                        \
-        field_at_offset(elm, entry, QTailQLink)
-/*
- * Tail queue traversal using pointer arithmetic.
- */
-#define QTAILQ_RAW_FOREACH(elm, head, entry)                                   \
-        for ((elm) = *QTAILQ_RAW_FIRST(head);                                  \
-             (elm);                                                            \
-             (elm) = *QTAILQ_RAW_NEXT(elm, entry))
-/*
- * Tail queue insertion using pointer arithmetic.
- */
-#define QTAILQ_RAW_INSERT_TAIL(head, elm, entry) do {                           \
-        *QTAILQ_RAW_NEXT(elm, entry) = NULL;                                    \
-        QTAILQ_RAW_TQE_CIRC(elm, entry)->tql_prev = QTAILQ_RAW_TQH_CIRC(head)->tql_prev; \
-        QTAILQ_RAW_TQH_CIRC(head)->tql_prev->tql_next = (elm);                  \
-        QTAILQ_RAW_TQH_CIRC(head)->tql_prev = QTAILQ_RAW_TQE_CIRC(elm, entry);  \
-} while (/*CONSTCOND*/0)
-
-#endif /* QTAILQ_H */
diff --git a/slirp/sbuf.c b/slirp/sbuf.c
deleted file mode 100644 (file)
index 51a9f0c..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#include "slirp.h"
-
-static void sbappendsb(struct sbuf *sb, struct mbuf *m);
-
-void
-sbfree(struct sbuf *sb)
-{
-       free(sb->sb_data);
-}
-
-bool
-sbdrop(struct sbuf *sb, int num)
-{
-    int limit = sb->sb_datalen / 2;
-
-       /*
-        * We can only drop how much we have
-        * This should never succeed
-        */
-       if(num > sb->sb_cc)
-               num = sb->sb_cc;
-       sb->sb_cc -= num;
-       sb->sb_rptr += num;
-       if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen)
-               sb->sb_rptr -= sb->sb_datalen;
-
-    if (sb->sb_cc < limit && sb->sb_cc + num >= limit) {
-        return true;
-    }
-
-    return false;
-}
-
-void
-sbreserve(struct sbuf *sb, int size)
-{
-       if (sb->sb_data) {
-               /* Already alloced, realloc if necessary */
-               if (sb->sb_datalen != size) {
-                       sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size);
-                       sb->sb_cc = 0;
-                       if (sb->sb_wptr)
-                          sb->sb_datalen = size;
-                       else
-                          sb->sb_datalen = 0;
-               }
-       } else {
-               sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size);
-               sb->sb_cc = 0;
-               if (sb->sb_wptr)
-                  sb->sb_datalen = size;
-               else
-                  sb->sb_datalen = 0;
-       }
-}
-
-/*
- * Try and write() to the socket, whatever doesn't get written
- * append to the buffer... for a host with a fast net connection,
- * this prevents an unnecessary copy of the data
- * (the socket is non-blocking, so we won't hang)
- */
-void
-sbappend(struct socket *so, struct mbuf *m)
-{
-       int ret = 0;
-
-       DEBUG_CALL("sbappend");
-       DEBUG_ARG("so = %p", so);
-       DEBUG_ARG("m = %p", m);
-       DEBUG_ARG("m->m_len = %d", m->m_len);
-
-       /* Shouldn't happen, but...  e.g. foreign host closes connection */
-       if (m->m_len <= 0) {
-               m_free(m);
-               return;
-       }
-
-       /*
-        * If there is urgent data, call sosendoob
-        * if not all was sent, sowrite will take care of the rest
-        * (The rest of this function is just an optimisation)
-        */
-       if (so->so_urgc) {
-               sbappendsb(&so->so_rcv, m);
-               m_free(m);
-               (void)sosendoob(so);
-               return;
-       }
-
-       /*
-        * We only write if there's nothing in the buffer,
-        * ottherwise it'll arrive out of order, and hence corrupt
-        */
-       if (!so->so_rcv.sb_cc)
-          ret = slirp_send(so, m->m_data, m->m_len, 0);
-
-       if (ret <= 0) {
-               /*
-                * Nothing was written
-                * It's possible that the socket has closed, but
-                * we don't need to check because if it has closed,
-                * it will be detected in the normal way by soread()
-                */
-               sbappendsb(&so->so_rcv, m);
-       } else if (ret != m->m_len) {
-               /*
-                * Something was written, but not everything..
-                * sbappendsb the rest
-                */
-               m->m_len -= ret;
-               m->m_data += ret;
-               sbappendsb(&so->so_rcv, m);
-       } /* else */
-       /* Whatever happened, we free the mbuf */
-       m_free(m);
-}
-
-/*
- * Copy the data from m into sb
- * The caller is responsible to make sure there's enough room
- */
-static void
-sbappendsb(struct sbuf *sb, struct mbuf *m)
-{
-       int len, n,  nn;
-
-       len = m->m_len;
-
-       if (sb->sb_wptr < sb->sb_rptr) {
-               n = sb->sb_rptr - sb->sb_wptr;
-               if (n > len) n = len;
-               memcpy(sb->sb_wptr, m->m_data, n);
-       } else {
-               /* Do the right edge first */
-               n = sb->sb_data + sb->sb_datalen - sb->sb_wptr;
-               if (n > len) n = len;
-               memcpy(sb->sb_wptr, m->m_data, n);
-               len -= n;
-               if (len) {
-                       /* Now the left edge */
-                       nn = sb->sb_rptr - sb->sb_data;
-                       if (nn > len) nn = len;
-                       memcpy(sb->sb_data,m->m_data+n,nn);
-                       n += nn;
-               }
-       }
-
-       sb->sb_cc += n;
-       sb->sb_wptr += n;
-       if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen)
-               sb->sb_wptr -= sb->sb_datalen;
-}
-
-/*
- * Copy data from sbuf to a normal, straight buffer
- * Don't update the sbuf rptr, this will be
- * done in sbdrop when the data is acked
- */
-void
-sbcopy(struct sbuf *sb, int off, int len, char *to)
-{
-       char *from;
-
-       from = sb->sb_rptr + off;
-       if (from >= sb->sb_data + sb->sb_datalen)
-               from -= sb->sb_datalen;
-
-       if (from < sb->sb_wptr) {
-               if (len > sb->sb_cc) len = sb->sb_cc;
-               memcpy(to,from,len);
-       } else {
-               /* re-use off */
-               off = (sb->sb_data + sb->sb_datalen) - from;
-               if (off > len) off = len;
-               memcpy(to,from,off);
-               len -= off;
-               if (len)
-                  memcpy(to+off,sb->sb_data,len);
-       }
-}
diff --git a/slirp/sbuf.h b/slirp/sbuf.h
deleted file mode 100644 (file)
index 1cb9a42..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#ifndef SBUF_H
-#define SBUF_H
-
-#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc)
-
-struct sbuf {
-       uint32_t sb_cc;         /* actual chars in buffer */
-       uint32_t sb_datalen;    /* Length of data  */
-       char    *sb_wptr;       /* write pointer. points to where the next
-                                * bytes should be written in the sbuf */
-       char    *sb_rptr;       /* read pointer. points to where the next
-                                * byte should be read from the sbuf */
-       char    *sb_data;       /* Actual data */
-};
-
-void sbfree(struct sbuf *);
-bool sbdrop(struct sbuf *, int);
-void sbreserve(struct sbuf *, int);
-void sbappend(struct socket *, struct mbuf *);
-void sbcopy(struct sbuf *, int, int, char *);
-
-#endif
diff --git a/slirp/slirp.c b/slirp/slirp.c
deleted file mode 100644 (file)
index 5559143..0000000
+++ /dev/null
@@ -1,1121 +0,0 @@
-/*
- * libslirp glue
- *
- * Copyright (c) 2004-2008 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "slirp.h"
-
-#ifdef WITH_QEMU
-#include "state.h"
-#endif
-
-#ifndef _WIN32
-#include <net/if.h>
-#endif
-
-int slirp_debug;
-
-/* Define to 1 if you want KEEPALIVE timers */
-bool slirp_do_keepalive;
-
-/* host loopback address */
-struct in_addr loopback_addr;
-/* host loopback network mask */
-unsigned long loopback_mask;
-
-/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
-static const uint8_t special_ethaddr[ETH_ALEN] = {
-    0x52, 0x55, 0x00, 0x00, 0x00, 0x00
-};
-
-unsigned curtime;
-
-static struct in_addr dns_addr;
-#ifndef _WIN32
-static struct in6_addr dns6_addr;
-#endif
-static unsigned dns_addr_time;
-#ifndef _WIN32
-static unsigned dns6_addr_time;
-#endif
-
-#define TIMEOUT_FAST 2  /* milliseconds */
-#define TIMEOUT_SLOW 499  /* milliseconds */
-/* for the aging of certain requests like DNS */
-#define TIMEOUT_DEFAULT 1000  /* milliseconds */
-
-#ifdef _WIN32
-
-int get_dns_addr(struct in_addr *pdns_addr)
-{
-    FIXED_INFO *FixedInfo=NULL;
-    ULONG    BufLen;
-    DWORD    ret;
-    IP_ADDR_STRING *pIPAddr;
-    struct in_addr tmp_addr;
-
-    if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < TIMEOUT_DEFAULT) {
-        *pdns_addr = dns_addr;
-        return 0;
-    }
-
-    FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
-    BufLen = sizeof(FIXED_INFO);
-
-    if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
-        if (FixedInfo) {
-            GlobalFree(FixedInfo);
-            FixedInfo = NULL;
-        }
-        FixedInfo = GlobalAlloc(GPTR, BufLen);
-    }
-
-    if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
-        printf("GetNetworkParams failed. ret = %08x\n", (unsigned)ret );
-        if (FixedInfo) {
-            GlobalFree(FixedInfo);
-            FixedInfo = NULL;
-        }
-        return -1;
-    }
-
-    pIPAddr = &(FixedInfo->DnsServerList);
-    inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
-    *pdns_addr = tmp_addr;
-    dns_addr = tmp_addr;
-    dns_addr_time = curtime;
-    if (FixedInfo) {
-        GlobalFree(FixedInfo);
-        FixedInfo = NULL;
-    }
-    return 0;
-}
-
-int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id)
-{
-    return -1;
-}
-
-static void winsock_cleanup(void)
-{
-    WSACleanup();
-}
-
-#else
-
-static int get_dns_addr_cached(void *pdns_addr, void *cached_addr,
-                               socklen_t addrlen,
-                               struct stat *cached_stat, unsigned *cached_time)
-{
-    struct stat old_stat;
-    if (curtime - *cached_time < TIMEOUT_DEFAULT) {
-        memcpy(pdns_addr, cached_addr, addrlen);
-        return 0;
-    }
-    old_stat = *cached_stat;
-    if (stat("/etc/resolv.conf", cached_stat) != 0) {
-        return -1;
-    }
-    if (cached_stat->st_dev == old_stat.st_dev
-        && cached_stat->st_ino == old_stat.st_ino
-        && cached_stat->st_size == old_stat.st_size
-        && cached_stat->st_mtime == old_stat.st_mtime) {
-        memcpy(pdns_addr, cached_addr, addrlen);
-        return 0;
-    }
-    return 1;
-}
-
-static int get_dns_addr_resolv_conf(int af, void *pdns_addr, void *cached_addr,
-                                    socklen_t addrlen, uint32_t *scope_id,
-                                    unsigned *cached_time)
-{
-    char buff[512];
-    char buff2[257];
-    FILE *f;
-    int found = 0;
-    void *tmp_addr = alloca(addrlen);
-    unsigned if_index;
-
-    f = fopen("/etc/resolv.conf", "r");
-    if (!f)
-        return -1;
-
-    DEBUG_MISC("IP address of your DNS(s):");
-    while (fgets(buff, 512, f) != NULL) {
-        if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
-            char *c = strchr(buff2, '%');
-            if (c) {
-                if_index = if_nametoindex(c + 1);
-                *c = '\0';
-            } else {
-                if_index = 0;
-            }
-
-            if (!inet_pton(af, buff2, tmp_addr)) {
-                continue;
-            }
-            /* If it's the first one, set it to dns_addr */
-            if (!found) {
-                memcpy(pdns_addr, tmp_addr, addrlen);
-                memcpy(cached_addr, tmp_addr, addrlen);
-                if (scope_id) {
-                    *scope_id = if_index;
-                }
-                *cached_time = curtime;
-            }
-
-            if (++found > 3) {
-                DEBUG_MISC("  (more)");
-                break;
-            } else if (slirp_debug & DBG_MISC) {
-                char s[INET6_ADDRSTRLEN];
-                const char *res = inet_ntop(af, tmp_addr, s, sizeof(s));
-                if (!res) {
-                    res = "  (string conversion error)";
-                }
-                DEBUG_MISC("  %s", res);
-            }
-        }
-    }
-    fclose(f);
-    if (!found)
-        return -1;
-    return 0;
-}
-
-int get_dns_addr(struct in_addr *pdns_addr)
-{
-    static struct stat dns_addr_stat;
-
-    if (dns_addr.s_addr != 0) {
-        int ret;
-        ret = get_dns_addr_cached(pdns_addr, &dns_addr, sizeof(dns_addr),
-                                  &dns_addr_stat, &dns_addr_time);
-        if (ret <= 0) {
-            return ret;
-        }
-    }
-    return get_dns_addr_resolv_conf(AF_INET, pdns_addr, &dns_addr,
-                                    sizeof(dns_addr), NULL, &dns_addr_time);
-}
-
-int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id)
-{
-    static struct stat dns6_addr_stat;
-
-    if (!in6_zero(&dns6_addr)) {
-        int ret;
-        ret = get_dns_addr_cached(pdns6_addr, &dns6_addr, sizeof(dns6_addr),
-                                  &dns6_addr_stat, &dns6_addr_time);
-        if (ret <= 0) {
-            return ret;
-        }
-    }
-    return get_dns_addr_resolv_conf(AF_INET6, pdns6_addr, &dns6_addr,
-                                    sizeof(dns6_addr),
-                                    scope_id, &dns6_addr_time);
-}
-
-#endif
-
-static void slirp_init_once(void)
-{
-    static int initialized;
-    const char *debug;
-#ifdef _WIN32
-    WSADATA Data;
-#endif
-
-    if (initialized) {
-        return;
-    }
-    initialized = 1;
-
-#ifdef _WIN32
-    WSAStartup(MAKEWORD(2,0), &Data);
-    atexit(winsock_cleanup);
-#endif
-
-    loopback_addr.s_addr = htonl(INADDR_LOOPBACK);
-    loopback_mask = htonl(IN_CLASSA_NET);
-
-    debug = g_getenv("SLIRP_DEBUG");
-    if (debug) {
-        const GDebugKey keys[] = {
-            { "call", DBG_CALL },
-            { "misc", DBG_MISC },
-            { "error", DBG_ERROR },
-            { "tftp", DBG_TFTP },
-        };
-        slirp_debug = g_parse_debug_string(debug, keys, G_N_ELEMENTS(keys));
-    }
-
-
-}
-
-Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
-                  struct in_addr vnetmask, struct in_addr vhost,
-                  bool in6_enabled,
-                  struct in6_addr vprefix_addr6, uint8_t vprefix_len,
-                  struct in6_addr vhost6, const char *vhostname,
-                  const char *tftp_server_name,
-                  const char *tftp_path, const char *bootfile,
-                  struct in_addr vdhcp_start, struct in_addr vnameserver,
-                  struct in6_addr vnameserver6, const char **vdnssearch,
-                  const char *vdomainname,
-                  const SlirpCb *callbacks,
-                  void *opaque)
-{
-    Slirp *slirp = g_malloc0(sizeof(Slirp));
-
-    slirp_init_once();
-
-    slirp->opaque = opaque;
-    slirp->cb = callbacks;
-    slirp->grand = g_rand_new();
-    slirp->restricted = restricted;
-
-    slirp->in_enabled = in_enabled;
-    slirp->in6_enabled = in6_enabled;
-
-    if_init(slirp);
-    ip_init(slirp);
-    ip6_init(slirp);
-
-    /* Initialise mbufs *after* setting the MTU */
-    m_init(slirp);
-
-    slirp->vnetwork_addr = vnetwork;
-    slirp->vnetwork_mask = vnetmask;
-    slirp->vhost_addr = vhost;
-    slirp->vprefix_addr6 = vprefix_addr6;
-    slirp->vprefix_len = vprefix_len;
-    slirp->vhost_addr6 = vhost6;
-    if (vhostname) {
-        slirp_pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
-                      vhostname);
-    }
-    slirp->tftp_prefix = g_strdup(tftp_path);
-    slirp->bootp_filename = g_strdup(bootfile);
-    slirp->vdomainname = g_strdup(vdomainname);
-    slirp->vdhcp_startaddr = vdhcp_start;
-    slirp->vnameserver_addr = vnameserver;
-    slirp->vnameserver_addr6 = vnameserver6;
-    slirp->tftp_server_name = g_strdup(tftp_server_name);
-
-    if (vdnssearch) {
-        translate_dnssearch(slirp, vdnssearch);
-    }
-
-#ifdef WITH_QEMU
-    slirp_state_register(slirp);
-#endif
-    return slirp;
-}
-
-void slirp_cleanup(Slirp *slirp)
-{
-    struct gfwd_list *e, *next;
-
-    for (e = slirp->guestfwd_list; e; e = next) {
-        next = e->ex_next;
-        g_free(e->ex_exec);
-        g_free(e);
-    }
-
-#ifdef WITH_QEMU
-    slirp_state_unregister(slirp);
-#endif
-    ip_cleanup(slirp);
-    ip6_cleanup(slirp);
-    m_cleanup(slirp);
-
-    g_rand_free(slirp->grand);
-
-    g_free(slirp->vdnssearch);
-    g_free(slirp->tftp_prefix);
-    g_free(slirp->bootp_filename);
-    g_free(slirp->vdomainname);
-    g_free(slirp);
-}
-
-#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
-#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
-
-static void slirp_update_timeout(Slirp *slirp, uint32_t *timeout)
-{
-    uint32_t t;
-
-    if (*timeout <= TIMEOUT_FAST) {
-        return;
-    }
-
-    t = MIN(1000, *timeout);
-
-    /* If we have tcp timeout with slirp, then we will fill @timeout with
-     * more precise value.
-     */
-    if (slirp->time_fasttimo) {
-        *timeout = TIMEOUT_FAST;
-        return;
-    }
-    if (slirp->do_slowtimo) {
-        t = MIN(TIMEOUT_SLOW, t);
-    }
-    *timeout = t;
-}
-
-void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
-                        SlirpAddPollCb add_poll, void *opaque)
-{
-    struct socket *so, *so_next;
-
-    /*
-     * First, TCP sockets
-     */
-
-    /*
-     * *_slowtimo needs calling if there are IP fragments
-     * in the fragment queue, or there are TCP connections active
-     */
-    slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) ||
-                          (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
-
-    for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) {
-        int events = 0;
-
-        so_next = so->so_next;
-
-        so->pollfds_idx = -1;
-
-        /*
-         * See if we need a tcp_fasttimo
-         */
-        if (slirp->time_fasttimo == 0 &&
-            so->so_tcpcb->t_flags & TF_DELACK) {
-            slirp->time_fasttimo = curtime; /* Flag when want a fasttimo */
-        }
-
-        /*
-         * NOFDREF can include still connecting to local-host,
-         * newly socreated() sockets etc. Don't want to select these.
-         */
-        if (so->so_state & SS_NOFDREF || so->s == -1) {
-            continue;
-        }
-
-        /*
-         * Set for reading sockets which are accepting
-         */
-        if (so->so_state & SS_FACCEPTCONN) {
-            so->pollfds_idx = add_poll(so->s,
-                SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
-            continue;
-        }
-
-        /*
-         * Set for writing sockets which are connecting
-         */
-        if (so->so_state & SS_ISFCONNECTING) {
-            so->pollfds_idx = add_poll(so->s,
-                SLIRP_POLL_OUT | SLIRP_POLL_ERR, opaque);
-            continue;
-        }
-
-        /*
-         * Set for writing if we are connected, can send more, and
-         * we have something to send
-         */
-        if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
-            events |= SLIRP_POLL_OUT | SLIRP_POLL_ERR;
-        }
-
-        /*
-         * Set for reading (and urgent data) if we are connected, can
-         * receive more, and we have room for it XXX /2 ?
-         */
-        if (CONN_CANFRCV(so) &&
-            (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
-            events |= SLIRP_POLL_IN | SLIRP_POLL_HUP |
-                      SLIRP_POLL_ERR | SLIRP_POLL_PRI;
-        }
-
-        if (events) {
-            so->pollfds_idx = add_poll(so->s, events, opaque);
-        }
-    }
-
-    /*
-     * UDP sockets
-     */
-    for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) {
-        so_next = so->so_next;
-
-        so->pollfds_idx = -1;
-
-        /*
-         * See if it's timed out
-         */
-        if (so->so_expire) {
-            if (so->so_expire <= curtime) {
-                udp_detach(so);
-                continue;
-            } else {
-                slirp->do_slowtimo = true; /* Let socket expire */
-            }
-        }
-
-        /*
-         * When UDP packets are received from over the
-         * link, they're sendto()'d straight away, so
-         * no need for setting for writing
-         * Limit the number of packets queued by this session
-         * to 4.  Note that even though we try and limit this
-         * to 4 packets, the session could have more queued
-         * if the packets needed to be fragmented
-         * (XXX <= 4 ?)
-         */
-        if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
-            so->pollfds_idx = add_poll(so->s,
-                SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
-        }
-    }
-
-    /*
-     * ICMP sockets
-     */
-    for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) {
-        so_next = so->so_next;
-
-        so->pollfds_idx = -1;
-
-        /*
-         * See if it's timed out
-         */
-        if (so->so_expire) {
-            if (so->so_expire <= curtime) {
-                icmp_detach(so);
-                continue;
-            } else {
-                slirp->do_slowtimo = true; /* Let socket expire */
-            }
-        }
-
-        if (so->so_state & SS_ISFCONNECTED) {
-            so->pollfds_idx = add_poll(so->s,
-                SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
-        }
-    }
-
-    slirp_update_timeout(slirp, timeout);
-}
-
-void slirp_pollfds_poll(Slirp *slirp, int select_error,
-                        SlirpGetREventsCb get_revents, void *opaque)
-{
-    struct socket *so, *so_next;
-    int ret;
-
-    curtime = slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS;
-
-    /*
-     * See if anything has timed out
-     */
-    if (slirp->time_fasttimo &&
-        ((curtime - slirp->time_fasttimo) >= TIMEOUT_FAST)) {
-        tcp_fasttimo(slirp);
-        slirp->time_fasttimo = 0;
-    }
-    if (slirp->do_slowtimo &&
-        ((curtime - slirp->last_slowtimo) >= TIMEOUT_SLOW)) {
-        ip_slowtimo(slirp);
-        tcp_slowtimo(slirp);
-        slirp->last_slowtimo = curtime;
-    }
-
-    /*
-     * Check sockets
-     */
-    if (!select_error) {
-        /*
-         * Check TCP sockets
-         */
-        for (so = slirp->tcb.so_next; so != &slirp->tcb;
-             so = so_next) {
-            int revents;
-
-            so_next = so->so_next;
-
-            revents = 0;
-            if (so->pollfds_idx != -1) {
-                revents = get_revents(so->pollfds_idx, opaque);
-            }
-
-            if (so->so_state & SS_NOFDREF || so->s == -1) {
-                continue;
-            }
-
-            /*
-             * Check for URG data
-             * This will soread as well, so no need to
-             * test for SLIRP_POLL_IN below if this succeeds
-             */
-            if (revents & SLIRP_POLL_PRI) {
-                ret = sorecvoob(so);
-                if (ret < 0) {
-                    /* Socket error might have resulted in the socket being
-                     * removed, do not try to do anything more with it. */
-                    continue;
-                }
-            }
-            /*
-             * Check sockets for reading
-             */
-            else if (revents &
-                     (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR)) {
-                /*
-                 * Check for incoming connections
-                 */
-                if (so->so_state & SS_FACCEPTCONN) {
-                    tcp_connect(so);
-                    continue;
-                } /* else */
-                ret = soread(so);
-
-                /* Output it if we read something */
-                if (ret > 0) {
-                    tcp_output(sototcpcb(so));
-                }
-                if (ret < 0) {
-                    /* Socket error might have resulted in the socket being
-                     * removed, do not try to do anything more with it. */
-                    continue;
-                }
-            }
-
-            /*
-             * Check sockets for writing
-             */
-            if (!(so->so_state & SS_NOFDREF) &&
-                (revents & (SLIRP_POLL_OUT | SLIRP_POLL_ERR))) {
-                /*
-                 * Check for non-blocking, still-connecting sockets
-                 */
-                if (so->so_state & SS_ISFCONNECTING) {
-                    /* Connected */
-                    so->so_state &= ~SS_ISFCONNECTING;
-
-                    ret = send(so->s, (const void *) &ret, 0, 0);
-                    if (ret < 0) {
-                        /* XXXXX Must fix, zero bytes is a NOP */
-                        if (errno == EAGAIN || errno == EWOULDBLOCK ||
-                            errno == EINPROGRESS || errno == ENOTCONN) {
-                            continue;
-                        }
-
-                        /* else failed */
-                        so->so_state &= SS_PERSISTENT_MASK;
-                        so->so_state |= SS_NOFDREF;
-                    }
-                    /* else so->so_state &= ~SS_ISFCONNECTING; */
-
-                    /*
-                     * Continue tcp_input
-                     */
-                    tcp_input((struct mbuf *)NULL, sizeof(struct ip), so,
-                              so->so_ffamily);
-                    /* continue; */
-                } else {
-                    ret = sowrite(so);
-                    if (ret > 0) {
-                        /* Call tcp_output in case we need to send a window
-                         * update to the guest, otherwise it will be stuck
-                         * until it sends a window probe. */
-                        tcp_output(sototcpcb(so));
-                    }
-                }
-            }
-        }
-
-        /*
-         * Now UDP sockets.
-         * Incoming packets are sent straight away, they're not buffered.
-         * Incoming UDP data isn't buffered either.
-         */
-        for (so = slirp->udb.so_next; so != &slirp->udb;
-             so = so_next) {
-            int revents;
-
-            so_next = so->so_next;
-
-            revents = 0;
-            if (so->pollfds_idx != -1) {
-                revents = get_revents(so->pollfds_idx, opaque);
-            }
-
-            if (so->s != -1 &&
-                (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) {
-                sorecvfrom(so);
-            }
-        }
-
-        /*
-         * Check incoming ICMP relies.
-         */
-        for (so = slirp->icmp.so_next; so != &slirp->icmp;
-             so = so_next) {
-            int revents;
-
-            so_next = so->so_next;
-
-            revents = 0;
-            if (so->pollfds_idx != -1) {
-                revents = get_revents(so->pollfds_idx, opaque);
-            }
-
-            if (so->s != -1 &&
-                (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) {
-                icmp_receive(so);
-            }
-        }
-    }
-
-    if_start(slirp);
-}
-
-static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
-{
-    struct slirp_arphdr *ah = (struct slirp_arphdr *)(pkt + ETH_HLEN);
-    uint8_t arp_reply[MAX(ETH_HLEN + sizeof(struct slirp_arphdr), 64)];
-    struct ethhdr *reh = (struct ethhdr *)arp_reply;
-    struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_reply + ETH_HLEN);
-    int ar_op;
-    struct gfwd_list *ex_ptr;
-
-    if (!slirp->in_enabled) {
-        return;
-    }
-
-    ar_op = ntohs(ah->ar_op);
-    switch(ar_op) {
-    case ARPOP_REQUEST:
-        if (ah->ar_tip == ah->ar_sip) {
-            /* Gratuitous ARP */
-            arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
-            return;
-        }
-
-        if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) ==
-            slirp->vnetwork_addr.s_addr) {
-            if (ah->ar_tip == slirp->vnameserver_addr.s_addr ||
-                ah->ar_tip == slirp->vhost_addr.s_addr)
-                goto arp_ok;
-            for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
-                if (ex_ptr->ex_addr.s_addr == ah->ar_tip)
-                    goto arp_ok;
-            }
-            return;
-        arp_ok:
-            memset(arp_reply, 0, sizeof(arp_reply));
-
-            arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
-
-            /* ARP request for alias/dns mac address */
-            memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
-            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
-            memcpy(&reh->h_source[2], &ah->ar_tip, 4);
-            reh->h_proto = htons(ETH_P_ARP);
-
-            rah->ar_hrd = htons(1);
-            rah->ar_pro = htons(ETH_P_IP);
-            rah->ar_hln = ETH_ALEN;
-            rah->ar_pln = 4;
-            rah->ar_op = htons(ARPOP_REPLY);
-            memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
-            rah->ar_sip = ah->ar_tip;
-            memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
-            rah->ar_tip = ah->ar_sip;
-            slirp_send_packet_all(slirp, arp_reply, sizeof(arp_reply));
-        }
-        break;
-    case ARPOP_REPLY:
-        arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
-        break;
-    default:
-        break;
-    }
-}
-
-void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
-{
-    struct mbuf *m;
-    int proto;
-
-    if (pkt_len < ETH_HLEN)
-        return;
-
-    proto = (((uint16_t) pkt[12]) << 8) + pkt[13];
-    switch(proto) {
-    case ETH_P_ARP:
-        arp_input(slirp, pkt, pkt_len);
-        break;
-    case ETH_P_IP:
-    case ETH_P_IPV6:
-        m = m_get(slirp);
-        if (!m)
-            return;
-        /* Note: we add 2 to align the IP header on 4 bytes,
-         * and add the margin for the tcpiphdr overhead  */
-        if (M_FREEROOM(m) < pkt_len + TCPIPHDR_DELTA + 2) {
-            m_inc(m, pkt_len + TCPIPHDR_DELTA + 2);
-        }
-        m->m_len = pkt_len + TCPIPHDR_DELTA + 2;
-        memcpy(m->m_data + TCPIPHDR_DELTA + 2, pkt, pkt_len);
-
-        m->m_data += TCPIPHDR_DELTA + 2 + ETH_HLEN;
-        m->m_len -= TCPIPHDR_DELTA + 2 + ETH_HLEN;
-
-        if (proto == ETH_P_IP) {
-            ip_input(m);
-        } else if (proto == ETH_P_IPV6) {
-            ip6_input(m);
-        }
-        break;
-
-    case ETH_P_NCSI:
-        ncsi_input(slirp, pkt, pkt_len);
-        break;
-
-    default:
-        break;
-    }
-}
-
-/* Prepare the IPv4 packet to be sent to the ethernet device. Returns 1 if no
- * packet should be sent, 0 if the packet must be re-queued, 2 if the packet
- * is ready to go.
- */
-static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
-        uint8_t ethaddr[ETH_ALEN])
-{
-    const struct ip *iph = (const struct ip *)ifm->m_data;
-
-    if (iph->ip_dst.s_addr == 0) {
-        /* 0.0.0.0 can not be a destination address, something went wrong,
-         * avoid making it worse */
-        return 1;
-    }
-    if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
-        uint8_t arp_req[ETH_HLEN + sizeof(struct slirp_arphdr)];
-        struct ethhdr *reh = (struct ethhdr *)arp_req;
-        struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_req + ETH_HLEN);
-
-        if (!ifm->resolution_requested) {
-            /* If the client addr is not known, send an ARP request */
-            memset(reh->h_dest, 0xff, ETH_ALEN);
-            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
-            memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
-            reh->h_proto = htons(ETH_P_ARP);
-            rah->ar_hrd = htons(1);
-            rah->ar_pro = htons(ETH_P_IP);
-            rah->ar_hln = ETH_ALEN;
-            rah->ar_pln = 4;
-            rah->ar_op = htons(ARPOP_REQUEST);
-
-            /* source hw addr */
-            memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
-            memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);
-
-            /* source IP */
-            rah->ar_sip = slirp->vhost_addr.s_addr;
-
-            /* target hw addr (none) */
-            memset(rah->ar_tha, 0, ETH_ALEN);
-
-            /* target IP */
-            rah->ar_tip = iph->ip_dst.s_addr;
-            slirp->client_ipaddr = iph->ip_dst;
-            slirp_send_packet_all(slirp, arp_req, sizeof(arp_req));
-            ifm->resolution_requested = true;
-
-            /* Expire request and drop outgoing packet after 1 second */
-            ifm->expiration_date =
-                slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL;
-        }
-        return 0;
-    } else {
-        memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
-        /* XXX: not correct */
-        memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
-        eh->h_proto = htons(ETH_P_IP);
-
-        /* Send this */
-        return 2;
-    }
-}
-
-/* Prepare the IPv6 packet to be sent to the ethernet device. Returns 1 if no
- * packet should be sent, 0 if the packet must be re-queued, 2 if the packet
- * is ready to go.
- */
-static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
-        uint8_t ethaddr[ETH_ALEN])
-{
-    const struct ip6 *ip6h = mtod(ifm, const struct ip6 *);
-    if (!ndp_table_search(slirp, ip6h->ip_dst, ethaddr)) {
-        if (!ifm->resolution_requested) {
-            ndp_send_ns(slirp, ip6h->ip_dst);
-            ifm->resolution_requested = true;
-            ifm->expiration_date = slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL;
-        }
-        return 0;
-    } else {
-        eh->h_proto = htons(ETH_P_IPV6);
-        in6_compute_ethaddr(ip6h->ip_src, eh->h_source);
-
-        /* Send this */
-        return 2;
-    }
-}
-
-/* Output the IP packet to the ethernet device. Returns 0 if the packet must be
- * re-queued.
- */
-int if_encap(Slirp *slirp, struct mbuf *ifm)
-{
-    uint8_t buf[1600];
-    struct ethhdr *eh = (struct ethhdr *)buf;
-    uint8_t ethaddr[ETH_ALEN];
-    const struct ip *iph = (const struct ip *)ifm->m_data;
-    int ret;
-
-    if (ifm->m_len + ETH_HLEN > sizeof(buf)) {
-        return 1;
-    }
-
-    switch (iph->ip_v) {
-    case IPVERSION:
-        ret = if_encap4(slirp, ifm, eh, ethaddr);
-        if (ret < 2) {
-            return ret;
-        }
-        break;
-
-    case IP6VERSION:
-        ret = if_encap6(slirp, ifm, eh, ethaddr);
-        if (ret < 2) {
-            return ret;
-        }
-        break;
-
-    default:
-        g_assert_not_reached();
-        break;
-    }
-
-    memcpy(eh->h_dest, ethaddr, ETH_ALEN);
-    DEBUG_ARG("src = %02x:%02x:%02x:%02x:%02x:%02x",
-              eh->h_source[0], eh->h_source[1], eh->h_source[2],
-              eh->h_source[3], eh->h_source[4], eh->h_source[5]);
-    DEBUG_ARG("dst = %02x:%02x:%02x:%02x:%02x:%02x",
-              eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
-              eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]);
-    memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
-    slirp_send_packet_all(slirp, buf, ifm->m_len + ETH_HLEN);
-    return 1;
-}
-
-/* Drop host forwarding rule, return 0 if found. */
-int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
-                         int host_port)
-{
-    struct socket *so;
-    struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb);
-    struct sockaddr_in addr;
-    int port = htons(host_port);
-    socklen_t addr_len;
-
-    for (so = head->so_next; so != head; so = so->so_next) {
-        addr_len = sizeof(addr);
-        if ((so->so_state & SS_HOSTFWD) &&
-            getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
-            addr.sin_addr.s_addr == host_addr.s_addr &&
-            addr.sin_port == port) {
-            so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
-            closesocket(so->s);
-            sofree(so);
-            return 0;
-        }
-    }
-
-    return -1;
-}
-
-int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
-                      int host_port, struct in_addr guest_addr, int guest_port)
-{
-    if (!guest_addr.s_addr) {
-        guest_addr = slirp->vdhcp_startaddr;
-    }
-    if (is_udp) {
-        if (!udp_listen(slirp, host_addr.s_addr, htons(host_port),
-                        guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
-            return -1;
-    } else {
-        if (!tcp_listen(slirp, host_addr.s_addr, htons(host_port),
-                        guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
-            return -1;
-    }
-    return 0;
-}
-
-static bool
-check_guestfwd(Slirp *slirp, struct in_addr *guest_addr, int guest_port)
-{
-    struct gfwd_list *tmp_ptr;
-
-    if (!guest_addr->s_addr) {
-        guest_addr->s_addr = slirp->vnetwork_addr.s_addr |
-            (htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
-    }
-    if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) !=
-        slirp->vnetwork_addr.s_addr ||
-        guest_addr->s_addr == slirp->vhost_addr.s_addr ||
-        guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
-        return false;
-    }
-
-    /* check if the port is "bound" */
-    for (tmp_ptr = slirp->guestfwd_list; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
-        if (guest_port == tmp_ptr->ex_fport &&
-            guest_addr->s_addr == tmp_ptr->ex_addr.s_addr)
-            return false;
-    }
-
-    return true;
-}
-
-int slirp_add_exec(Slirp *slirp, const char *cmdline,
-                   struct in_addr *guest_addr, int guest_port)
-{
-    if (!check_guestfwd(slirp, guest_addr, guest_port)) {
-        return -1;
-    }
-
-    add_exec(&slirp->guestfwd_list, cmdline, *guest_addr, htons(guest_port));
-    return 0;
-}
-
-int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
-                       struct in_addr *guest_addr, int guest_port)
-{
-    if (!check_guestfwd(slirp, guest_addr, guest_port)) {
-        return -1;
-    }
-
-    add_guestfwd(&slirp->guestfwd_list, write_cb, opaque,
-                 *guest_addr, htons(guest_port));
-    return 0;
-}
-
-ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
-{
-    if (so->s == -1 && so->guestfwd) {
-        /* XXX this blocks entire thread. Rewrite to use
-         * qemu_chr_fe_write and background I/O callbacks */
-        so->guestfwd->write_cb(buf, len, so->guestfwd->opaque);
-        return len;
-    }
-
-    if (so->s == -1) {
-        /*
-         * This should in theory not happen but it is hard to be
-         * sure because some code paths will end up with so->s == -1
-         * on a failure but don't dispose of the struct socket.
-         * Check specifically, so we don't pass -1 to send().
-         */
-        errno = EBADF;
-        return -1;
-    }
-
-    return send(so->s, buf, len, flags);
-}
-
-struct socket *
-slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port)
-{
-    struct socket *so;
-
-    for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
-        if (so->so_faddr.s_addr == guest_addr.s_addr &&
-            htons(so->so_fport) == guest_port) {
-            return so;
-        }
-    }
-    return NULL;
-}
-
-size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
-                             int guest_port)
-{
-    struct iovec iov[2];
-    struct socket *so;
-
-    so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
-
-    if (!so || so->so_state & SS_NOFDREF) {
-        return 0;
-    }
-
-    if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2)) {
-        return 0;
-    }
-
-    return sopreprbuf(so, iov, NULL);
-}
-
-void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
-                       const uint8_t *buf, int size)
-{
-    int ret;
-    struct socket *so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
-
-    if (!so)
-        return;
-
-    ret = soreadbuf(so, (const char *)buf, size);
-
-    if (ret > 0)
-        tcp_output(sototcpcb(so));
-}
-
-void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len)
-{
-    ssize_t ret = slirp->cb->send_packet(buf, len, slirp->opaque);
-
-    if (ret < 0) {
-        g_critical("Failed to send packet, ret: %ld", (long) ret);
-    } else if (ret < len) {
-        DEBUG_ERROR("send_packet() didn't send all data: %ld < %lu",
-                (long) ret, (unsigned long) len);
-    }
-}
diff --git a/slirp/slirp.h b/slirp/slirp.h
deleted file mode 100644 (file)
index 752a4cd..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-#ifndef SLIRP_H
-#define SLIRP_H
-
-#ifdef _WIN32
-
-/* as defined in sdkddkver.h */
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0600 /* Vista */
-#endif
-/* reduces the number of implicitly included headers */
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif
-
-# include <winsock2.h>
-# include <windows.h>
-# include <ws2tcpip.h>
-# include <sys/timeb.h>
-# include <iphlpapi.h>
-
-#else
-# if !defined(__HAIKU__)
-#  define O_BINARY 0
-# endif
-#endif
-
-#ifndef _WIN32
-#include <sys/uio.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#endif
-
-#ifdef __APPLE__
-# include <sys/filio.h>
-#endif
-
-/* Avoid conflicting with the libc insque() and remque(), which
-   have different prototypes. */
-#define insque slirp_insque
-#define remque slirp_remque
-#define quehead slirp_quehead
-
-#include "debug.h"
-#include "util.h"
-#include "qtailq.h"
-
-#include "libslirp.h"
-#include "ip.h"
-#include "ip6.h"
-#include "tcp.h"
-#include "tcp_timer.h"
-#include "tcp_var.h"
-#include "tcpip.h"
-#include "udp.h"
-#include "ip_icmp.h"
-#include "ip6_icmp.h"
-#include "mbuf.h"
-#include "sbuf.h"
-#include "socket.h"
-#include "if.h"
-#include "main.h"
-#include "misc.h"
-
-#include "bootp.h"
-#include "tftp.h"
-
-#define ARPOP_REQUEST 1         /* ARP request */
-#define ARPOP_REPLY   2         /* ARP reply   */
-
-struct ethhdr {
-    unsigned char  h_dest[ETH_ALEN];   /* destination eth addr */
-    unsigned char  h_source[ETH_ALEN]; /* source ether addr    */
-    unsigned short h_proto;            /* packet type ID field */
-};
-
-struct slirp_arphdr {
-    unsigned short ar_hrd;      /* format of hardware address */
-    unsigned short ar_pro;      /* format of protocol address */
-    unsigned char  ar_hln;      /* length of hardware address */
-    unsigned char  ar_pln;      /* length of protocol address */
-    unsigned short ar_op;       /* ARP opcode (command)       */
-
-    /*
-     *  Ethernet looks like this : This bit is variable sized however...
-     */
-    unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
-    uint32_t      ar_sip;           /* sender IP address       */
-    unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
-    uint32_t      ar_tip;           /* target IP address       */
-} SLIRP_PACKED;
-
-#define ARP_TABLE_SIZE 16
-
-typedef struct ArpTable {
-    struct slirp_arphdr table[ARP_TABLE_SIZE];
-    int next_victim;
-} ArpTable;
-
-void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN]);
-
-bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
-                      uint8_t out_ethaddr[ETH_ALEN]);
-
-struct ndpentry {
-    unsigned char   eth_addr[ETH_ALEN];     /* sender hardware address */
-    struct in6_addr ip_addr;                /* sender IP address       */
-} SLIRP_PACKED;
-
-#define NDP_TABLE_SIZE 16
-
-typedef struct NdpTable {
-    struct ndpentry table[NDP_TABLE_SIZE];
-    int next_victim;
-} NdpTable;
-
-void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
-                   uint8_t ethaddr[ETH_ALEN]);
-bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
-                      uint8_t out_ethaddr[ETH_ALEN]);
-
-struct Slirp {
-    QTAILQ_ENTRY(Slirp) entry;
-    unsigned time_fasttimo;
-    unsigned last_slowtimo;
-    bool do_slowtimo;
-
-    bool in_enabled, in6_enabled;
-
-    /* virtual network configuration */
-    struct in_addr vnetwork_addr;
-    struct in_addr vnetwork_mask;
-    struct in_addr vhost_addr;
-    struct in6_addr vprefix_addr6;
-    uint8_t vprefix_len;
-    struct in6_addr vhost_addr6;
-    struct in_addr vdhcp_startaddr;
-    struct in_addr vnameserver_addr;
-    struct in6_addr vnameserver_addr6;
-
-    struct in_addr client_ipaddr;
-    char client_hostname[33];
-
-    int restricted;
-    struct gfwd_list *guestfwd_list;
-
-    /* mbuf states */
-    struct quehead m_freelist;
-    struct quehead m_usedlist;
-    int mbuf_alloced;
-
-    /* if states */
-    struct quehead if_fastq;   /* fast queue (for interactive data) */
-    struct quehead if_batchq;  /* queue for non-interactive data */
-    bool if_start_busy;     /* avoid if_start recursion */
-
-    /* ip states */
-    struct ipq ipq;         /* ip reass. queue */
-    uint16_t ip_id;         /* ip packet ctr, for ids */
-
-    /* bootp/dhcp states */
-    BOOTPClient bootp_clients[NB_BOOTP_CLIENTS];
-    char *bootp_filename;
-    size_t vdnssearch_len;
-    uint8_t *vdnssearch;
-    char *vdomainname;
-
-    /* tcp states */
-    struct socket tcb;
-    struct socket *tcp_last_so;
-    tcp_seq tcp_iss;        /* tcp initial send seq # */
-    uint32_t tcp_now;       /* for RFC 1323 timestamps */
-
-    /* udp states */
-    struct socket udb;
-    struct socket *udp_last_so;
-
-    /* icmp states */
-    struct socket icmp;
-    struct socket *icmp_last_so;
-
-    /* tftp states */
-    char *tftp_prefix;
-    struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
-    char *tftp_server_name;
-
-    ArpTable arp_table;
-    NdpTable ndp_table;
-
-    GRand *grand;
-    void *ra_timer;
-
-    const SlirpCb *cb;
-    void *opaque;
-};
-
-void if_start(Slirp *);
-
-int get_dns_addr(struct in_addr *pdns_addr);
-int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id);
-
-/* ncsi.c */
-void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
-
-#ifndef _WIN32
-#include <netdb.h>
-#endif
-
-
-extern bool slirp_do_keepalive;
-
-#define TCP_MAXIDLE (TCPTV_KEEPCNT * TCPTV_KEEPINTVL)
-
-/* dnssearch.c */
-int translate_dnssearch(Slirp *s, const char ** names);
-
-/* cksum.c */
-int cksum(struct mbuf *m, int len);
-int ip6_cksum(struct mbuf *m);
-
-/* if.c */
-void if_init(Slirp *);
-void if_output(struct socket *, struct mbuf *);
-
-/* ip_input.c */
-void ip_init(Slirp *);
-void ip_cleanup(Slirp *);
-void ip_input(struct mbuf *);
-void ip_slowtimo(Slirp *);
-void ip_stripoptions(register struct mbuf *, struct mbuf *);
-
-/* ip_output.c */
-int ip_output(struct socket *, struct mbuf *);
-
-/* ip6_input.c */
-void ip6_init(Slirp *);
-void ip6_cleanup(Slirp *);
-void ip6_input(struct mbuf *);
-
-/* ip6_output */
-int ip6_output(struct socket *, struct mbuf *, int fast);
-
-/* tcp_input.c */
-void tcp_input(register struct mbuf *, int, struct socket *, unsigned short af);
-int tcp_mss(register struct tcpcb *, unsigned);
-
-/* tcp_output.c */
-int tcp_output(register struct tcpcb *);
-void tcp_setpersist(register struct tcpcb *);
-
-/* tcp_subr.c */
-void tcp_init(Slirp *);
-void tcp_cleanup(Slirp *);
-void tcp_template(struct tcpcb *);
-void tcp_respond(struct tcpcb *, register struct tcpiphdr *,
-        register struct mbuf *, tcp_seq, tcp_seq, int, unsigned short);
-struct tcpcb * tcp_newtcpcb(struct socket *);
-struct tcpcb * tcp_close(register struct tcpcb *);
-void tcp_sockclosed(struct tcpcb *);
-int tcp_fconnect(struct socket *, unsigned short af);
-void tcp_connect(struct socket *);
-int tcp_attach(struct socket *);
-uint8_t tcp_tos(struct socket *);
-int tcp_emu(struct socket *, struct mbuf *);
-int tcp_ctl(struct socket *);
-struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
-
-struct socket *
-slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port);
-
-void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len);
-
-#endif
diff --git a/slirp/socket.c b/slirp/socket.c
deleted file mode 100644 (file)
index 4876ea3..0000000
+++ /dev/null
@@ -1,935 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#include "slirp.h"
-#include "ip_icmp.h"
-#ifdef __sun__
-#include <sys/filio.h>
-#endif
-
-static void sofcantrcvmore(struct socket *so);
-static void sofcantsendmore(struct socket *so);
-
-struct socket *solookup(struct socket **last, struct socket *head,
-        struct sockaddr_storage *lhost, struct sockaddr_storage *fhost)
-{
-    struct socket *so = *last;
-
-    /* Optimisation */
-    if (so != head && sockaddr_equal(&(so->lhost.ss), lhost)
-            && (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) {
-        return so;
-    }
-
-    for (so = head->so_next; so != head; so = so->so_next) {
-        if (sockaddr_equal(&(so->lhost.ss), lhost)
-                && (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) {
-            *last = so;
-            return so;
-        }
-    }
-
-    return (struct socket *)NULL;
-}
-
-/*
- * Create a new socket, initialise the fields
- * It is the responsibility of the caller to
- * insque() it into the correct linked-list
- */
-struct socket *
-socreate(Slirp *slirp)
-{
-    struct socket *so = g_new(struct socket, 1);
-
-    memset(so, 0, sizeof(struct socket));
-    so->so_state = SS_NOFDREF;
-    so->s = -1;
-    so->slirp = slirp;
-    so->pollfds_idx = -1;
-
-    return so;
-}
-
-/*
- * Remove references to so from the given message queue.
- */
-static void
-soqfree(struct socket *so, struct quehead *qh)
-{
-    struct mbuf *ifq;
-
-    for (ifq = (struct mbuf *) qh->qh_link;
-             (struct quehead *) ifq != qh;
-             ifq = ifq->ifq_next) {
-        if (ifq->ifq_so == so) {
-            struct mbuf *ifm;
-            ifq->ifq_so = NULL;
-            for (ifm = ifq->ifs_next; ifm != ifq; ifm = ifm->ifs_next) {
-                ifm->ifq_so = NULL;
-            }
-        }
-    }
-}
-
-/*
- * remque and free a socket, clobber cache
- */
-void
-sofree(struct socket *so)
-{
-  Slirp *slirp = so->slirp;
-
-  soqfree(so, &slirp->if_fastq);
-  soqfree(so, &slirp->if_batchq);
-
-  if (so == slirp->tcp_last_so) {
-      slirp->tcp_last_so = &slirp->tcb;
-  } else if (so == slirp->udp_last_so) {
-      slirp->udp_last_so = &slirp->udb;
-  } else if (so == slirp->icmp_last_so) {
-      slirp->icmp_last_so = &slirp->icmp;
-  }
-  m_free(so->so_m);
-
-  if(so->so_next && so->so_prev)
-    remque(so);  /* crashes if so is not in a queue */
-
-  if (so->so_tcpcb) {
-      free(so->so_tcpcb);
-  }
-  g_free(so);
-}
-
-size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np)
-{
-       int n, lss, total;
-       struct sbuf *sb = &so->so_snd;
-       int len = sb->sb_datalen - sb->sb_cc;
-       int mss = so->so_tcpcb->t_maxseg;
-
-       DEBUG_CALL("sopreprbuf");
-       DEBUG_ARG("so = %p", so);
-
-       if (len <= 0)
-               return 0;
-
-       iov[0].iov_base = sb->sb_wptr;
-        iov[1].iov_base = NULL;
-        iov[1].iov_len = 0;
-       if (sb->sb_wptr < sb->sb_rptr) {
-               iov[0].iov_len = sb->sb_rptr - sb->sb_wptr;
-               /* Should never succeed, but... */
-               if (iov[0].iov_len > len)
-                  iov[0].iov_len = len;
-               if (iov[0].iov_len > mss)
-                  iov[0].iov_len -= iov[0].iov_len%mss;
-               n = 1;
-       } else {
-               iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr;
-               /* Should never succeed, but... */
-               if (iov[0].iov_len > len) iov[0].iov_len = len;
-               len -= iov[0].iov_len;
-               if (len) {
-                       iov[1].iov_base = sb->sb_data;
-                       iov[1].iov_len = sb->sb_rptr - sb->sb_data;
-                       if(iov[1].iov_len > len)
-                          iov[1].iov_len = len;
-                       total = iov[0].iov_len + iov[1].iov_len;
-                       if (total > mss) {
-                               lss = total%mss;
-                               if (iov[1].iov_len > lss) {
-                                       iov[1].iov_len -= lss;
-                                       n = 2;
-                               } else {
-                                       lss -= iov[1].iov_len;
-                                       iov[0].iov_len -= lss;
-                                       n = 1;
-                               }
-                       } else
-                               n = 2;
-               } else {
-                       if (iov[0].iov_len > mss)
-                          iov[0].iov_len -= iov[0].iov_len%mss;
-                       n = 1;
-               }
-       }
-       if (np)
-               *np = n;
-
-       return iov[0].iov_len + (n - 1) * iov[1].iov_len;
-}
-
-/*
- * Read from so's socket into sb_snd, updating all relevant sbuf fields
- * NOTE: This will only be called if it is select()ed for reading, so
- * a read() of 0 (or less) means it's disconnected
- */
-int
-soread(struct socket *so)
-{
-       int n, nn;
-       struct sbuf *sb = &so->so_snd;
-       struct iovec iov[2];
-
-       DEBUG_CALL("soread");
-       DEBUG_ARG("so = %p", so);
-
-       /*
-        * No need to check if there's enough room to read.
-        * soread wouldn't have been called if there weren't
-        */
-       sopreprbuf(so, iov, &n);
-
-       nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
-       if (nn <= 0) {
-               if (nn < 0 && (errno == EINTR || errno == EAGAIN))
-                       return 0;
-               else {
-                       int err;
-                       socklen_t elen = sizeof err;
-                       struct sockaddr_storage addr;
-                       struct sockaddr *paddr = (struct sockaddr *) &addr;
-                       socklen_t alen = sizeof addr;
-
-                       err = errno;
-                       if (nn == 0) {
-                               if (getpeername(so->s, paddr, &alen) < 0) {
-                                       err = errno;
-                               } else {
-                                       getsockopt(so->s, SOL_SOCKET, SO_ERROR,
-                                               &err, &elen);
-                               }
-                       }
-
-                       DEBUG_MISC(" --- soread() disconnected, nn = %d, errno = %d-%s",
-                       nn, errno,strerror(errno));
-                       sofcantrcvmore(so);
-
-                       if (err == ECONNRESET || err == ECONNREFUSED
-                           || err == ENOTCONN || err == EPIPE) {
-                               tcp_drop(sototcpcb(so), err);
-                       } else {
-                               tcp_sockclosed(sototcpcb(so));
-                       }
-                       return -1;
-               }
-       }
-
-       /*
-        * If there was no error, try and read the second time round
-        * We read again if n = 2 (ie, there's another part of the buffer)
-        * and we read as much as we could in the first read
-        * We don't test for <= 0 this time, because there legitimately
-        * might not be any more data (since the socket is non-blocking),
-        * a close will be detected on next iteration.
-        * A return of -1 won't (shouldn't) happen, since it didn't happen above
-        */
-       if (n == 2 && nn == iov[0].iov_len) {
-            int ret;
-            ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0);
-            if (ret > 0)
-                nn += ret;
-        }
-
-       DEBUG_MISC(" ... read nn = %d bytes", nn);
-
-       /* Update fields */
-       sb->sb_cc += nn;
-       sb->sb_wptr += nn;
-       if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
-               sb->sb_wptr -= sb->sb_datalen;
-       return nn;
-}
-
-int soreadbuf(struct socket *so, const char *buf, int size)
-{
-    int n, nn, copy = size;
-       struct sbuf *sb = &so->so_snd;
-       struct iovec iov[2];
-
-       DEBUG_CALL("soreadbuf");
-       DEBUG_ARG("so = %p", so);
-
-       /*
-        * No need to check if there's enough room to read.
-        * soread wouldn't have been called if there weren't
-        */
-       if (sopreprbuf(so, iov, &n) < size)
-        goto err;
-
-    nn = MIN(iov[0].iov_len, copy);
-    memcpy(iov[0].iov_base, buf, nn);
-
-    copy -= nn;
-    buf += nn;
-
-    if (copy == 0)
-        goto done;
-
-    memcpy(iov[1].iov_base, buf, copy);
-
-done:
-    /* Update fields */
-       sb->sb_cc += size;
-       sb->sb_wptr += size;
-       if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
-               sb->sb_wptr -= sb->sb_datalen;
-    return size;
-err:
-
-    sofcantrcvmore(so);
-    tcp_sockclosed(sototcpcb(so));
-    g_critical("soreadbuf buffer too small");
-    return -1;
-}
-
-/*
- * Get urgent data
- *
- * When the socket is created, we set it SO_OOBINLINE,
- * so when OOB data arrives, we soread() it and everything
- * in the send buffer is sent as urgent data
- */
-int
-sorecvoob(struct socket *so)
-{
-       struct tcpcb *tp = sototcpcb(so);
-       int ret;
-
-       DEBUG_CALL("sorecvoob");
-       DEBUG_ARG("so = %p", so);
-
-       /*
-        * We take a guess at how much urgent data has arrived.
-        * In most situations, when urgent data arrives, the next
-        * read() should get all the urgent data.  This guess will
-        * be wrong however if more data arrives just after the
-        * urgent data, or the read() doesn't return all the
-        * urgent data.
-        */
-       ret = soread(so);
-       if (ret > 0) {
-           tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
-           tp->t_force = 1;
-           tcp_output(tp);
-           tp->t_force = 0;
-       }
-
-       return ret;
-}
-
-/*
- * Send urgent data
- * There's a lot duplicated code here, but...
- */
-int
-sosendoob(struct socket *so)
-{
-       struct sbuf *sb = &so->so_rcv;
-       char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
-
-       int n;
-
-       DEBUG_CALL("sosendoob");
-       DEBUG_ARG("so = %p", so);
-       DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc);
-
-       if (so->so_urgc > 2048)
-          so->so_urgc = 2048; /* XXXX */
-
-       if (sb->sb_rptr < sb->sb_wptr) {
-               /* We can send it directly */
-               n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
-       } else {
-               /*
-                * Since there's no sendv or sendtov like writev,
-                * we must copy all data to a linear buffer then
-                * send it all
-                */
-               uint32_t urgc = so->so_urgc;
-               int len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
-               if (len > urgc) {
-                       len = urgc;
-               }
-               memcpy(buff, sb->sb_rptr, len);
-               urgc -= len;
-               if (urgc) {
-                       n = sb->sb_wptr - sb->sb_data;
-                       if (n > urgc) {
-                               n = urgc;
-                       }
-                       memcpy((buff + len), sb->sb_data, n);
-                       len += n;
-               }
-               n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
-#ifdef DEBUG
-               if (n != len) {
-                       DEBUG_ERROR("Didn't send all data urgently XXXXX");
-               }
-#endif
-       }
-
-       if (n < 0) {
-               return n;
-       }
-       so->so_urgc -= n;
-       DEBUG_MISC(" ---2 sent %d bytes urgent data, %d urgent bytes left", n, so->so_urgc);
-
-       sb->sb_cc -= n;
-       sb->sb_rptr += n;
-       if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
-               sb->sb_rptr -= sb->sb_datalen;
-
-       return n;
-}
-
-/*
- * Write data from so_rcv to so's socket,
- * updating all sbuf field as necessary
- */
-int
-sowrite(struct socket *so)
-{
-       int  n,nn;
-       struct sbuf *sb = &so->so_rcv;
-       int len = sb->sb_cc;
-       struct iovec iov[2];
-
-       DEBUG_CALL("sowrite");
-       DEBUG_ARG("so = %p", so);
-
-       if (so->so_urgc) {
-               uint32_t expected = so->so_urgc;
-               if (sosendoob(so) < expected) {
-                       /* Treat a short write as a fatal error too,
-                        * rather than continuing on and sending the urgent
-                        * data as if it were non-urgent and leaving the
-                        * so_urgc count wrong.
-                        */
-                       goto err_disconnected;
-               }
-               if (sb->sb_cc == 0)
-                       return 0;
-       }
-
-       /*
-        * No need to check if there's something to write,
-        * sowrite wouldn't have been called otherwise
-        */
-
-       iov[0].iov_base = sb->sb_rptr;
-        iov[1].iov_base = NULL;
-        iov[1].iov_len = 0;
-       if (sb->sb_rptr < sb->sb_wptr) {
-               iov[0].iov_len = sb->sb_wptr - sb->sb_rptr;
-               /* Should never succeed, but... */
-               if (iov[0].iov_len > len) iov[0].iov_len = len;
-               n = 1;
-       } else {
-               iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
-               if (iov[0].iov_len > len) iov[0].iov_len = len;
-               len -= iov[0].iov_len;
-               if (len) {
-                       iov[1].iov_base = sb->sb_data;
-                       iov[1].iov_len = sb->sb_wptr - sb->sb_data;
-                       if (iov[1].iov_len > len) iov[1].iov_len = len;
-                       n = 2;
-               } else
-                       n = 1;
-       }
-       /* Check if there's urgent data to send, and if so, send it */
-
-       nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0);
-       /* This should never happen, but people tell me it does *shrug* */
-       if (nn < 0 && (errno == EAGAIN || errno == EINTR))
-               return 0;
-
-       if (nn <= 0) {
-               goto err_disconnected;
-       }
-
-       if (n == 2 && nn == iov[0].iov_len) {
-            int ret;
-            ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len,0);
-            if (ret > 0)
-                nn += ret;
-        }
-        DEBUG_MISC("  ... wrote nn = %d bytes", nn);
-
-       /* Update sbuf */
-       sb->sb_cc -= nn;
-       sb->sb_rptr += nn;
-       if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
-               sb->sb_rptr -= sb->sb_datalen;
-
-       /*
-        * If in DRAIN mode, and there's no more data, set
-        * it CANTSENDMORE
-        */
-       if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0)
-               sofcantsendmore(so);
-
-       return nn;
-
-err_disconnected:
-       DEBUG_MISC(" --- sowrite disconnected, so->so_state = %x, errno = %d",
-               so->so_state, errno);
-       sofcantsendmore(so);
-       tcp_sockclosed(sototcpcb(so));
-       return -1;
-}
-
-/*
- * recvfrom() a UDP socket
- */
-void
-sorecvfrom(struct socket *so)
-{
-       struct sockaddr_storage addr;
-       struct sockaddr_storage saddr, daddr;
-       socklen_t addrlen = sizeof(struct sockaddr_storage);
-
-       DEBUG_CALL("sorecvfrom");
-       DEBUG_ARG("so = %p", so);
-
-       if (so->so_type == IPPROTO_ICMP) {   /* This is a "ping" reply */
-         char buff[256];
-         int len;
-
-         len = recvfrom(so->s, buff, 256, 0,
-                        (struct sockaddr *)&addr, &addrlen);
-         /* XXX Check if reply is "correct"? */
-
-         if(len == -1 || len == 0) {
-           uint8_t code=ICMP_UNREACH_PORT;
-
-           if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
-           else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
-
-           DEBUG_MISC(" udp icmp rx errno = %d-%s",
-                   errno,strerror(errno));
-           icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno));
-         } else {
-           icmp_reflect(so->so_m);
-            so->so_m = NULL; /* Don't m_free() it again! */
-         }
-         /* No need for this socket anymore, udp_detach it */
-         udp_detach(so);
-       } else {                                /* A "normal" UDP packet */
-         struct mbuf *m;
-          int len;
-#ifdef _WIN32
-          unsigned long n;
-#else
-          int n;
-#endif
-
-         m = m_get(so->slirp);
-         if (!m) {
-             return;
-         }
-         switch (so->so_ffamily) {
-         case AF_INET:
-             m->m_data += IF_MAXLINKHDR + sizeof(struct udpiphdr);
-             break;
-         case AF_INET6:
-             m->m_data += IF_MAXLINKHDR + sizeof(struct ip6)
-                                        + sizeof(struct udphdr);
-             break;
-         default:
-             g_assert_not_reached();
-             break;
-         }
-
-         /*
-          * XXX Shouldn't FIONREAD packets destined for port 53,
-          * but I don't know the max packet size for DNS lookups
-          */
-         len = M_FREEROOM(m);
-         /* if (so->so_fport != htons(53)) { */
-         ioctlsocket(so->s, FIONREAD, &n);
-
-         if (n > len) {
-           n = (m->m_data - m->m_dat) + m->m_len + n + 1;
-           m_inc(m, n);
-           len = M_FREEROOM(m);
-         }
-         /* } */
-
-         m->m_len = recvfrom(so->s, m->m_data, len, 0,
-                             (struct sockaddr *)&addr, &addrlen);
-         DEBUG_MISC(" did recvfrom %d, errno = %d-%s",
-                 m->m_len, errno,strerror(errno));
-         if(m->m_len<0) {
-           /* Report error as ICMP */
-           switch (so->so_lfamily) {
-           uint8_t code;
-           case AF_INET:
-             code = ICMP_UNREACH_PORT;
-
-             if (errno == EHOSTUNREACH) {
-               code = ICMP_UNREACH_HOST;
-             } else if (errno == ENETUNREACH) {
-               code = ICMP_UNREACH_NET;
-             }
-
-             DEBUG_MISC(" rx error, tx icmp ICMP_UNREACH:%i", code);
-             icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno));
-             break;
-           case AF_INET6:
-             code = ICMP6_UNREACH_PORT;
-
-             if (errno == EHOSTUNREACH) {
-               code = ICMP6_UNREACH_ADDRESS;
-             } else if (errno == ENETUNREACH) {
-               code = ICMP6_UNREACH_NO_ROUTE;
-             }
-
-             DEBUG_MISC(" rx error, tx icmp6 ICMP_UNREACH:%i", code);
-             icmp6_send_error(so->so_m, ICMP6_UNREACH, code);
-             break;
-           default:
-             g_assert_not_reached();
-             break;
-           }
-           m_free(m);
-         } else {
-         /*
-          * Hack: domain name lookup will be used the most for UDP,
-          * and since they'll only be used once there's no need
-          * for the 4 minute (or whatever) timeout... So we time them
-          * out much quicker (10 seconds  for now...)
-          */
-           if (so->so_expire) {
-             if (so->so_fport == htons(53))
-               so->so_expire = curtime + SO_EXPIREFAST;
-             else
-               so->so_expire = curtime + SO_EXPIRE;
-           }
-
-           /*
-            * If this packet was destined for CTL_ADDR,
-            * make it look like that's where it came from
-            */
-           saddr = addr;
-           sotranslate_in(so, &saddr);
-           daddr = so->lhost.ss;
-
-           switch (so->so_ffamily) {
-           case AF_INET:
-               udp_output(so, m, (struct sockaddr_in *) &saddr,
-                          (struct sockaddr_in *) &daddr,
-                          so->so_iptos);
-               break;
-           case AF_INET6:
-               udp6_output(so, m, (struct sockaddr_in6 *) &saddr,
-                           (struct sockaddr_in6 *) &daddr);
-               break;
-           default:
-               g_assert_not_reached();
-               break;
-           }
-         } /* rx error */
-       } /* if ping packet */
-}
-
-/*
- * sendto() a socket
- */
-int
-sosendto(struct socket *so, struct mbuf *m)
-{
-       int ret;
-       struct sockaddr_storage addr;
-
-       DEBUG_CALL("sosendto");
-       DEBUG_ARG("so = %p", so);
-       DEBUG_ARG("m = %p", m);
-
-       addr = so->fhost.ss;
-       DEBUG_CALL(" sendto()ing)");
-       sotranslate_out(so, &addr);
-
-       /* Don't care what port we get */
-       ret = sendto(so->s, m->m_data, m->m_len, 0,
-                    (struct sockaddr *)&addr, sockaddr_size(&addr));
-       if (ret < 0)
-               return -1;
-
-       /*
-        * Kill the socket if there's no reply in 4 minutes,
-        * but only if it's an expirable socket
-        */
-       if (so->so_expire)
-               so->so_expire = curtime + SO_EXPIRE;
-       so->so_state &= SS_PERSISTENT_MASK;
-       so->so_state |= SS_ISFCONNECTED; /* So that it gets select()ed */
-       return 0;
-}
-
-/*
- * Listen for incoming TCP connections
- */
-struct socket *
-tcp_listen(Slirp *slirp, uint32_t haddr, unsigned hport, uint32_t laddr,
-           unsigned lport, int flags)
-{
-       struct sockaddr_in addr;
-       struct socket *so;
-       int s, opt = 1;
-       socklen_t addrlen = sizeof(addr);
-       memset(&addr, 0, addrlen);
-
-       DEBUG_CALL("tcp_listen");
-       DEBUG_ARG("haddr = %s", inet_ntoa((struct in_addr){.s_addr = haddr}));
-       DEBUG_ARG("hport = %d", ntohs(hport));
-       DEBUG_ARG("laddr = %s", inet_ntoa((struct in_addr){.s_addr = laddr}));
-       DEBUG_ARG("lport = %d", ntohs(lport));
-       DEBUG_ARG("flags = %x", flags);
-
-       so = socreate(slirp);
-
-       /* Don't tcp_attach... we don't need so_snd nor so_rcv */
-       if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) {
-            g_free(so);
-            return NULL;
-       }
-       insque(so, &slirp->tcb);
-
-       /*
-        * SS_FACCEPTONCE sockets must time out.
-        */
-       if (flags & SS_FACCEPTONCE)
-          so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2;
-
-       so->so_state &= SS_PERSISTENT_MASK;
-       so->so_state |= (SS_FACCEPTCONN | flags);
-       so->so_lfamily = AF_INET;
-       so->so_lport = lport; /* Kept in network format */
-       so->so_laddr.s_addr = laddr; /* Ditto */
-
-       addr.sin_family = AF_INET;
-       addr.sin_addr.s_addr = haddr;
-       addr.sin_port = hport;
-
-       if (((s = slirp_socket(AF_INET,SOCK_STREAM,0)) < 0) ||
-           (slirp_socket_set_fast_reuse(s) < 0) ||
-           (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
-           (listen(s,1) < 0)) {
-               int tmperrno = errno; /* Don't clobber the real reason we failed */
-
-                if (s >= 0) {
-                    closesocket(s);
-                }
-               sofree(so);
-               /* Restore the real errno */
-#ifdef _WIN32
-               WSASetLastError(tmperrno);
-#else
-               errno = tmperrno;
-#endif
-               return NULL;
-       }
-       setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
-       opt = 1;
-       setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(int));
-
-       getsockname(s,(struct sockaddr *)&addr,&addrlen);
-       so->so_ffamily = AF_INET;
-       so->so_fport = addr.sin_port;
-       if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
-          so->so_faddr = slirp->vhost_addr;
-       else
-          so->so_faddr = addr.sin_addr;
-
-       so->s = s;
-       return so;
-}
-
-/*
- * Various session state calls
- * XXX Should be #define's
- * The socket state stuff needs work, these often get call 2 or 3
- * times each when only 1 was needed
- */
-void
-soisfconnecting(struct socket *so)
-{
-       so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE|
-                         SS_FCANTSENDMORE|SS_FWDRAIN);
-       so->so_state |= SS_ISFCONNECTING; /* Clobber other states */
-}
-
-void
-soisfconnected(struct socket *so)
-{
-       so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF);
-       so->so_state |= SS_ISFCONNECTED; /* Clobber other states */
-}
-
-static void
-sofcantrcvmore(struct socket *so)
-{
-       if ((so->so_state & SS_NOFDREF) == 0) {
-               shutdown(so->s,0);
-       }
-       so->so_state &= ~(SS_ISFCONNECTING);
-       if (so->so_state & SS_FCANTSENDMORE) {
-          so->so_state &= SS_PERSISTENT_MASK;
-          so->so_state |= SS_NOFDREF; /* Don't select it */
-       } else {
-          so->so_state |= SS_FCANTRCVMORE;
-       }
-}
-
-static void
-sofcantsendmore(struct socket *so)
-{
-       if ((so->so_state & SS_NOFDREF) == 0) {
-            shutdown(so->s,1);           /* send FIN to fhost */
-       }
-       so->so_state &= ~(SS_ISFCONNECTING);
-       if (so->so_state & SS_FCANTRCVMORE) {
-          so->so_state &= SS_PERSISTENT_MASK;
-          so->so_state |= SS_NOFDREF; /* as above */
-       } else {
-          so->so_state |= SS_FCANTSENDMORE;
-       }
-}
-
-/*
- * Set write drain mode
- * Set CANTSENDMORE once all data has been write()n
- */
-void
-sofwdrain(struct socket *so)
-{
-       if (so->so_rcv.sb_cc)
-               so->so_state |= SS_FWDRAIN;
-       else
-               sofcantsendmore(so);
-}
-
-/*
- * Translate addr in host addr when it is a virtual address
- */
-void sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
-{
-    Slirp *slirp = so->slirp;
-    struct sockaddr_in *sin = (struct sockaddr_in *)addr;
-    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
-
-    switch (addr->ss_family) {
-    case AF_INET:
-        if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
-                slirp->vnetwork_addr.s_addr) {
-            /* It's an alias */
-            if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
-                if (get_dns_addr(&sin->sin_addr) < 0) {
-                    sin->sin_addr = loopback_addr;
-                }
-            } else {
-                sin->sin_addr = loopback_addr;
-            }
-        }
-
-        DEBUG_MISC(" addr.sin_port=%d, addr.sin_addr.s_addr=%.16s",
-                   ntohs(sin->sin_port), inet_ntoa(sin->sin_addr));
-        break;
-
-    case AF_INET6:
-        if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6,
-                    slirp->vprefix_len)) {
-            if (in6_equal(&so->so_faddr6, &slirp->vnameserver_addr6)) {
-                uint32_t scope_id;
-                if (get_dns6_addr(&sin6->sin6_addr, &scope_id) >= 0) {
-                    sin6->sin6_scope_id = scope_id;
-                } else {
-                    sin6->sin6_addr = in6addr_loopback;
-                }
-            } else {
-                sin6->sin6_addr = in6addr_loopback;
-            }
-        }
-        break;
-
-    default:
-        break;
-    }
-}
-
-void sotranslate_in(struct socket *so, struct sockaddr_storage *addr)
-{
-    Slirp *slirp = so->slirp;
-    struct sockaddr_in *sin = (struct sockaddr_in *)addr;
-    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
-
-    switch (addr->ss_family) {
-    case AF_INET:
-        if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
-            slirp->vnetwork_addr.s_addr) {
-            uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
-
-            if ((so->so_faddr.s_addr & inv_mask) == inv_mask) {
-                sin->sin_addr = slirp->vhost_addr;
-            } else if (sin->sin_addr.s_addr == loopback_addr.s_addr ||
-                       so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
-                sin->sin_addr = so->so_faddr;
-            }
-        }
-        break;
-
-    case AF_INET6:
-        if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6,
-                    slirp->vprefix_len)) {
-            if (in6_equal(&sin6->sin6_addr, &in6addr_loopback)
-                    || !in6_equal(&so->so_faddr6, &slirp->vhost_addr6)) {
-                sin6->sin6_addr = so->so_faddr6;
-            }
-        }
-        break;
-
-    default:
-        break;
-    }
-}
-
-/*
- * Translate connections from localhost to the real hostname
- */
-void sotranslate_accept(struct socket *so)
-{
-    Slirp *slirp = so->slirp;
-
-    switch (so->so_ffamily) {
-    case AF_INET:
-        if (so->so_faddr.s_addr == INADDR_ANY ||
-            (so->so_faddr.s_addr & loopback_mask) ==
-            (loopback_addr.s_addr & loopback_mask)) {
-           so->so_faddr = slirp->vhost_addr;
-        }
-        break;
-
-   case AF_INET6:
-        if (in6_equal(&so->so_faddr6, &in6addr_any) ||
-                in6_equal(&so->so_faddr6, &in6addr_loopback)) {
-           so->so_faddr6 = slirp->vhost_addr6;
-        }
-        break;
-
-    default:
-        break;
-    }
-}
-
-void sodrop(struct socket *s, int num)
-{
-    if (sbdrop(&s->so_snd, num)) {
-        s->slirp->cb->notify(s->slirp->opaque);
-    }
-}
diff --git a/slirp/socket.h b/slirp/socket.h
deleted file mode 100644 (file)
index e4d12cd..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#ifndef SLIRP_SOCKET_H
-#define SLIRP_SOCKET_H
-
-#include "misc.h"
-
-#define SO_EXPIRE 240000
-#define SO_EXPIREFAST 10000
-
-/*
- * Our socket structure
- */
-
-union slirp_sockaddr {
-    struct sockaddr_storage ss;
-    struct sockaddr_in sin;
-    struct sockaddr_in6 sin6;
-};
-
-struct socket {
-  struct socket *so_next,*so_prev;      /* For a linked list of sockets */
-
-  int s;                           /* The actual socket */
-  struct gfwd_list *guestfwd;
-
-  int pollfds_idx;                 /* GPollFD GArray index */
-
-  Slirp *slirp;                           /* managing slirp instance */
-
-                       /* XXX union these with not-yet-used sbuf params */
-  struct mbuf *so_m;              /* Pointer to the original SYN packet,
-                                   * for non-blocking connect()'s, and
-                                   * PING reply's */
-  struct tcpiphdr *so_ti;         /* Pointer to the original ti within
-                                   * so_mconn, for non-blocking connections */
-  uint32_t      so_urgc;
-  union slirp_sockaddr fhost;      /* Foreign host */
-#define so_faddr fhost.sin.sin_addr
-#define so_fport fhost.sin.sin_port
-#define so_faddr6 fhost.sin6.sin6_addr
-#define so_fport6 fhost.sin6.sin6_port
-#define so_ffamily fhost.ss.ss_family
-
-  union slirp_sockaddr lhost;      /* Local host */
-#define so_laddr lhost.sin.sin_addr
-#define so_lport lhost.sin.sin_port
-#define so_laddr6 lhost.sin6.sin6_addr
-#define so_lport6 lhost.sin6.sin6_port
-#define so_lfamily lhost.ss.ss_family
-
-  uint8_t      so_iptos;       /* Type of service */
-  uint8_t      so_emu;         /* Is the socket emulated? */
-
-  uint8_t       so_type;        /* Type of socket, UDP or TCP */
-  int32_t       so_state;       /* internal state flags SS_*, below */
-
-  struct       tcpcb *so_tcpcb;        /* pointer to TCP protocol control block */
-  unsigned     so_expire;              /* When the socket will expire */
-
-  int  so_queued;              /* Number of packets queued from this socket */
-  int  so_nqueued;             /* Number of packets queued in a row
-                                * Used to determine when to "downgrade" a session
-                                        * from fastq to batchq */
-
-  struct sbuf so_rcv;          /* Receive buffer */
-  struct sbuf so_snd;          /* Send buffer */
-};
-
-
-/*
- * Socket state bits. (peer means the host on the Internet,
- * local host means the host on the other end of the modem)
- */
-#define SS_NOFDREF             0x001   /* No fd reference */
-
-#define SS_ISFCONNECTING       0x002   /* Socket is connecting to peer (non-blocking connect()'s) */
-#define SS_ISFCONNECTED                0x004   /* Socket is connected to peer */
-#define SS_FCANTRCVMORE                0x008   /* Socket can't receive more from peer (for half-closes) */
-#define SS_FCANTSENDMORE       0x010   /* Socket can't send more to peer (for half-closes) */
-#define SS_FWDRAIN             0x040   /* We received a FIN, drain data and set SS_FCANTSENDMORE */
-
-#define SS_CTL                 0x080
-#define SS_FACCEPTCONN         0x100   /* Socket is accepting connections from a host on the internet */
-#define SS_FACCEPTONCE         0x200   /* If set, the SS_FACCEPTCONN socket will die after one accept */
-
-#define SS_PERSISTENT_MASK     0xf000  /* Unremovable state bits */
-#define SS_HOSTFWD             0x1000  /* Socket describes host->guest forwarding */
-#define SS_INCOMING            0x2000  /* Connection was initiated by a host on the internet */
-
-static inline int sockaddr_equal(struct sockaddr_storage *a,
-        struct sockaddr_storage *b)
-{
-    if (a->ss_family != b->ss_family) {
-        return 0;
-    }
-
-    switch (a->ss_family) {
-    case AF_INET:
-    {
-        struct sockaddr_in *a4 = (struct sockaddr_in *) a;
-        struct sockaddr_in *b4 = (struct sockaddr_in *) b;
-        return a4->sin_addr.s_addr == b4->sin_addr.s_addr
-               && a4->sin_port == b4->sin_port;
-    }
-    case AF_INET6:
-    {
-        struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) a;
-        struct sockaddr_in6 *b6 = (struct sockaddr_in6 *) b;
-        return (in6_equal(&a6->sin6_addr, &b6->sin6_addr)
-                && a6->sin6_port == b6->sin6_port);
-    }
-    default:
-        g_assert_not_reached();
-    }
-
-    return 0;
-}
-
-static inline socklen_t sockaddr_size(struct sockaddr_storage *a)
-{
-    switch (a->ss_family) {
-    case AF_INET:
-        return sizeof(struct sockaddr_in);
-    case AF_INET6:
-        return sizeof(struct sockaddr_in6);
-    default:
-        g_assert_not_reached();
-    }
-}
-
-struct socket *solookup(struct socket **, struct socket *,
-        struct sockaddr_storage *, struct sockaddr_storage *);
-struct socket *socreate(Slirp *);
-void sofree(struct socket *);
-int soread(struct socket *);
-int sorecvoob(struct socket *);
-int sosendoob(struct socket *);
-int sowrite(struct socket *);
-void sorecvfrom(struct socket *);
-int sosendto(struct socket *, struct mbuf *);
-struct socket * tcp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned,
-                               int);
-void soisfconnecting(register struct socket *);
-void soisfconnected(register struct socket *);
-void sofwdrain(struct socket *);
-struct iovec; /* For win32 */
-size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
-int soreadbuf(struct socket *so, const char *buf, int size);
-
-void sotranslate_out(struct socket *, struct sockaddr_storage *);
-void sotranslate_in(struct socket *, struct sockaddr_storage *);
-void sotranslate_accept(struct socket *);
-void sodrop(struct socket *, int num);
-
-
-#endif /* SLIRP_SOCKET_H */
diff --git a/slirp/src/arp_table.c b/slirp/src/arp_table.c
new file mode 100644 (file)
index 0000000..58eafdc
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * ARP table
+ *
+ * Copyright (c) 2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "slirp.h"
+
+#include <string.h>
+
+void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
+{
+    const uint32_t broadcast_addr =
+        ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
+    ArpTable *arptbl = &slirp->arp_table;
+    int i;
+
+    DEBUG_CALL("arp_table_add");
+    DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){.s_addr = ip_addr}));
+    DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
+              ethaddr[0], ethaddr[1], ethaddr[2],
+              ethaddr[3], ethaddr[4], ethaddr[5]);
+
+    if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
+        /* Do not register broadcast addresses */
+        return;
+    }
+
+    /* Search for an entry */
+    for (i = 0; i < ARP_TABLE_SIZE; i++) {
+        if (arptbl->table[i].ar_sip == ip_addr) {
+            /* Update the entry */
+            memcpy(arptbl->table[i].ar_sha, ethaddr, ETH_ALEN);
+            return;
+        }
+    }
+
+    /* No entry found, create a new one */
+    arptbl->table[arptbl->next_victim].ar_sip = ip_addr;
+    memcpy(arptbl->table[arptbl->next_victim].ar_sha,  ethaddr, ETH_ALEN);
+    arptbl->next_victim = (arptbl->next_victim + 1) % ARP_TABLE_SIZE;
+}
+
+bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
+                      uint8_t out_ethaddr[ETH_ALEN])
+{
+    const uint32_t broadcast_addr =
+        ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
+    ArpTable *arptbl = &slirp->arp_table;
+    int i;
+
+    DEBUG_CALL("arp_table_search");
+    DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){.s_addr = ip_addr}));
+
+    /* If broadcast address */
+    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
+        /* return Ethernet broadcast address */
+        memset(out_ethaddr, 0xff, ETH_ALEN);
+        return 1;
+    }
+
+    for (i = 0; i < ARP_TABLE_SIZE; i++) {
+        if (arptbl->table[i].ar_sip == ip_addr) {
+            memcpy(out_ethaddr, arptbl->table[i].ar_sha,  ETH_ALEN);
+            DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
+                      out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
+                      out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
+            return 1;
+        }
+    }
+
+    return 0;
+}
diff --git a/slirp/src/bootp.c b/slirp/src/bootp.c
new file mode 100644 (file)
index 0000000..d396849
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * QEMU BOOTP/DHCP server
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "slirp.h"
+
+#if defined(_WIN32)
+/* Windows ntohl() returns an u_long value.
+ * Add a type cast to match the format strings. */
+# define ntohl(n) ((uint32_t)ntohl(n))
+#endif
+
+/* XXX: only DHCP is supported */
+
+#define LEASE_TIME (24 * 3600)
+
+static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
+
+#define DPRINTF(fmt, ...) DEBUG_CALL(fmt, ##__VA_ARGS__)
+
+static BOOTPClient *get_new_addr(Slirp *slirp, struct in_addr *paddr,
+                                 const uint8_t *macaddr)
+{
+    BOOTPClient *bc;
+    int i;
+
+    for(i = 0; i < NB_BOOTP_CLIENTS; i++) {
+        bc = &slirp->bootp_clients[i];
+        if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6))
+            goto found;
+    }
+    return NULL;
+ found:
+    bc = &slirp->bootp_clients[i];
+    bc->allocated = 1;
+    paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
+    return bc;
+}
+
+static BOOTPClient *request_addr(Slirp *slirp, const struct in_addr *paddr,
+                                 const uint8_t *macaddr)
+{
+    uint32_t req_addr = ntohl(paddr->s_addr);
+    uint32_t dhcp_addr = ntohl(slirp->vdhcp_startaddr.s_addr);
+    BOOTPClient *bc;
+
+    if (req_addr >= dhcp_addr &&
+        req_addr < (dhcp_addr + NB_BOOTP_CLIENTS)) {
+        bc = &slirp->bootp_clients[req_addr - dhcp_addr];
+        if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
+            bc->allocated = 1;
+            return bc;
+        }
+    }
+    return NULL;
+}
+
+static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr,
+                              const uint8_t *macaddr)
+{
+    BOOTPClient *bc;
+    int i;
+
+    for(i = 0; i < NB_BOOTP_CLIENTS; i++) {
+        if (!memcmp(macaddr, slirp->bootp_clients[i].macaddr, 6))
+            goto found;
+    }
+    return NULL;
+ found:
+    bc = &slirp->bootp_clients[i];
+    bc->allocated = 1;
+    paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
+    return bc;
+}
+
+static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
+                        struct in_addr *preq_addr)
+{
+    const uint8_t *p, *p_end;
+    int len, tag;
+
+    *pmsg_type = 0;
+    preq_addr->s_addr = htonl(0L);
+
+    p = bp->bp_vend;
+    p_end = p + DHCP_OPT_LEN;
+    if (memcmp(p, rfc1533_cookie, 4) != 0)
+        return;
+    p += 4;
+    while (p < p_end) {
+        tag = p[0];
+        if (tag == RFC1533_PAD) {
+            p++;
+        } else if (tag == RFC1533_END) {
+            break;
+        } else {
+            p++;
+            if (p >= p_end)
+                break;
+            len = *p++;
+            if (p + len > p_end) {
+                break;
+            }
+            DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
+
+            switch(tag) {
+            case RFC2132_MSG_TYPE:
+                if (len >= 1)
+                    *pmsg_type = p[0];
+                break;
+            case RFC2132_REQ_ADDR:
+                if (len >= 4) {
+                    memcpy(&(preq_addr->s_addr), p, 4);
+                }
+                break;
+            default:
+                break;
+            }
+            p += len;
+        }
+    }
+    if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) &&
+        bp->bp_ciaddr.s_addr) {
+        memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4);
+    }
+}
+
+static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
+{
+    BOOTPClient *bc = NULL;
+    struct mbuf *m;
+    struct bootp_t *rbp;
+    struct sockaddr_in saddr, daddr;
+    struct in_addr preq_addr;
+    int dhcp_msg_type, val;
+    uint8_t *q;
+    uint8_t *end;
+    uint8_t client_ethaddr[ETH_ALEN];
+
+    /* extract exact DHCP msg type */
+    dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
+    DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
+    if (preq_addr.s_addr != htonl(0L))
+        DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
+    else {
+        DPRINTF("\n");
+    }
+
+    if (dhcp_msg_type == 0)
+        dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
+
+    if (dhcp_msg_type != DHCPDISCOVER &&
+        dhcp_msg_type != DHCPREQUEST)
+        return;
+
+    /* Get client's hardware address from bootp request */
+    memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN);
+
+    m = m_get(slirp);
+    if (!m) {
+        return;
+    }
+    m->m_data += IF_MAXLINKHDR;
+    rbp = (struct bootp_t *)m->m_data;
+    m->m_data += sizeof(struct udpiphdr);
+    memset(rbp, 0, sizeof(struct bootp_t));
+
+    if (dhcp_msg_type == DHCPDISCOVER) {
+        if (preq_addr.s_addr != htonl(0L)) {
+            bc = request_addr(slirp, &preq_addr, client_ethaddr);
+            if (bc) {
+                daddr.sin_addr = preq_addr;
+            }
+        }
+        if (!bc) {
+         new_addr:
+            bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr);
+            if (!bc) {
+                DPRINTF("no address left\n");
+                return;
+            }
+        }
+        memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
+    } else if (preq_addr.s_addr != htonl(0L)) {
+        bc = request_addr(slirp, &preq_addr, client_ethaddr);
+        if (bc) {
+            daddr.sin_addr = preq_addr;
+            memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
+        } else {
+            /* DHCPNAKs should be sent to broadcast */
+            daddr.sin_addr.s_addr = 0xffffffff;
+        }
+    } else {
+        bc = find_addr(slirp, &daddr.sin_addr, bp->bp_hwaddr);
+        if (!bc) {
+            /* if never assigned, behaves as if it was already
+               assigned (windows fix because it remembers its address) */
+            goto new_addr;
+        }
+    }
+
+    /* Update ARP table for this IP address */
+    arp_table_add(slirp, daddr.sin_addr.s_addr, client_ethaddr);
+
+    saddr.sin_addr = slirp->vhost_addr;
+    saddr.sin_port = htons(BOOTP_SERVER);
+
+    daddr.sin_port = htons(BOOTP_CLIENT);
+
+    rbp->bp_op = BOOTP_REPLY;
+    rbp->bp_xid = bp->bp_xid;
+    rbp->bp_htype = 1;
+    rbp->bp_hlen = 6;
+    memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN);
+
+    rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
+    rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
+
+    q = rbp->bp_vend;
+    end = (uint8_t *)&rbp[1];
+    memcpy(q, rfc1533_cookie, 4);
+    q += 4;
+
+    if (bc) {
+        DPRINTF("%s addr=%08" PRIx32 "\n",
+                (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed",
+                ntohl(daddr.sin_addr.s_addr));
+
+        if (dhcp_msg_type == DHCPDISCOVER) {
+            *q++ = RFC2132_MSG_TYPE;
+            *q++ = 1;
+            *q++ = DHCPOFFER;
+        } else /* DHCPREQUEST */ {
+            *q++ = RFC2132_MSG_TYPE;
+            *q++ = 1;
+            *q++ = DHCPACK;
+        }
+
+        if (slirp->bootp_filename)
+            snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s",
+                     slirp->bootp_filename);
+
+        *q++ = RFC2132_SRV_ID;
+        *q++ = 4;
+        memcpy(q, &saddr.sin_addr, 4);
+        q += 4;
+
+        *q++ = RFC1533_NETMASK;
+        *q++ = 4;
+        memcpy(q, &slirp->vnetwork_mask, 4);
+        q += 4;
+
+        if (!slirp->restricted) {
+            *q++ = RFC1533_GATEWAY;
+            *q++ = 4;
+            memcpy(q, &saddr.sin_addr, 4);
+            q += 4;
+
+            *q++ = RFC1533_DNS;
+            *q++ = 4;
+            memcpy(q, &slirp->vnameserver_addr, 4);
+            q += 4;
+        }
+
+        *q++ = RFC2132_LEASE_TIME;
+        *q++ = 4;
+        val = htonl(LEASE_TIME);
+        memcpy(q, &val, 4);
+        q += 4;
+
+        if (*slirp->client_hostname) {
+            val = strlen(slirp->client_hostname);
+            if (q + val + 2 >= end) {
+                g_warning("DHCP packet size exceeded, "
+                    "omitting host name option.");
+            } else {
+                *q++ = RFC1533_HOSTNAME;
+                *q++ = val;
+                memcpy(q, slirp->client_hostname, val);
+                q += val;
+            }
+        }
+
+        if (slirp->vdomainname) {
+            val = strlen(slirp->vdomainname);
+            if (q + val + 2 >= end) {
+                g_warning("DHCP packet size exceeded, "
+                    "omitting domain name option.");
+            } else {
+                *q++ = RFC1533_DOMAINNAME;
+                *q++ = val;
+                memcpy(q, slirp->vdomainname, val);
+                q += val;
+            }
+        }
+
+        if (slirp->tftp_server_name) {
+            val = strlen(slirp->tftp_server_name);
+            if (q + val + 2 >= end) {
+                g_warning("DHCP packet size exceeded, "
+                    "omitting tftp-server-name option.");
+            } else {
+                *q++ = RFC2132_TFTP_SERVER_NAME;
+                *q++ = val;
+                memcpy(q, slirp->tftp_server_name, val);
+                q += val;
+            }
+        }
+
+        if (slirp->vdnssearch) {
+            val = slirp->vdnssearch_len;
+            if (q + val >= end) {
+                g_warning("DHCP packet size exceeded, "
+                    "omitting domain-search option.");
+            } else {
+                memcpy(q, slirp->vdnssearch, val);
+                q += val;
+            }
+        }
+    } else {
+        static const char nak_msg[] = "requested address not available";
+
+        DPRINTF("nak'ed addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
+
+        *q++ = RFC2132_MSG_TYPE;
+        *q++ = 1;
+        *q++ = DHCPNAK;
+
+        *q++ = RFC2132_MESSAGE;
+        *q++ = sizeof(nak_msg) - 1;
+        memcpy(q, nak_msg, sizeof(nak_msg) - 1);
+        q += sizeof(nak_msg) - 1;
+    }
+    assert(q < end);
+    *q = RFC1533_END;
+
+    daddr.sin_addr.s_addr = 0xffffffffu;
+
+    m->m_len = sizeof(struct bootp_t) -
+        sizeof(struct ip) - sizeof(struct udphdr);
+    udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+}
+
+void bootp_input(struct mbuf *m)
+{
+    struct bootp_t *bp = mtod(m, struct bootp_t *);
+
+    if (bp->bp_op == BOOTP_REQUEST) {
+        bootp_reply(m->slirp, bp);
+    }
+}
diff --git a/slirp/src/bootp.h b/slirp/src/bootp.h
new file mode 100644 (file)
index 0000000..4043489
--- /dev/null
@@ -0,0 +1,128 @@
+/* bootp/dhcp defines */
+
+#ifndef SLIRP_BOOTP_H
+#define SLIRP_BOOTP_H
+
+#define BOOTP_SERVER   67
+#define BOOTP_CLIENT   68
+
+#define BOOTP_REQUEST  1
+#define BOOTP_REPLY    2
+
+#define RFC1533_COOKIE         99, 130, 83, 99
+#define RFC1533_PAD            0
+#define RFC1533_NETMASK                1
+#define RFC1533_TIMEOFFSET     2
+#define RFC1533_GATEWAY                3
+#define RFC1533_TIMESERVER     4
+#define RFC1533_IEN116NS       5
+#define RFC1533_DNS            6
+#define RFC1533_LOGSERVER      7
+#define RFC1533_COOKIESERVER   8
+#define RFC1533_LPRSERVER      9
+#define RFC1533_IMPRESSSERVER  10
+#define RFC1533_RESOURCESERVER 11
+#define RFC1533_HOSTNAME       12
+#define RFC1533_BOOTFILESIZE   13
+#define RFC1533_MERITDUMPFILE  14
+#define RFC1533_DOMAINNAME     15
+#define RFC1533_SWAPSERVER     16
+#define RFC1533_ROOTPATH       17
+#define RFC1533_EXTENSIONPATH  18
+#define RFC1533_IPFORWARDING   19
+#define RFC1533_IPSOURCEROUTING        20
+#define RFC1533_IPPOLICYFILTER 21
+#define RFC1533_IPMAXREASSEMBLY        22
+#define RFC1533_IPTTL          23
+#define RFC1533_IPMTU          24
+#define RFC1533_IPMTUPLATEAU   25
+#define RFC1533_INTMTU         26
+#define RFC1533_INTLOCALSUBNETS        27
+#define RFC1533_INTBROADCAST   28
+#define RFC1533_INTICMPDISCOVER        29
+#define RFC1533_INTICMPRESPOND 30
+#define RFC1533_INTROUTEDISCOVER 31
+#define RFC1533_INTROUTESOLICIT        32
+#define RFC1533_INTSTATICROUTES        33
+#define RFC1533_LLTRAILERENCAP 34
+#define RFC1533_LLARPCACHETMO  35
+#define RFC1533_LLETHERNETENCAP        36
+#define RFC1533_TCPTTL         37
+#define RFC1533_TCPKEEPALIVETMO        38
+#define RFC1533_TCPKEEPALIVEGB 39
+#define RFC1533_NISDOMAIN      40
+#define RFC1533_NISSERVER      41
+#define RFC1533_NTPSERVER      42
+#define RFC1533_VENDOR         43
+#define RFC1533_NBNS           44
+#define RFC1533_NBDD           45
+#define RFC1533_NBNT           46
+#define RFC1533_NBSCOPE                47
+#define RFC1533_XFS            48
+#define RFC1533_XDM            49
+
+#define RFC2132_REQ_ADDR       50
+#define RFC2132_LEASE_TIME      51
+#define RFC2132_MSG_TYPE       53
+#define RFC2132_SRV_ID         54
+#define RFC2132_PARAM_LIST     55
+#define RFC2132_MESSAGE                56
+#define RFC2132_MAX_SIZE       57
+#define RFC2132_RENEWAL_TIME    58
+#define RFC2132_REBIND_TIME     59
+#define RFC2132_TFTP_SERVER_NAME 66
+
+#define DHCPDISCOVER           1
+#define DHCPOFFER              2
+#define DHCPREQUEST            3
+#define DHCPACK                        5
+#define DHCPNAK                        6
+
+#define RFC1533_VENDOR_MAJOR   0
+#define RFC1533_VENDOR_MINOR   0
+
+#define RFC1533_VENDOR_MAGIC   128
+#define RFC1533_VENDOR_ADDPARM 129
+#define        RFC1533_VENDOR_ETHDEV   130
+#define RFC1533_VENDOR_HOWTO    132
+#define RFC1533_VENDOR_MNUOPTS 160
+#define RFC1533_VENDOR_SELECTION 176
+#define RFC1533_VENDOR_MOTD    184
+#define RFC1533_VENDOR_NUMOFMOTD 8
+#define RFC1533_VENDOR_IMG     192
+#define RFC1533_VENDOR_NUMOFIMG        16
+
+#define RFC1533_END            255
+#define BOOTP_VENDOR_LEN       64
+#define DHCP_OPT_LEN           312
+
+struct bootp_t {
+    struct ip ip;
+    struct udphdr udp;
+    uint8_t bp_op;
+    uint8_t bp_htype;
+    uint8_t bp_hlen;
+    uint8_t bp_hops;
+    uint32_t bp_xid;
+    uint16_t bp_secs;
+    uint16_t unused;
+    struct in_addr bp_ciaddr;
+    struct in_addr bp_yiaddr;
+    struct in_addr bp_siaddr;
+    struct in_addr bp_giaddr;
+    uint8_t bp_hwaddr[16];
+    uint8_t bp_sname[64];
+    uint8_t bp_file[128];
+    uint8_t bp_vend[DHCP_OPT_LEN];
+};
+
+typedef struct {
+    uint16_t allocated;
+    uint8_t macaddr[6];
+} BOOTPClient;
+
+#define NB_BOOTP_CLIENTS 16
+
+void bootp_input(struct mbuf *m);
+
+#endif
diff --git a/slirp/src/cksum.c b/slirp/src/cksum.c
new file mode 100644 (file)
index 0000000..25bfa67
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 1988, 1992, 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. 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.
+ *
+ *     @(#)in_cksum.c  8.1 (Berkeley) 6/10/93
+ * in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp
+ */
+
+#include "slirp.h"
+
+/*
+ * Checksum routine for Internet Protocol family headers (Portable Version).
+ *
+ * This routine is very heavily used in the network
+ * code and should be modified for each CPU to be as fast as possible.
+ *
+ * XXX Since we will never span more than 1 mbuf, we can optimise this
+ */
+
+#define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
+#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1];        \
+        (void)ADDCARRY(sum);}
+
+int cksum(struct mbuf *m, int len)
+{
+       register uint16_t *w;
+       register int sum = 0;
+       register int mlen = 0;
+       int byte_swapped = 0;
+
+       union {
+               uint8_t  c[2];
+               uint16_t s;
+       } s_util;
+       union {
+               uint16_t s[2];
+               uint32_t l;
+       } l_util;
+
+       if (m->m_len == 0)
+          goto cont;
+       w = mtod(m, uint16_t *);
+
+       mlen = m->m_len;
+
+       if (len < mlen)
+          mlen = len;
+       len -= mlen;
+       /*
+        * Force to even boundary.
+        */
+       if ((1 & (uintptr_t)w) && (mlen > 0)) {
+               REDUCE;
+               sum <<= 8;
+               s_util.c[0] = *(uint8_t *)w;
+               w = (uint16_t *)((int8_t *)w + 1);
+               mlen--;
+               byte_swapped = 1;
+       }
+       /*
+        * Unroll the loop to make overhead from
+        * branches &c small.
+        */
+       while ((mlen -= 32) >= 0) {
+               sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
+               sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
+               sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
+               sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
+               w += 16;
+       }
+       mlen += 32;
+       while ((mlen -= 8) >= 0) {
+               sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
+               w += 4;
+       }
+       mlen += 8;
+       if (mlen == 0 && byte_swapped == 0)
+          goto cont;
+       REDUCE;
+       while ((mlen -= 2) >= 0) {
+               sum += *w++;
+       }
+
+       if (byte_swapped) {
+               REDUCE;
+               sum <<= 8;
+               if (mlen == -1) {
+                       s_util.c[1] = *(uint8_t *)w;
+                       sum += s_util.s;
+                       mlen = 0;
+               } else
+
+                  mlen = -1;
+       } else if (mlen == -1)
+          s_util.c[0] = *(uint8_t *)w;
+
+cont:
+       if (len) {
+               DEBUG_ERROR("cksum: out of data");
+               DEBUG_ERROR(" len = %d", len);
+       }
+       if (mlen == -1) {
+               /* The last mbuf has odd # of bytes. Follow the
+                standard (the odd byte may be shifted left by 8 bits
+                          or not as determined by endian-ness of the machine) */
+               s_util.c[1] = 0;
+               sum += s_util.s;
+       }
+       REDUCE;
+       return (~sum & 0xffff);
+}
+
+int ip6_cksum(struct mbuf *m)
+{
+    /* TODO: Optimize this by being able to pass the ip6_pseudohdr to cksum
+     * separately from the mbuf */
+    struct ip6 save_ip, *ip = mtod(m, struct ip6 *);
+    struct ip6_pseudohdr *ih = mtod(m, struct ip6_pseudohdr *);
+    int sum;
+
+    save_ip = *ip;
+
+    ih->ih_src = save_ip.ip_src;
+    ih->ih_dst = save_ip.ip_dst;
+    ih->ih_pl = htonl((uint32_t)ntohs(save_ip.ip_pl));
+    ih->ih_zero_hi = 0;
+    ih->ih_zero_lo = 0;
+    ih->ih_nh = save_ip.ip_nh;
+
+    sum = cksum(m, ((int)sizeof(struct ip6_pseudohdr))
+                    + ntohl(ih->ih_pl));
+
+    *ip = save_ip;
+
+    return sum;
+}
diff --git a/slirp/src/debug.h b/slirp/src/debug.h
new file mode 100644 (file)
index 0000000..44d922d
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef DEBUG_H_
+#define DEBUG_H_
+
+#define DBG_CALL (1 << 0)
+#define DBG_MISC (1 << 1)
+#define DBG_ERROR (1 << 2)
+#define DBG_TFTP (1 << 3)
+
+extern int slirp_debug;
+
+#define DEBUG_CALL(fmt, ...) do {               \
+    if (G_UNLIKELY(slirp_debug & DBG_CALL)) {   \
+        g_debug(fmt "...", ##__VA_ARGS__);      \
+    }                                           \
+} while (0)
+
+#define DEBUG_ARG(fmt, ...) do {                \
+    if (G_UNLIKELY(slirp_debug & DBG_CALL)) {   \
+        g_debug(" " fmt, ##__VA_ARGS__);        \
+    }                                           \
+} while (0)
+
+#define DEBUG_MISC(fmt, ...) do {               \
+    if (G_UNLIKELY(slirp_debug & DBG_MISC)) {   \
+        g_debug(fmt, ##__VA_ARGS__);            \
+    }                                           \
+} while (0)
+
+#define DEBUG_ERROR(fmt, ...) do {              \
+    if (G_UNLIKELY(slirp_debug & DBG_ERROR)) {  \
+        g_debug(fmt, ##__VA_ARGS__);            \
+    }                                           \
+} while (0)
+
+#define DEBUG_TFTP(fmt, ...) do {               \
+    if (G_UNLIKELY(slirp_debug & DBG_TFTP)) {   \
+        g_debug(fmt, ##__VA_ARGS__);            \
+    }                                           \
+} while (0)
+
+#endif /* DEBUG_H_ */
diff --git a/slirp/src/dhcpv6.c b/slirp/src/dhcpv6.c
new file mode 100644 (file)
index 0000000..e655c7d
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * SLIRP stateless DHCPv6
+ *
+ * We only support stateless DHCPv6, e.g. for network booting.
+ * See RFC 3315, RFC 3736, RFC 3646 and RFC 5970 for details.
+ *
+ * Copyright 2016 Thomas Huth, Red Hat Inc.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "slirp.h"
+#include "dhcpv6.h"
+
+/* DHCPv6 message types */
+#define MSGTYPE_REPLY        7
+#define MSGTYPE_INFO_REQUEST 11
+
+/* DHCPv6 option types */
+#define OPTION_CLIENTID      1
+#define OPTION_IAADDR        5
+#define OPTION_ORO           6
+#define OPTION_DNS_SERVERS   23
+#define OPTION_BOOTFILE_URL  59
+
+struct requested_infos {
+    uint8_t *client_id;
+    int client_id_len;
+    bool want_dns;
+    bool want_boot_url;
+};
+
+/**
+ * Analyze the info request message sent by the client to see what data it
+ * provided and what it wants to have. The information is gathered in the
+ * "requested_infos" struct. Note that client_id (if provided) points into
+ * the odata region, thus the caller must keep odata valid as long as it
+ * needs to access the requested_infos struct.
+ */
+static int dhcpv6_parse_info_request(Slirp *slirp, uint8_t *odata, int olen,
+                                     struct requested_infos *ri)
+{
+    int i, req_opt;
+
+    while (olen > 4) {
+        /* Parse one option */
+        int option = odata[0] << 8 | odata[1];
+        int len = odata[2] << 8 | odata[3];
+
+        if (len + 4 > olen) {
+            slirp->cb->guest_error("Guest sent bad DHCPv6 packet!", slirp->opaque);
+            return -E2BIG;
+        }
+
+        switch (option) {
+        case OPTION_IAADDR:
+            /* According to RFC3315, we must discard requests with IA option */
+            return -EINVAL;
+        case OPTION_CLIENTID:
+            if (len > 256) {
+                /* Avoid very long IDs which could cause problems later */
+                return -E2BIG;
+            }
+            ri->client_id = odata + 4;
+            ri->client_id_len = len;
+            break;
+        case OPTION_ORO:        /* Option request option */
+            if (len & 1) {
+                return -EINVAL;
+            }
+            /* Check which options the client wants to have */
+            for (i = 0; i < len; i += 2) {
+                req_opt = odata[4 + i] << 8 | odata[4 + i + 1];
+                switch (req_opt) {
+                case OPTION_DNS_SERVERS:
+                    ri->want_dns = true;
+                    break;
+                case OPTION_BOOTFILE_URL:
+                    ri->want_boot_url = true;
+                    break;
+                default:
+                    DEBUG_MISC("dhcpv6: Unsupported option request %d",
+                               req_opt);
+                }
+            }
+            break;
+        default:
+            DEBUG_MISC("dhcpv6 info req: Unsupported option %d, len=%d",
+                       option, len);
+        }
+
+        odata += len + 4;
+        olen -= len + 4;
+    }
+
+    return 0;
+}
+
+
+/**
+ * Handle information request messages
+ */
+static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas,
+                                uint32_t xid, uint8_t *odata, int olen)
+{
+    struct requested_infos ri = { NULL };
+    struct sockaddr_in6 sa6, da6;
+    struct mbuf *m;
+    uint8_t *resp;
+
+    if (dhcpv6_parse_info_request(slirp, odata, olen, &ri) < 0) {
+        return;
+    }
+
+    m = m_get(slirp);
+    if (!m) {
+        return;
+    }
+    memset(m->m_data, 0, m->m_size);
+    m->m_data += IF_MAXLINKHDR;
+    resp = (uint8_t *)m->m_data + sizeof(struct ip6) + sizeof(struct udphdr);
+
+    /* Fill in response */
+    *resp++ = MSGTYPE_REPLY;
+    *resp++ = (uint8_t)(xid >> 16);
+    *resp++ = (uint8_t)(xid >> 8);
+    *resp++ = (uint8_t)xid;
+
+    if (ri.client_id) {
+        *resp++ = OPTION_CLIENTID >> 8;         /* option-code high byte */
+        *resp++ = OPTION_CLIENTID;              /* option-code low byte */
+        *resp++ = ri.client_id_len >> 8;        /* option-len high byte */
+        *resp++ = ri.client_id_len;             /* option-len low byte */
+        memcpy(resp, ri.client_id, ri.client_id_len);
+        resp += ri.client_id_len;
+    }
+    if (ri.want_dns) {
+        *resp++ = OPTION_DNS_SERVERS >> 8;      /* option-code high byte */
+        *resp++ = OPTION_DNS_SERVERS;           /* option-code low byte */
+        *resp++ = 0;                            /* option-len high byte */
+        *resp++ = 16;                           /* option-len low byte */
+        memcpy(resp, &slirp->vnameserver_addr6, 16);
+        resp += 16;
+    }
+    if (ri.want_boot_url) {
+        uint8_t *sa = slirp->vhost_addr6.s6_addr;
+        int slen, smaxlen;
+
+        *resp++ = OPTION_BOOTFILE_URL >> 8;     /* option-code high byte */
+        *resp++ = OPTION_BOOTFILE_URL;          /* option-code low byte */
+        smaxlen = (uint8_t *)m->m_data + IF_MTU - (resp + 2);
+        slen = snprintf((char *)resp + 2, smaxlen,
+                        "tftp://[%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
+                                "%02x%02x:%02x%02x:%02x%02x:%02x%02x]/%s",
+                        sa[0], sa[1], sa[2], sa[3], sa[4], sa[5], sa[6], sa[7],
+                        sa[8], sa[9], sa[10], sa[11], sa[12], sa[13], sa[14],
+                        sa[15], slirp->bootp_filename);
+        slen = MIN(slen, smaxlen);
+        *resp++ = slen >> 8;                    /* option-len high byte */
+        *resp++ = slen;                         /* option-len low byte */
+        resp += slen;
+    }
+
+    sa6.sin6_addr = slirp->vhost_addr6;
+    sa6.sin6_port = DHCPV6_SERVER_PORT;
+    da6.sin6_addr = srcsas->sin6_addr;
+    da6.sin6_port = srcsas->sin6_port;
+    m->m_data += sizeof(struct ip6) + sizeof(struct udphdr);
+    m->m_len = resp - (uint8_t *)m->m_data;
+    udp6_output(NULL, m, &sa6, &da6);
+}
+
+/**
+ * Handle DHCPv6 messages sent by the client
+ */
+void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m)
+{
+    uint8_t *data = (uint8_t *)m->m_data + sizeof(struct udphdr);
+    int data_len = m->m_len - sizeof(struct udphdr);
+    uint32_t xid;
+
+    if (data_len < 4) {
+        return;
+    }
+
+    xid = ntohl(*(uint32_t *)data) & 0xffffff;
+
+    switch (data[0]) {
+    case MSGTYPE_INFO_REQUEST:
+        dhcpv6_info_request(m->slirp, srcsas, xid, &data[4], data_len - 4);
+        break;
+    default:
+        DEBUG_MISC("dhcpv6_input: Unsupported message type 0x%x", data[0]);
+    }
+}
diff --git a/slirp/src/dhcpv6.h b/slirp/src/dhcpv6.h
new file mode 100644 (file)
index 0000000..3373f6c
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Definitions and prototypes for SLIRP stateless DHCPv6
+ *
+ * Copyright 2016 Thomas Huth, Red Hat Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2
+ * or later. See the COPYING file in the top-level directory.
+ */
+#ifndef SLIRP_DHCPV6_H
+#define SLIRP_DHCPV6_H
+
+#define DHCPV6_SERVER_PORT 547
+
+#define ALLDHCP_MULTICAST { .s6_addr = \
+                            { 0xff, 0x02, 0x00, 0x00,\
+                            0x00, 0x00, 0x00, 0x00,\
+                            0x00, 0x00, 0x00, 0x00,\
+                            0x00, 0x01, 0x00, 0x02 } }
+
+#define in6_dhcp_multicast(a)\
+    in6_equal(a, &(struct in6_addr)ALLDHCP_MULTICAST)
+
+void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m);
+
+#endif
diff --git a/slirp/src/dnssearch.c b/slirp/src/dnssearch.c
new file mode 100644 (file)
index 0000000..c459cec
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * Domain search option for DHCP (RFC 3397)
+ *
+ * Copyright (c) 2012 Klaus Stengel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "slirp.h"
+
+static const uint8_t RFC3397_OPT_DOMAIN_SEARCH = 119;
+static const uint8_t MAX_OPT_LEN = 255;
+static const uint8_t OPT_HEADER_LEN = 2;
+static const uint8_t REFERENCE_LEN = 2;
+
+struct compact_domain;
+
+typedef struct compact_domain {
+    struct compact_domain *self;
+    struct compact_domain *refdom;
+    uint8_t *labels;
+    size_t len;
+    size_t common_octets;
+} CompactDomain;
+
+static size_t
+domain_suffix_diffoff(const CompactDomain *a, const CompactDomain *b)
+{
+    size_t la = a->len, lb = b->len;
+    uint8_t *da = a->labels + la, *db = b->labels + lb;
+    size_t i, lm = (la < lb) ? la : lb;
+
+    for (i = 0; i < lm; i++) {
+        da--; db--;
+        if (*da != *db) {
+            break;
+        }
+    }
+    return i;
+}
+
+static int domain_suffix_ord(const void *cva, const void *cvb)
+{
+    const CompactDomain *a = cva, *b = cvb;
+    size_t la = a->len, lb = b->len;
+    size_t doff = domain_suffix_diffoff(a, b);
+    uint8_t ca = a->labels[la - doff];
+    uint8_t cb = b->labels[lb - doff];
+
+    if (ca < cb) {
+        return -1;
+    }
+    if (ca > cb) {
+        return 1;
+    }
+    if (la < lb) {
+        return -1;
+    }
+    if (la > lb) {
+        return 1;
+    }
+    return 0;
+}
+
+static size_t domain_common_label(CompactDomain *a, CompactDomain *b)
+{
+    size_t res, doff = domain_suffix_diffoff(a, b);
+    uint8_t *first_eq_pos = a->labels + (a->len - doff);
+    uint8_t *label = a->labels;
+
+    while (*label && label < first_eq_pos) {
+        label += *label + 1;
+    }
+    res = a->len - (label - a->labels);
+    /* only report if it can help to reduce the packet size */
+    return (res > REFERENCE_LEN) ? res : 0;
+}
+
+static void domain_fixup_order(CompactDomain *cd, size_t n)
+{
+    size_t i;
+
+    for (i = 0; i < n; i++) {
+        CompactDomain *cur = cd + i, *next = cd[i].self;
+
+        while (!cur->common_octets) {
+            CompactDomain *tmp = next->self; /* backup target value */
+
+            next->self = cur;
+            cur->common_octets++;
+
+            cur = next;
+            next = tmp;
+        }
+    }
+}
+
+static void domain_mklabels(CompactDomain *cd, const char *input)
+{
+    uint8_t *len_marker = cd->labels;
+    uint8_t *output = len_marker; /* pre-incremented */
+    const char *in = input;
+    char cur_chr;
+    size_t len = 0;
+
+    if (cd->len == 0) {
+        goto fail;
+    }
+    cd->len++;
+
+    do {
+        cur_chr = *in++;
+        if (cur_chr == '.' || cur_chr == '\0') {
+            len = output - len_marker;
+            if ((len == 0 && cur_chr == '.') || len >= 64) {
+                goto fail;
+            }
+            *len_marker = len;
+
+            output++;
+            len_marker = output;
+        } else {
+            output++;
+            *output = cur_chr;
+        }
+    } while (cur_chr != '\0');
+
+    /* ensure proper zero-termination */
+    if (len != 0) {
+        *len_marker = 0;
+        cd->len++;
+    }
+    return;
+
+fail:
+    g_warning("failed to parse domain name '%s'\n", input);
+    cd->len = 0;
+}
+
+static void
+domain_mkxrefs(CompactDomain *doms, CompactDomain *last, size_t depth)
+{
+    CompactDomain *i = doms, *target = doms;
+
+    do {
+        if (i->labels < target->labels) {
+            target = i;
+        }
+    } while (i++ != last);
+
+    for (i = doms; i != last; i++) {
+        CompactDomain *group_last;
+        size_t next_depth;
+
+        if (i->common_octets == depth) {
+            continue;
+        }
+
+        next_depth = -1;
+        for (group_last = i; group_last != last; group_last++) {
+            size_t co = group_last->common_octets;
+            if (co <= depth) {
+                break;
+            }
+            if (co < next_depth) {
+                next_depth = co;
+            }
+        }
+        domain_mkxrefs(i, group_last, next_depth);
+
+        i = group_last;
+        if (i == last) {
+            break;
+        }
+    }
+
+    if (depth == 0) {
+        return;
+    }
+
+    i = doms;
+    do {
+        if (i != target && i->refdom == NULL) {
+            i->refdom = target;
+            i->common_octets = depth;
+        }
+    } while (i++ != last);
+}
+
+static size_t domain_compactify(CompactDomain *domains, size_t n)
+{
+    uint8_t *start = domains->self->labels, *outptr = start;
+    size_t i;
+
+    for (i = 0; i < n; i++) {
+        CompactDomain *cd = domains[i].self;
+        CompactDomain *rd = cd->refdom;
+
+        if (rd != NULL) {
+            size_t moff = (rd->labels - start)
+                    + (rd->len - cd->common_octets);
+            if (moff < 0x3FFFu) {
+                cd->len -= cd->common_octets - 2;
+                cd->labels[cd->len - 1] = moff & 0xFFu;
+                cd->labels[cd->len - 2] = 0xC0u | (moff >> 8);
+            }
+        }
+
+        if (cd->labels != outptr) {
+            memmove(outptr, cd->labels, cd->len);
+            cd->labels = outptr;
+        }
+        outptr += cd->len;
+    }
+    return outptr - start;
+}
+
+int translate_dnssearch(Slirp *s, const char **names)
+{
+    size_t blocks, bsrc_start, bsrc_end, bdst_start;
+    size_t i, num_domains, memreq = 0;
+    uint8_t *result = NULL, *outptr;
+    CompactDomain *domains = NULL;
+    const char **nameptr = names;
+
+    while (*nameptr != NULL) {
+        nameptr++;
+    }
+
+    num_domains = nameptr - names;
+    if (num_domains == 0) {
+        return -2;
+    }
+
+    domains = g_malloc(num_domains * sizeof(*domains));
+
+    for (i = 0; i < num_domains; i++) {
+        size_t nlen = strlen(names[i]);
+        memreq += nlen + 2; /* 1 zero octet + 1 label length octet */
+        domains[i].self = domains + i;
+        domains[i].len = nlen;
+        domains[i].common_octets = 0;
+        domains[i].refdom = NULL;
+    }
+
+    /* reserve extra 2 header bytes for each 255 bytes of output */
+    memreq += DIV_ROUND_UP(memreq, MAX_OPT_LEN) * OPT_HEADER_LEN;
+    result = g_malloc(memreq * sizeof(*result));
+
+    outptr = result;
+    for (i = 0; i < num_domains; i++) {
+        domains[i].labels = outptr;
+        domain_mklabels(domains + i, names[i]);
+        outptr += domains[i].len;
+    }
+
+    if (outptr == result) {
+        g_free(domains);
+        g_free(result);
+        return -1;
+    }
+
+    qsort(domains, num_domains, sizeof(*domains), domain_suffix_ord);
+    domain_fixup_order(domains, num_domains);
+
+    for (i = 1; i < num_domains; i++) {
+        size_t cl = domain_common_label(domains + i - 1, domains + i);
+        domains[i - 1].common_octets = cl;
+    }
+
+    domain_mkxrefs(domains, domains + num_domains - 1, 0);
+    memreq = domain_compactify(domains, num_domains);
+
+    blocks = DIV_ROUND_UP(memreq, MAX_OPT_LEN);
+    bsrc_end = memreq;
+    bsrc_start = (blocks - 1) * MAX_OPT_LEN;
+    bdst_start = bsrc_start + blocks * OPT_HEADER_LEN;
+    memreq += blocks * OPT_HEADER_LEN;
+
+    while (blocks--) {
+        size_t len = bsrc_end - bsrc_start;
+        memmove(result + bdst_start, result + bsrc_start, len);
+        result[bdst_start - 2] = RFC3397_OPT_DOMAIN_SEARCH;
+        result[bdst_start - 1] = len;
+        bsrc_end = bsrc_start;
+        bsrc_start -= MAX_OPT_LEN;
+        bdst_start -= MAX_OPT_LEN + OPT_HEADER_LEN;
+    }
+
+    g_free(domains);
+    s->vdnssearch = result;
+    s->vdnssearch_len = memreq;
+    return 0;
+}
diff --git a/slirp/src/if.c b/slirp/src/if.c
new file mode 100644 (file)
index 0000000..1830cc3
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include "slirp.h"
+
+static void
+ifs_insque(struct mbuf *ifm, struct mbuf *ifmhead)
+{
+       ifm->ifs_next = ifmhead->ifs_next;
+       ifmhead->ifs_next = ifm;
+       ifm->ifs_prev = ifmhead;
+       ifm->ifs_next->ifs_prev = ifm;
+}
+
+static void
+ifs_remque(struct mbuf *ifm)
+{
+       ifm->ifs_prev->ifs_next = ifm->ifs_next;
+       ifm->ifs_next->ifs_prev = ifm->ifs_prev;
+}
+
+void
+if_init(Slirp *slirp)
+{
+    slirp->if_fastq.qh_link = slirp->if_fastq.qh_rlink = &slirp->if_fastq;
+    slirp->if_batchq.qh_link = slirp->if_batchq.qh_rlink = &slirp->if_batchq;
+}
+
+/*
+ * if_output: Queue packet into an output queue.
+ * There are 2 output queue's, if_fastq and if_batchq.
+ * Each output queue is a doubly linked list of double linked lists
+ * of mbufs, each list belonging to one "session" (socket).  This
+ * way, we can output packets fairly by sending one packet from each
+ * session, instead of all the packets from one session, then all packets
+ * from the next session, etc.  Packets on the if_fastq get absolute
+ * priority, but if one session hogs the link, it gets "downgraded"
+ * to the batchq until it runs out of packets, then it'll return
+ * to the fastq (eg. if the user does an ls -alR in a telnet session,
+ * it'll temporarily get downgraded to the batchq)
+ */
+void
+if_output(struct socket *so, struct mbuf *ifm)
+{
+       Slirp *slirp = ifm->slirp;
+       struct mbuf *ifq;
+       int on_fastq = 1;
+
+       DEBUG_CALL("if_output");
+       DEBUG_ARG("so = %p", so);
+       DEBUG_ARG("ifm = %p", ifm);
+
+       /*
+        * First remove the mbuf from m_usedlist,
+        * since we're gonna use m_next and m_prev ourselves
+        * XXX Shouldn't need this, gotta change dtom() etc.
+        */
+       if (ifm->m_flags & M_USEDLIST) {
+               remque(ifm);
+               ifm->m_flags &= ~M_USEDLIST;
+       }
+
+       /*
+        * See if there's already a batchq list for this session.
+        * This can include an interactive session, which should go on fastq,
+        * but gets too greedy... hence it'll be downgraded from fastq to batchq.
+        * We mustn't put this packet back on the fastq (or we'll send it out of order)
+        * XXX add cache here?
+        */
+       if (so) {
+               for (ifq = (struct mbuf *) slirp->if_batchq.qh_rlink;
+                    (struct quehead *) ifq != &slirp->if_batchq;
+                    ifq = ifq->ifq_prev) {
+                       if (so == ifq->ifq_so) {
+                               /* A match! */
+                               ifm->ifq_so = so;
+                               ifs_insque(ifm, ifq->ifs_prev);
+                               goto diddit;
+                       }
+               }
+       }
+
+       /* No match, check which queue to put it on */
+       if (so && (so->so_iptos & IPTOS_LOWDELAY)) {
+               ifq = (struct mbuf *) slirp->if_fastq.qh_rlink;
+               on_fastq = 1;
+               /*
+                * Check if this packet is a part of the last
+                * packet's session
+                */
+               if (ifq->ifq_so == so) {
+                       ifm->ifq_so = so;
+                       ifs_insque(ifm, ifq->ifs_prev);
+                       goto diddit;
+               }
+        } else {
+               ifq = (struct mbuf *) slirp->if_batchq.qh_rlink;
+        }
+
+       /* Create a new doubly linked list for this session */
+       ifm->ifq_so = so;
+       ifs_init(ifm);
+       insque(ifm, ifq);
+
+diddit:
+       if (so) {
+               /* Update *_queued */
+               so->so_queued++;
+               so->so_nqueued++;
+               /*
+                * Check if the interactive session should be downgraded to
+                * the batchq.  A session is downgraded if it has queued 6
+                * packets without pausing, and at least 3 of those packets
+                * have been sent over the link
+                * (XXX These are arbitrary numbers, probably not optimal..)
+                */
+               if (on_fastq && ((so->so_nqueued >= 6) &&
+                                (so->so_nqueued - so->so_queued) >= 3)) {
+
+                       /* Remove from current queue... */
+                       remque(ifm->ifs_next);
+
+                       /* ...And insert in the new.  That'll teach ya! */
+                       insque(ifm->ifs_next, &slirp->if_batchq);
+               }
+       }
+
+       /*
+        * This prevents us from malloc()ing too many mbufs
+        */
+       if_start(ifm->slirp);
+}
+
+/*
+ * Send one packet from each session.
+ * If there are packets on the fastq, they are sent FIFO, before
+ * everything else.  Then we choose the first packet from each
+ * batchq session (socket) and send it.
+ * For example, if there are 3 ftp sessions fighting for bandwidth,
+ * one packet will be sent from the first session, then one packet
+ * from the second session, then one packet from the third.
+ */
+void if_start(Slirp *slirp)
+{
+    uint64_t now = slirp->cb->clock_get_ns(slirp->opaque);
+    bool from_batchq = false;
+    struct mbuf *ifm, *ifm_next, *ifqt;
+
+    DEBUG_CALL("if_start");
+
+    if (slirp->if_start_busy) {
+        return;
+    }
+    slirp->if_start_busy = true;
+
+    struct mbuf *batch_head = NULL;
+    if (slirp->if_batchq.qh_link != &slirp->if_batchq) {
+        batch_head = (struct mbuf *) slirp->if_batchq.qh_link;
+    }
+
+    if (slirp->if_fastq.qh_link != &slirp->if_fastq) {
+        ifm_next = (struct mbuf *) slirp->if_fastq.qh_link;
+    } else if (batch_head) {
+        /* Nothing on fastq, pick up from batchq */
+        ifm_next = batch_head;
+        from_batchq = true;
+    } else {
+        ifm_next = NULL;
+    }
+
+    while (ifm_next) {
+        ifm = ifm_next;
+
+        ifm_next = ifm->ifq_next;
+        if ((struct quehead *) ifm_next == &slirp->if_fastq) {
+            /* No more packets in fastq, switch to batchq */
+            ifm_next = batch_head;
+            from_batchq = true;
+        }
+        if ((struct quehead *) ifm_next == &slirp->if_batchq) {
+            /* end of batchq */
+            ifm_next = NULL;
+        }
+
+        /* Try to send packet unless it already expired */
+        if (ifm->expiration_date >= now && !if_encap(slirp, ifm)) {
+            /* Packet is delayed due to pending ARP or NDP resolution */
+            continue;
+        }
+
+        /* Remove it from the queue */
+        ifqt = ifm->ifq_prev;
+        remque(ifm);
+
+        /* If there are more packets for this session, re-queue them */
+        if (ifm->ifs_next != ifm) {
+            struct mbuf *next = ifm->ifs_next;
+
+            insque(next, ifqt);
+            ifs_remque(ifm);
+            if (!from_batchq) {
+                ifm_next = next;
+            }
+        }
+
+        /* Update so_queued */
+        if (ifm->ifq_so && --ifm->ifq_so->so_queued == 0) {
+            /* If there's no more queued, reset nqueued */
+            ifm->ifq_so->so_nqueued = 0;
+        }
+
+        m_free(ifm);
+    }
+
+    slirp->if_start_busy = false;
+}
diff --git a/slirp/src/if.h b/slirp/src/if.h
new file mode 100644 (file)
index 0000000..69569c1
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef IF_H
+#define IF_H
+
+#define IF_COMPRESS    0x01    /* We want compression */
+#define IF_NOCOMPRESS  0x02    /* Do not do compression */
+#define IF_AUTOCOMP    0x04    /* Autodetect (default) */
+#define IF_NOCIDCOMP   0x08    /* CID compression */
+
+#define IF_MTU 1500
+#define IF_MRU 1500
+#define        IF_COMP IF_AUTOCOMP     /* Flags for compression */
+
+/* 2 for alignment, 14 for ethernet */
+#define IF_MAXLINKHDR (2 + ETH_HLEN)
+
+#endif
diff --git a/slirp/src/ip.h b/slirp/src/ip.h
new file mode 100644 (file)
index 0000000..73a4d2a
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 1982, 1986, 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. 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.
+ *
+ *     @(#)ip.h        8.1 (Berkeley) 6/10/93
+ * ip.h,v 1.3 1994/08/21 05:27:30 paul Exp
+ */
+
+#ifndef IP_H
+#define IP_H
+
+#include <glib.h>
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+# undef NTOHL
+# undef NTOHS
+# undef HTONL
+# undef HTONS
+# define NTOHL(d)
+# define NTOHS(d)
+# define HTONL(d)
+# define HTONS(d)
+#else
+# ifndef NTOHL
+#  define NTOHL(d) ((d) = ntohl((d)))
+# endif
+# ifndef NTOHS
+#  define NTOHS(d) ((d) = ntohs((uint16_t)(d)))
+# endif
+# ifndef HTONL
+#  define HTONL(d) ((d) = htonl((d)))
+# endif
+# ifndef HTONS
+#  define HTONS(d) ((d) = htons((uint16_t)(d)))
+# endif
+#endif
+
+typedef uint32_t n_long;                 /* long as received from the net */
+
+/*
+ * Definitions for internet protocol version 4.
+ * Per RFC 791, September 1981.
+ */
+#define        IPVERSION       4
+
+/*
+ * Structure of an internet header, naked of options.
+ */
+struct ip {
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+       uint8_t ip_v:4,                 /* version */
+               ip_hl:4;                /* header length */
+#else
+       uint8_t ip_hl:4,                /* header length */
+               ip_v:4;                 /* version */
+#endif
+       uint8_t         ip_tos;                 /* type of service */
+       uint16_t        ip_len;                 /* total length */
+       uint16_t        ip_id;                  /* identification */
+       uint16_t        ip_off;                 /* fragment offset field */
+#define        IP_DF 0x4000                    /* don't fragment flag */
+#define        IP_MF 0x2000                    /* more fragments flag */
+#define        IP_OFFMASK 0x1fff               /* mask for fragmenting bits */
+       uint8_t ip_ttl;                 /* time to live */
+       uint8_t ip_p;                   /* protocol */
+       uint16_t        ip_sum;                 /* checksum */
+       struct  in_addr ip_src,ip_dst;  /* source and dest address */
+} SLIRP_PACKED;
+
+#define        IP_MAXPACKET    65535           /* maximum packet size */
+
+/*
+ * Definitions for IP type of service (ip_tos)
+ */
+#define        IPTOS_LOWDELAY          0x10
+#define        IPTOS_THROUGHPUT        0x08
+#define        IPTOS_RELIABILITY       0x04
+
+/*
+ * Definitions for options.
+ */
+#define        IPOPT_COPIED(o)         ((o)&0x80)
+#define        IPOPT_CLASS(o)          ((o)&0x60)
+#define        IPOPT_NUMBER(o)         ((o)&0x1f)
+
+#define        IPOPT_CONTROL           0x00
+#define        IPOPT_RESERVED1         0x20
+#define        IPOPT_DEBMEAS           0x40
+#define        IPOPT_RESERVED2         0x60
+
+#define        IPOPT_EOL               0               /* end of option list */
+#define        IPOPT_NOP               1               /* no operation */
+
+#define        IPOPT_RR                7               /* record packet route */
+#define        IPOPT_TS                68              /* timestamp */
+#define        IPOPT_SECURITY          130             /* provide s,c,h,tcc */
+#define        IPOPT_LSRR              131             /* loose source route */
+#define        IPOPT_SATID             136             /* satnet id */
+#define        IPOPT_SSRR              137             /* strict source route */
+
+/*
+ * Offsets to fields in options other than EOL and NOP.
+ */
+#define        IPOPT_OPTVAL            0               /* option ID */
+#define        IPOPT_OLEN              1               /* option length */
+#define IPOPT_OFFSET           2               /* offset within option */
+#define        IPOPT_MINOFF            4               /* min value of above */
+
+/*
+ * Time stamp option structure.
+ */
+struct ip_timestamp {
+       uint8_t ipt_code;               /* IPOPT_TS */
+       uint8_t ipt_len;                /* size of structure (variable) */
+       uint8_t ipt_ptr;                /* index of current entry */
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+       uint8_t ipt_oflw:4,             /* overflow counter */
+               ipt_flg:4;              /* flags, see below */
+#else
+       uint8_t ipt_flg:4,              /* flags, see below */
+               ipt_oflw:4;             /* overflow counter */
+#endif
+       union ipt_timestamp {
+               n_long  ipt_time[1];
+               struct  ipt_ta {
+                       struct in_addr ipt_addr;
+                       n_long ipt_time;
+               } ipt_ta[1];
+       } ipt_timestamp;
+} SLIRP_PACKED;
+
+/* flag bits for ipt_flg */
+#define        IPOPT_TS_TSONLY         0               /* timestamps only */
+#define        IPOPT_TS_TSANDADDR      1               /* timestamps and addresses */
+#define        IPOPT_TS_PRESPEC        3               /* specified modules only */
+
+/* bits for security (not byte swapped) */
+#define        IPOPT_SECUR_UNCLASS     0x0000
+#define        IPOPT_SECUR_CONFID      0xf135
+#define        IPOPT_SECUR_EFTO        0x789a
+#define        IPOPT_SECUR_MMMM        0xbc4d
+#define        IPOPT_SECUR_RESTR       0xaf13
+#define        IPOPT_SECUR_SECRET      0xd788
+#define        IPOPT_SECUR_TOPSECRET   0x6bc5
+
+/*
+ * Internet implementation parameters.
+ */
+#define        MAXTTL          255             /* maximum time to live (seconds) */
+#define        IPDEFTTL        64              /* default ttl, from RFC 1340 */
+#define        IPFRAGTTL       60              /* time to live for frags, slowhz */
+#define        IPTTLDEC        1               /* subtracted when forwarding */
+
+#define        IP_MSS          576             /* default maximum segment size */
+
+#if GLIB_SIZEOF_VOID_P == 4
+struct mbuf_ptr {
+       struct mbuf *mptr;
+       uint32_t dummy;
+} SLIRP_PACKED;
+#else
+struct mbuf_ptr {
+       struct mbuf *mptr;
+} SLIRP_PACKED;
+#endif
+struct qlink {
+       void *next, *prev;
+};
+
+/*
+ * Overlay for ip header used by other protocols (tcp, udp).
+ */
+struct ipovly {
+       struct mbuf_ptr ih_mbuf;        /* backpointer to mbuf */
+       uint8_t ih_x1;                  /* (unused) */
+       uint8_t ih_pr;                  /* protocol */
+       uint16_t        ih_len;                 /* protocol length */
+       struct  in_addr ih_src;         /* source internet address */
+       struct  in_addr ih_dst;         /* destination internet address */
+} SLIRP_PACKED;
+
+/*
+ * Ip reassembly queue structure.  Each fragment
+ * being reassembled is attached to one of these structures.
+ * They are timed out after ipq_ttl drops to 0, and may also
+ * be reclaimed if memory becomes tight.
+ * size 28 bytes
+ */
+struct ipq {
+        struct qlink frag_link;                        /* to ip headers of fragments */
+       struct qlink ip_link;                           /* to other reass headers */
+       uint8_t ipq_ttl;                /* time for reass q to live */
+       uint8_t ipq_p;                  /* protocol of this fragment */
+       uint16_t        ipq_id;                 /* sequence id for reassembly */
+       struct  in_addr ipq_src,ipq_dst;
+};
+
+/*
+ * Ip header, when holding a fragment.
+ *
+ * Note: ipf_link must be at same offset as frag_link above
+ */
+struct ipasfrag {
+       struct qlink ipf_link;
+       struct ip ipf_ip;
+};
+
+G_STATIC_ASSERT(offsetof(struct ipq, frag_link) ==
+                offsetof(struct ipasfrag, ipf_link));
+
+#define ipf_off      ipf_ip.ip_off
+#define ipf_tos      ipf_ip.ip_tos
+#define ipf_len      ipf_ip.ip_len
+#define ipf_next     ipf_link.next
+#define ipf_prev     ipf_link.prev
+
+#endif
diff --git a/slirp/src/ip6.h b/slirp/src/ip6.h
new file mode 100644 (file)
index 0000000..1b3364f
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ */
+
+#ifndef SLIRP_IP6_H
+#define SLIRP_IP6_H
+
+#include <glib.h>
+#include <string.h>
+
+#define ALLNODES_MULTICAST  { .s6_addr = \
+                            { 0xff, 0x02, 0x00, 0x00,\
+                            0x00, 0x00, 0x00, 0x00,\
+                            0x00, 0x00, 0x00, 0x00,\
+                            0x00, 0x00, 0x00, 0x01 } }
+
+#define SOLICITED_NODE_PREFIX { .s6_addr = \
+                            { 0xff, 0x02, 0x00, 0x00,\
+                            0x00, 0x00, 0x00, 0x00,\
+                            0x00, 0x00, 0x00, 0x01,\
+                            0xff, 0x00, 0x00, 0x00 } }
+
+#define LINKLOCAL_ADDR  { .s6_addr = \
+                        { 0xfe, 0x80, 0x00, 0x00,\
+                        0x00, 0x00, 0x00, 0x00,\
+                        0x00, 0x00, 0x00, 0x00,\
+                        0x00, 0x00, 0x00, 0x02 } }
+
+#define ZERO_ADDR  { .s6_addr = \
+                        { 0x00, 0x00, 0x00, 0x00,\
+                        0x00, 0x00, 0x00, 0x00,\
+                        0x00, 0x00, 0x00, 0x00,\
+                        0x00, 0x00, 0x00, 0x00 } }
+
+static inline bool in6_equal(const struct in6_addr *a, const struct in6_addr *b)
+{
+    return memcmp(a, b, sizeof(*a)) == 0;
+}
+
+static inline bool in6_equal_net(const struct in6_addr *a,
+                                 const struct in6_addr *b,
+                                 int prefix_len)
+{
+    if (memcmp(a, b, prefix_len / 8) != 0) {
+        return 0;
+    }
+
+    if (prefix_len % 8 == 0) {
+        return 1;
+    }
+
+    return a->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8))
+        == b->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8));
+}
+
+static inline bool in6_equal_mach(const struct in6_addr *a,
+                                  const struct in6_addr *b,
+                                  int prefix_len)
+{
+    if (memcmp(&(a->s6_addr[DIV_ROUND_UP(prefix_len, 8)]),
+               &(b->s6_addr[DIV_ROUND_UP(prefix_len, 8)]),
+               16 - DIV_ROUND_UP(prefix_len, 8)) != 0) {
+        return 0;
+    }
+
+    if (prefix_len % 8 == 0) {
+        return 1;
+    }
+
+    return (a->s6_addr[prefix_len / 8] & ((1U << (8 - (prefix_len % 8))) - 1))
+        == (b->s6_addr[prefix_len / 8] & ((1U << (8 - (prefix_len % 8))) - 1));
+}
+
+
+#define in6_equal_router(a)\
+    ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len)\
+      && in6_equal_mach(a, &slirp->vhost_addr6, slirp->vprefix_len))\
+  || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64)\
+      && in6_equal_mach(a, &slirp->vhost_addr6, 64)))
+
+#define in6_equal_dns(a)\
+    ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len)\
+      && in6_equal_mach(a, &slirp->vnameserver_addr6, slirp->vprefix_len))\
+  || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64)\
+      && in6_equal_mach(a, &slirp->vnameserver_addr6, 64)))
+
+#define in6_equal_host(a)\
+    (in6_equal_router(a) || in6_equal_dns(a))
+
+#define in6_solicitednode_multicast(a)\
+    (in6_equal_net(a, &(struct in6_addr)SOLICITED_NODE_PREFIX, 104))
+
+#define in6_zero(a)\
+    (in6_equal(a, &(struct in6_addr)ZERO_ADDR))
+
+/* Compute emulated host MAC address from its ipv6 address */
+static inline void in6_compute_ethaddr(struct in6_addr ip,
+                                       uint8_t eth[ETH_ALEN])
+{
+    eth[0] = 0x52;
+    eth[1] = 0x56;
+    memcpy(&eth[2], &ip.s6_addr[16 - (ETH_ALEN - 2)], ETH_ALEN - 2);
+}
+
+/*
+ * Definitions for internet protocol version 6.
+ * Per RFC 2460, December 1998.
+ */
+#define IP6VERSION      6
+#define IP6_HOP_LIMIT 255
+
+/*
+ * Structure of an internet header, naked of options.
+ */
+struct ip6 {
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+    uint32_t
+        ip_v:4,         /* version */
+        ip_tc_hi:4,     /* traffic class */
+        ip_tc_lo:4,
+        ip_fl_hi:4,     /* flow label */
+        ip_fl_lo:16;
+#else
+    uint32_t
+        ip_tc_hi:4,
+        ip_v:4,
+        ip_fl_hi:4,
+        ip_tc_lo:4,
+        ip_fl_lo:16;
+#endif
+    uint16_t    ip_pl;               /* payload length */
+    uint8_t     ip_nh;               /* next header */
+    uint8_t     ip_hl;               /* hop limit */
+    struct in6_addr ip_src, ip_dst;  /* source and dest address */
+};
+
+/*
+ * IPv6 pseudo-header used by upper-layer protocols
+ */
+struct ip6_pseudohdr {
+    struct      in6_addr ih_src;  /* source internet address */
+    struct      in6_addr ih_dst;  /* destination internet address */
+    uint32_t    ih_pl;            /* upper-layer packet length */
+    uint16_t    ih_zero_hi;       /* zero */
+    uint8_t     ih_zero_lo;       /* zero */
+    uint8_t     ih_nh;            /* next header */
+};
+
+/*
+ * We don't want to mark these ip6 structs as packed as they are naturally
+ * correctly aligned; instead assert that there is no stray padding.
+ * If we marked the struct as packed then we would be unable to take
+ * the address of any of the fields in it.
+ */
+G_STATIC_ASSERT(sizeof(struct ip6) == 40);
+G_STATIC_ASSERT(sizeof(struct ip6_pseudohdr) == 40);
+
+#endif
diff --git a/slirp/src/ip6_icmp.c b/slirp/src/ip6_icmp.c
new file mode 100644 (file)
index 0000000..c1e3d30
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ */
+
+#include "slirp.h"
+#include "ip6_icmp.h"
+
+#define NDP_Interval g_rand_int_range(slirp->grand, \
+        NDP_MinRtrAdvInterval, NDP_MaxRtrAdvInterval)
+
+static void ra_timer_handler(void *opaque)
+{
+    Slirp *slirp = opaque;
+
+    slirp->cb->timer_mod(slirp->ra_timer,
+        slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS + NDP_Interval,
+        slirp->opaque);
+    ndp_send_ra(slirp);
+}
+
+void icmp6_init(Slirp *slirp)
+{
+    if (!slirp->in6_enabled) {
+        return;
+    }
+
+    slirp->ra_timer = slirp->cb->timer_new(ra_timer_handler, slirp, slirp->opaque);
+    slirp->cb->timer_mod(slirp->ra_timer,
+        slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS + NDP_Interval,
+        slirp->opaque);
+}
+
+void icmp6_cleanup(Slirp *slirp)
+{
+    if (!slirp->in6_enabled) {
+        return;
+    }
+
+    slirp->cb->timer_free(slirp->ra_timer, slirp->opaque);
+}
+
+static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
+        struct icmp6 *icmp)
+{
+    struct mbuf *t = m_get(slirp);
+    t->m_len = sizeof(struct ip6) + ntohs(ip->ip_pl);
+    memcpy(t->m_data, m->m_data, t->m_len);
+
+    /* IPv6 Packet */
+    struct ip6 *rip = mtod(t, struct ip6 *);
+    rip->ip_dst = ip->ip_src;
+    rip->ip_src = ip->ip_dst;
+
+    /* ICMPv6 packet */
+    t->m_data += sizeof(struct ip6);
+    struct icmp6 *ricmp = mtod(t, struct icmp6 *);
+    ricmp->icmp6_type = ICMP6_ECHO_REPLY;
+    ricmp->icmp6_cksum = 0;
+
+    /* Checksum */
+    t->m_data -= sizeof(struct ip6);
+    ricmp->icmp6_cksum = ip6_cksum(t);
+
+    ip6_output(NULL, t, 0);
+}
+
+void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
+{
+    Slirp *slirp = m->slirp;
+    struct mbuf *t;
+    struct ip6 *ip = mtod(m, struct ip6 *);
+    char addrstr[INET6_ADDRSTRLEN];
+
+    DEBUG_CALL("icmp6_send_error");
+    DEBUG_ARG("type = %d, code = %d", type, code);
+
+    if (IN6_IS_ADDR_MULTICAST(&ip->ip_src) ||
+            in6_zero(&ip->ip_src)) {
+        /* TODO icmp error? */
+        return;
+    }
+
+    t = m_get(slirp);
+
+    /* IPv6 packet */
+    struct ip6 *rip = mtod(t, struct ip6 *);
+    rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
+    rip->ip_dst = ip->ip_src;
+    inet_ntop(AF_INET6, &rip->ip_dst, addrstr, INET6_ADDRSTRLEN);
+    DEBUG_ARG("target = %s", addrstr);
+
+    rip->ip_nh = IPPROTO_ICMPV6;
+    const int error_data_len = MIN(m->m_len,
+            IF_MTU - (sizeof(struct ip6) + ICMP6_ERROR_MINLEN));
+    rip->ip_pl = htons(ICMP6_ERROR_MINLEN + error_data_len);
+    t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
+
+    /* ICMPv6 packet */
+    t->m_data += sizeof(struct ip6);
+    struct icmp6 *ricmp = mtod(t, struct icmp6 *);
+    ricmp->icmp6_type = type;
+    ricmp->icmp6_code = code;
+    ricmp->icmp6_cksum = 0;
+
+    switch (type) {
+    case ICMP6_UNREACH:
+    case ICMP6_TIMXCEED:
+        ricmp->icmp6_err.unused = 0;
+        break;
+    case ICMP6_TOOBIG:
+        ricmp->icmp6_err.mtu = htonl(IF_MTU);
+        break;
+    case ICMP6_PARAMPROB:
+        /* TODO: Handle this case */
+        break;
+    default:
+        g_assert_not_reached();
+        break;
+    }
+    t->m_data += ICMP6_ERROR_MINLEN;
+    memcpy(t->m_data, m->m_data, error_data_len);
+
+    /* Checksum */
+    t->m_data -= ICMP6_ERROR_MINLEN;
+    t->m_data -= sizeof(struct ip6);
+    ricmp->icmp6_cksum = ip6_cksum(t);
+
+    ip6_output(NULL, t, 0);
+}
+
+/*
+ * Send NDP Router Advertisement
+ */
+void ndp_send_ra(Slirp *slirp)
+{
+    DEBUG_CALL("ndp_send_ra");
+
+    /* Build IPv6 packet */
+    struct mbuf *t = m_get(slirp);
+    struct ip6 *rip = mtod(t, struct ip6 *);
+    size_t pl_size = 0;
+    struct in6_addr addr;
+    uint32_t scope_id;
+
+    rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
+    rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
+    rip->ip_nh = IPPROTO_ICMPV6;
+
+    /* Build ICMPv6 packet */
+    t->m_data += sizeof(struct ip6);
+    struct icmp6 *ricmp = mtod(t, struct icmp6 *);
+    ricmp->icmp6_type = ICMP6_NDP_RA;
+    ricmp->icmp6_code = 0;
+    ricmp->icmp6_cksum = 0;
+
+    /* NDP */
+    ricmp->icmp6_nra.chl = NDP_AdvCurHopLimit;
+    ricmp->icmp6_nra.M = NDP_AdvManagedFlag;
+    ricmp->icmp6_nra.O = NDP_AdvOtherConfigFlag;
+    ricmp->icmp6_nra.reserved = 0;
+    ricmp->icmp6_nra.lifetime = htons(NDP_AdvDefaultLifetime);
+    ricmp->icmp6_nra.reach_time = htonl(NDP_AdvReachableTime);
+    ricmp->icmp6_nra.retrans_time = htonl(NDP_AdvRetransTime);
+    t->m_data += ICMP6_NDP_RA_MINLEN;
+    pl_size += ICMP6_NDP_RA_MINLEN;
+
+    /* Source link-layer address (NDP option) */
+    struct ndpopt *opt = mtod(t, struct ndpopt *);
+    opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
+    opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
+    in6_compute_ethaddr(rip->ip_src, opt->ndpopt_linklayer);
+    t->m_data += NDPOPT_LINKLAYER_LEN;
+    pl_size += NDPOPT_LINKLAYER_LEN;
+
+    /* Prefix information (NDP option) */
+    struct ndpopt *opt2 = mtod(t, struct ndpopt *);
+    opt2->ndpopt_type = NDPOPT_PREFIX_INFO;
+    opt2->ndpopt_len = NDPOPT_PREFIXINFO_LEN / 8;
+    opt2->ndpopt_prefixinfo.prefix_length = slirp->vprefix_len;
+    opt2->ndpopt_prefixinfo.L = 1;
+    opt2->ndpopt_prefixinfo.A = 1;
+    opt2->ndpopt_prefixinfo.reserved1 = 0;
+    opt2->ndpopt_prefixinfo.valid_lt = htonl(NDP_AdvValidLifetime);
+    opt2->ndpopt_prefixinfo.pref_lt = htonl(NDP_AdvPrefLifetime);
+    opt2->ndpopt_prefixinfo.reserved2 = 0;
+    opt2->ndpopt_prefixinfo.prefix = slirp->vprefix_addr6;
+    t->m_data += NDPOPT_PREFIXINFO_LEN;
+    pl_size += NDPOPT_PREFIXINFO_LEN;
+
+    /* Prefix information (NDP option) */
+    if (get_dns6_addr(&addr, &scope_id) >= 0) {
+        /* Host system does have an IPv6 DNS server, announce our proxy.  */
+        struct ndpopt *opt3 = mtod(t, struct ndpopt *);
+        opt3->ndpopt_type = NDPOPT_RDNSS;
+        opt3->ndpopt_len = NDPOPT_RDNSS_LEN / 8;
+        opt3->ndpopt_rdnss.reserved = 0;
+        opt3->ndpopt_rdnss.lifetime = htonl(2 * NDP_MaxRtrAdvInterval);
+        opt3->ndpopt_rdnss.addr = slirp->vnameserver_addr6;
+        t->m_data += NDPOPT_RDNSS_LEN;
+        pl_size += NDPOPT_RDNSS_LEN;
+    }
+
+    rip->ip_pl = htons(pl_size);
+    t->m_data -= sizeof(struct ip6) + pl_size;
+    t->m_len = sizeof(struct ip6) + pl_size;
+
+    /* ICMPv6 Checksum */
+    ricmp->icmp6_cksum = ip6_cksum(t);
+
+    ip6_output(NULL, t, 0);
+}
+
+/*
+ * Send NDP Neighbor Solitication
+ */
+void ndp_send_ns(Slirp *slirp, struct in6_addr addr)
+{
+    char addrstr[INET6_ADDRSTRLEN];
+
+    inet_ntop(AF_INET6, &addr, addrstr, INET6_ADDRSTRLEN);
+
+    DEBUG_CALL("ndp_send_ns");
+    DEBUG_ARG("target = %s", addrstr);
+
+    /* Build IPv6 packet */
+    struct mbuf *t = m_get(slirp);
+    struct ip6 *rip = mtod(t, struct ip6 *);
+    rip->ip_src = slirp->vhost_addr6;
+    rip->ip_dst = (struct in6_addr)SOLICITED_NODE_PREFIX;
+    memcpy(&rip->ip_dst.s6_addr[13], &addr.s6_addr[13], 3);
+    rip->ip_nh = IPPROTO_ICMPV6;
+    rip->ip_pl = htons(ICMP6_NDP_NS_MINLEN + NDPOPT_LINKLAYER_LEN);
+    t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
+
+    /* Build ICMPv6 packet */
+    t->m_data += sizeof(struct ip6);
+    struct icmp6 *ricmp = mtod(t, struct icmp6 *);
+    ricmp->icmp6_type = ICMP6_NDP_NS;
+    ricmp->icmp6_code = 0;
+    ricmp->icmp6_cksum = 0;
+
+    /* NDP */
+    ricmp->icmp6_nns.reserved = 0;
+    ricmp->icmp6_nns.target = addr;
+
+    /* Build NDP option */
+    t->m_data += ICMP6_NDP_NS_MINLEN;
+    struct ndpopt *opt = mtod(t, struct ndpopt *);
+    opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
+    opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
+    in6_compute_ethaddr(slirp->vhost_addr6, opt->ndpopt_linklayer);
+
+    /* ICMPv6 Checksum */
+    t->m_data -= ICMP6_NDP_NA_MINLEN;
+    t->m_data -= sizeof(struct ip6);
+    ricmp->icmp6_cksum = ip6_cksum(t);
+
+    ip6_output(NULL, t, 1);
+}
+
+/*
+ * Send NDP Neighbor Advertisement
+ */
+static void ndp_send_na(Slirp *slirp, struct ip6 *ip, struct icmp6 *icmp)
+{
+    /* Build IPv6 packet */
+    struct mbuf *t = m_get(slirp);
+    struct ip6 *rip = mtod(t, struct ip6 *);
+    rip->ip_src = icmp->icmp6_nns.target;
+    if (in6_zero(&ip->ip_src)) {
+        rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
+    } else {
+        rip->ip_dst = ip->ip_src;
+    }
+    rip->ip_nh = IPPROTO_ICMPV6;
+    rip->ip_pl = htons(ICMP6_NDP_NA_MINLEN
+                        + NDPOPT_LINKLAYER_LEN);
+    t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
+
+    /* Build ICMPv6 packet */
+    t->m_data += sizeof(struct ip6);
+    struct icmp6 *ricmp = mtod(t, struct icmp6 *);
+    ricmp->icmp6_type = ICMP6_NDP_NA;
+    ricmp->icmp6_code = 0;
+    ricmp->icmp6_cksum = 0;
+
+    /* NDP */
+    ricmp->icmp6_nna.R = NDP_IsRouter;
+    ricmp->icmp6_nna.S = !IN6_IS_ADDR_MULTICAST(&rip->ip_dst);
+    ricmp->icmp6_nna.O = 1;
+    ricmp->icmp6_nna.reserved_hi = 0;
+    ricmp->icmp6_nna.reserved_lo = 0;
+    ricmp->icmp6_nna.target = icmp->icmp6_nns.target;
+
+    /* Build NDP option */
+    t->m_data += ICMP6_NDP_NA_MINLEN;
+    struct ndpopt *opt = mtod(t, struct ndpopt *);
+    opt->ndpopt_type = NDPOPT_LINKLAYER_TARGET;
+    opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
+    in6_compute_ethaddr(ricmp->icmp6_nna.target,
+                    opt->ndpopt_linklayer);
+
+    /* ICMPv6 Checksum */
+    t->m_data -= ICMP6_NDP_NA_MINLEN;
+    t->m_data -= sizeof(struct ip6);
+    ricmp->icmp6_cksum = ip6_cksum(t);
+
+    ip6_output(NULL, t, 0);
+}
+
+/*
+ * Process a NDP message
+ */
+static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
+        struct icmp6 *icmp)
+{
+    m->m_len += ETH_HLEN;
+    m->m_data -= ETH_HLEN;
+    struct ethhdr *eth = mtod(m, struct ethhdr *);
+    m->m_len -= ETH_HLEN;
+    m->m_data += ETH_HLEN;
+
+    switch (icmp->icmp6_type) {
+    case ICMP6_NDP_RS:
+        DEBUG_CALL(" type = Router Solicitation");
+        if (ip->ip_hl == 255
+                && icmp->icmp6_code == 0
+                && ntohs(ip->ip_pl) >= ICMP6_NDP_RS_MINLEN) {
+            /* Gratuitous NDP */
+            ndp_table_add(slirp, ip->ip_src, eth->h_source);
+
+            ndp_send_ra(slirp);
+        }
+        break;
+
+    case ICMP6_NDP_RA:
+        DEBUG_CALL(" type = Router Advertisement");
+        slirp->cb->guest_error("Warning: guest sent NDP RA, but shouldn't",
+                               slirp->opaque);
+        break;
+
+    case ICMP6_NDP_NS:
+        DEBUG_CALL(" type = Neighbor Solicitation");
+        if (ip->ip_hl == 255
+                && icmp->icmp6_code == 0
+                && !IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nns.target)
+                && ntohs(ip->ip_pl) >= ICMP6_NDP_NS_MINLEN
+                && (!in6_zero(&ip->ip_src)
+                    || in6_solicitednode_multicast(&ip->ip_dst))) {
+            if (in6_equal_host(&icmp->icmp6_nns.target)) {
+                /* Gratuitous NDP */
+                ndp_table_add(slirp, ip->ip_src, eth->h_source);
+                ndp_send_na(slirp, ip, icmp);
+            }
+        }
+        break;
+
+    case ICMP6_NDP_NA:
+        DEBUG_CALL(" type = Neighbor Advertisement");
+        if (ip->ip_hl == 255
+                && icmp->icmp6_code == 0
+                && ntohs(ip->ip_pl) >= ICMP6_NDP_NA_MINLEN
+                && !IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nna.target)
+                && (!IN6_IS_ADDR_MULTICAST(&ip->ip_dst)
+                    || icmp->icmp6_nna.S == 0)) {
+            ndp_table_add(slirp, ip->ip_src, eth->h_source);
+        }
+        break;
+
+    case ICMP6_NDP_REDIRECT:
+        DEBUG_CALL(" type = Redirect");
+        slirp->cb->guest_error(
+            "Warning: guest sent NDP REDIRECT, but shouldn't", slirp->opaque);
+        break;
+    }
+}
+
+/*
+ * Process a received ICMPv6 message.
+ */
+void icmp6_input(struct mbuf *m)
+{
+    struct icmp6 *icmp;
+    struct ip6 *ip = mtod(m, struct ip6 *);
+    Slirp *slirp = m->slirp;
+    int hlen = sizeof(struct ip6);
+
+    DEBUG_CALL("icmp6_input");
+    DEBUG_ARG("m = %p", m);
+    DEBUG_ARG("m_len = %d", m->m_len);
+
+    if (ntohs(ip->ip_pl) < ICMP6_MINLEN) {
+        goto end;
+    }
+
+    if (ip6_cksum(m)) {
+        goto end;
+    }
+
+    m->m_len -= hlen;
+    m->m_data += hlen;
+    icmp = mtod(m, struct icmp6 *);
+    m->m_len += hlen;
+    m->m_data -= hlen;
+
+    DEBUG_ARG("icmp6_type = %d", icmp->icmp6_type);
+    switch (icmp->icmp6_type) {
+    case ICMP6_ECHO_REQUEST:
+        if (in6_equal_host(&ip->ip_dst)) {
+            icmp6_send_echoreply(m, slirp, ip, icmp);
+        } else {
+            /* TODO */
+            g_critical("external icmpv6 not supported yet");
+        }
+        break;
+
+    case ICMP6_NDP_RS:
+    case ICMP6_NDP_RA:
+    case ICMP6_NDP_NS:
+    case ICMP6_NDP_NA:
+    case ICMP6_NDP_REDIRECT:
+        ndp_input(m, slirp, ip, icmp);
+        break;
+
+    case ICMP6_UNREACH:
+    case ICMP6_TOOBIG:
+    case ICMP6_TIMXCEED:
+    case ICMP6_PARAMPROB:
+        /* XXX? report error? close socket? */
+    default:
+        break;
+    }
+
+end:
+    m_free(m);
+}
diff --git a/slirp/src/ip6_icmp.h b/slirp/src/ip6_icmp.h
new file mode 100644 (file)
index 0000000..e8ed753
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ */
+
+#ifndef SLIRP_IP6_ICMP_H
+#define SLIRP_IP6_ICMP_H
+
+/*
+ * Interface Control Message Protocol version 6 Definitions.
+ * Per RFC 4443, March 2006.
+ *
+ * Network Discover Protocol Definitions.
+ * Per RFC 4861, September 2007.
+ */
+
+struct icmp6_echo { /* Echo Messages */
+    uint16_t id;
+    uint16_t seq_num;
+};
+
+union icmp6_error_body {
+    uint32_t unused;
+    uint32_t pointer;
+    uint32_t mtu;
+};
+
+/*
+ * NDP Messages
+ */
+struct ndp_rs {     /* Router Solicitation Message */
+    uint32_t reserved;
+};
+
+struct ndp_ra {     /* Router Advertisement Message */
+    uint8_t chl;    /* Cur Hop Limit */
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+    uint8_t
+        M:1,
+        O:1,
+        reserved:6;
+#else
+    uint8_t
+        reserved:6,
+        O:1,
+        M:1;
+#endif
+    uint16_t lifetime;      /* Router Lifetime */
+    uint32_t reach_time;    /* Reachable Time */
+    uint32_t retrans_time;  /* Retrans Timer */
+};
+
+G_STATIC_ASSERT(sizeof(struct ndp_ra) == 12);
+
+struct ndp_ns {     /* Neighbor Solicitation Message */
+    uint32_t reserved;
+    struct in6_addr target; /* Target Address */
+};
+
+G_STATIC_ASSERT(sizeof(struct ndp_ns) == 20);
+
+struct ndp_na {     /* Neighbor Advertisement Message */
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+    uint32_t
+        R:1,                /* Router Flag */
+        S:1,                /* Solicited Flag */
+        O:1,                /* Override Flag */
+        reserved_hi:5,
+        reserved_lo:24;
+#else
+    uint32_t
+        reserved_hi:5,
+        O:1,
+        S:1,
+        R:1,
+        reserved_lo:24;
+#endif
+    struct in6_addr target; /* Target Address */
+};
+
+G_STATIC_ASSERT(sizeof(struct ndp_na) == 20);
+
+struct ndp_redirect {
+    uint32_t reserved;
+    struct in6_addr target; /* Target Address */
+    struct in6_addr dest;   /* Destination Address */
+};
+
+G_STATIC_ASSERT(sizeof(struct ndp_redirect) == 36);
+
+/*
+ * Structure of an icmpv6 header.
+ */
+struct icmp6 {
+    uint8_t     icmp6_type;         /* type of message, see below */
+    uint8_t     icmp6_code;         /* type sub code */
+    uint16_t    icmp6_cksum;        /* ones complement cksum of struct */
+    union {
+        union icmp6_error_body error_body;
+        struct icmp6_echo echo;
+        struct ndp_rs ndp_rs;
+        struct ndp_ra ndp_ra;
+        struct ndp_ns ndp_ns;
+        struct ndp_na ndp_na;
+        struct ndp_redirect ndp_redirect;
+    } icmp6_body;
+#define icmp6_err icmp6_body.error_body
+#define icmp6_echo icmp6_body.echo
+#define icmp6_nrs icmp6_body.ndp_rs
+#define icmp6_nra icmp6_body.ndp_ra
+#define icmp6_nns icmp6_body.ndp_ns
+#define icmp6_nna icmp6_body.ndp_na
+#define icmp6_redirect icmp6_body.ndp_redirect
+};
+
+G_STATIC_ASSERT(sizeof(struct icmp6) == 40);
+
+#define ICMP6_MINLEN    4
+#define ICMP6_ERROR_MINLEN  8
+#define ICMP6_ECHO_MINLEN   8
+#define ICMP6_NDP_RS_MINLEN 8
+#define ICMP6_NDP_RA_MINLEN 16
+#define ICMP6_NDP_NS_MINLEN 24
+#define ICMP6_NDP_NA_MINLEN 24
+#define ICMP6_NDP_REDIRECT_MINLEN 40
+
+/*
+ * NDP Options
+ */
+struct ndpopt {
+    uint8_t     ndpopt_type;                    /* Option type */
+    uint8_t     ndpopt_len;                     /* /!\ In units of 8 octets */
+    union {
+        unsigned char   linklayer_addr[6];      /* Source/Target Link-layer */
+#define ndpopt_linklayer ndpopt_body.linklayer_addr
+        struct prefixinfo {                     /* Prefix Information */
+            uint8_t     prefix_length;
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+            uint8_t     L:1, A:1, reserved1:6;
+#else
+            uint8_t     reserved1:6, A:1, L:1;
+#endif
+            uint32_t    valid_lt;               /* Valid Lifetime */
+            uint32_t    pref_lt;                /* Preferred Lifetime */
+            uint32_t    reserved2;
+            struct in6_addr prefix;
+        } SLIRP_PACKED prefixinfo;
+#define ndpopt_prefixinfo ndpopt_body.prefixinfo
+        struct rdnss {
+            uint16_t reserved;
+            uint32_t lifetime;
+            struct in6_addr addr;
+        } SLIRP_PACKED rdnss;
+#define ndpopt_rdnss ndpopt_body.rdnss
+    } ndpopt_body;
+} SLIRP_PACKED;
+
+/* NDP options type */
+#define NDPOPT_LINKLAYER_SOURCE     1   /* Source Link-Layer Address */
+#define NDPOPT_LINKLAYER_TARGET     2   /* Target Link-Layer Address */
+#define NDPOPT_PREFIX_INFO          3   /* Prefix Information */
+#define NDPOPT_RDNSS                25  /* Recursive DNS Server Address */
+
+/* NDP options size, in octets. */
+#define NDPOPT_LINKLAYER_LEN    8
+#define NDPOPT_PREFIXINFO_LEN   32
+#define NDPOPT_RDNSS_LEN        24
+
+/*
+ * Definition of type and code field values.
+ * Per https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xml
+ * Last Updated 2012-11-12
+ */
+
+/* Errors */
+#define ICMP6_UNREACH   1   /* Destination Unreachable */
+#define     ICMP6_UNREACH_NO_ROUTE      0   /* no route to dest */
+#define     ICMP6_UNREACH_DEST_PROHIB   1   /* com with dest prohibited */
+#define     ICMP6_UNREACH_SCOPE         2   /* beyond scope of src addr */
+#define     ICMP6_UNREACH_ADDRESS       3   /* address unreachable */
+#define     ICMP6_UNREACH_PORT          4   /* port unreachable */
+#define     ICMP6_UNREACH_SRC_FAIL      5   /* src addr failed */
+#define     ICMP6_UNREACH_REJECT_ROUTE  6   /* reject route to dest */
+#define     ICMP6_UNREACH_SRC_HDR_ERROR 7   /* error in src routing header */
+#define ICMP6_TOOBIG    2   /* Packet Too Big */
+#define ICMP6_TIMXCEED  3   /* Time Exceeded */
+#define     ICMP6_TIMXCEED_INTRANS      0   /* hop limit exceeded in transit */
+#define     ICMP6_TIMXCEED_REASS        1   /* ttl=0 in reass */
+#define ICMP6_PARAMPROB 4   /* Parameter Problem */
+#define     ICMP6_PARAMPROB_HDR_FIELD   0   /* err header field */
+#define     ICMP6_PARAMPROB_NXTHDR_TYPE 1   /* unrecognized Next Header type */
+#define     ICMP6_PARAMPROB_IPV6_OPT    2   /* unrecognized IPv6 option */
+
+/* Informational Messages */
+#define ICMP6_ECHO_REQUEST      128 /* Echo Request */
+#define ICMP6_ECHO_REPLY        129 /* Echo Reply */
+#define ICMP6_NDP_RS            133 /* Router Solicitation (NDP) */
+#define ICMP6_NDP_RA            134 /* Router Advertisement (NDP) */
+#define ICMP6_NDP_NS            135 /* Neighbor Solicitation (NDP) */
+#define ICMP6_NDP_NA            136 /* Neighbor Advertisement (NDP) */
+#define ICMP6_NDP_REDIRECT      137 /* Redirect Message (NDP) */
+
+/*
+ * Router Configuration Variables (rfc4861#section-6)
+ */
+#define NDP_IsRouter                1
+#define NDP_AdvSendAdvertisements   1
+#define NDP_MaxRtrAdvInterval       600000
+#define NDP_MinRtrAdvInterval       ((NDP_MaxRtrAdvInterval >= 9) ? \
+                                        NDP_MaxRtrAdvInterval / 3 : \
+                                        NDP_MaxRtrAdvInterval)
+#define NDP_AdvManagedFlag          0
+#define NDP_AdvOtherConfigFlag      0
+#define NDP_AdvLinkMTU              0
+#define NDP_AdvReachableTime        0
+#define NDP_AdvRetransTime          0
+#define NDP_AdvCurHopLimit          64
+#define NDP_AdvDefaultLifetime      ((3 * NDP_MaxRtrAdvInterval) / 1000)
+#define NDP_AdvValidLifetime        86400
+#define NDP_AdvOnLinkFlag           1
+#define NDP_AdvPrefLifetime         14400
+#define NDP_AdvAutonomousFlag       1
+
+void icmp6_init(Slirp *slirp);
+void icmp6_cleanup(Slirp *slirp);
+void icmp6_input(struct mbuf *);
+void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code);
+void ndp_send_ra(Slirp *slirp);
+void ndp_send_ns(Slirp *slirp, struct in6_addr addr);
+
+#endif
diff --git a/slirp/src/ip6_input.c b/slirp/src/ip6_input.c
new file mode 100644 (file)
index 0000000..1b8c003
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ */
+
+#include "slirp.h"
+#include "ip6_icmp.h"
+
+/*
+ * IP initialization: fill in IP protocol switch table.
+ * All protocols not implemented in kernel go to raw IP protocol handler.
+ */
+void ip6_init(Slirp *slirp)
+{
+    icmp6_init(slirp);
+}
+
+void ip6_cleanup(Slirp *slirp)
+{
+    icmp6_cleanup(slirp);
+}
+
+void ip6_input(struct mbuf *m)
+{
+    struct ip6 *ip6;
+    Slirp *slirp = m->slirp;
+
+    if (!slirp->in6_enabled) {
+        goto bad;
+    }
+
+    DEBUG_CALL("ip6_input");
+    DEBUG_ARG("m = %p", m);
+    DEBUG_ARG("m_len = %d", m->m_len);
+
+    if (m->m_len < sizeof(struct ip6)) {
+        goto bad;
+    }
+
+    ip6 = mtod(m, struct ip6 *);
+
+    if (ip6->ip_v != IP6VERSION) {
+        goto bad;
+    }
+
+    if (ntohs(ip6->ip_pl) > IF_MTU) {
+        icmp6_send_error(m, ICMP6_TOOBIG, 0);
+        goto bad;
+    }
+
+    /* check ip_ttl for a correct ICMP reply */
+    if (ip6->ip_hl == 0) {
+        icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS);
+        goto bad;
+    }
+
+    /*
+     * Switch out to protocol's input routine.
+     */
+    switch (ip6->ip_nh) {
+    case IPPROTO_TCP:
+        NTOHS(ip6->ip_pl);
+        tcp_input(m, sizeof(struct ip6), (struct socket *)NULL, AF_INET6);
+        break;
+    case IPPROTO_UDP:
+        udp6_input(m);
+        break;
+    case IPPROTO_ICMPV6:
+        icmp6_input(m);
+        break;
+    default:
+        m_free(m);
+    }
+    return;
+bad:
+    m_free(m);
+}
diff --git a/slirp/src/ip6_output.c b/slirp/src/ip6_output.c
new file mode 100644 (file)
index 0000000..19d1ae7
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ */
+
+#include "slirp.h"
+
+/* Number of packets queued before we start sending
+ * (to prevent allocing too many mbufs) */
+#define IF6_THRESH 10
+
+/*
+ * IPv6 output. The packet in mbuf chain m contains a IP header
+ */
+int ip6_output(struct socket *so, struct mbuf *m, int fast)
+{
+    struct ip6 *ip = mtod(m, struct ip6 *);
+
+    DEBUG_CALL("ip6_output");
+    DEBUG_ARG("so = %p", so);
+    DEBUG_ARG("m = %p", m);
+
+    /* Fill IPv6 header */
+    ip->ip_v = IP6VERSION;
+    ip->ip_hl = IP6_HOP_LIMIT;
+    ip->ip_tc_hi = 0;
+    ip->ip_tc_lo = 0;
+    ip->ip_fl_hi = 0;
+    ip->ip_fl_lo = 0;
+
+    if (fast) {
+        if_encap(m->slirp, m);
+    } else {
+        if_output(so, m);
+    }
+
+    return 0;
+}
diff --git a/slirp/src/ip_icmp.c b/slirp/src/ip_icmp.c
new file mode 100644 (file)
index 0000000..120108f
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 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. 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.
+ *
+ *     @(#)ip_icmp.c   8.2 (Berkeley) 1/4/94
+ * ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp
+ */
+
+#include "slirp.h"
+#include "ip_icmp.h"
+
+#ifndef WITH_ICMP_ERROR_MSG
+#define WITH_ICMP_ERROR_MSG 0
+#endif
+
+/* The message sent when emulating PING */
+/* Be nice and tell them it's just a pseudo-ping packet */
+static const char icmp_ping_msg[] = "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n";
+
+/* list of actions for icmp_send_error() on RX of an icmp message */
+static const int icmp_flush[19] = {
+/*  ECHO REPLY (0)  */   0,
+                        1,
+                        1,
+/* DEST UNREACH (3) */   1,
+/* SOURCE QUENCH (4)*/   1,
+/* REDIRECT (5) */       1,
+                        1,
+                        1,
+/* ECHO (8) */           0,
+/* ROUTERADVERT (9) */   1,
+/* ROUTERSOLICIT (10) */ 1,
+/* TIME EXCEEDED (11) */ 1,
+/* PARAMETER PROBLEM (12) */ 1,
+/* TIMESTAMP (13) */     0,
+/* TIMESTAMP REPLY (14) */ 0,
+/* INFO (15) */          0,
+/* INFO REPLY (16) */    0,
+/* ADDR MASK (17) */     0,
+/* ADDR MASK REPLY (18) */ 0
+};
+
+void icmp_init(Slirp *slirp)
+{
+    slirp->icmp.so_next = slirp->icmp.so_prev = &slirp->icmp;
+    slirp->icmp_last_so = &slirp->icmp;
+}
+
+void icmp_cleanup(Slirp *slirp)
+{
+    while (slirp->icmp.so_next != &slirp->icmp) {
+        icmp_detach(slirp->icmp.so_next);
+    }
+}
+
+static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
+{
+    struct ip *ip = mtod(m, struct ip *);
+    struct sockaddr_in addr;
+
+    so->s = slirp_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+    if (so->s == -1) {
+        return -1;
+    }
+
+    so->so_m = m;
+    so->so_faddr = ip->ip_dst;
+    so->so_laddr = ip->ip_src;
+    so->so_iptos = ip->ip_tos;
+    so->so_type = IPPROTO_ICMP;
+    so->so_state = SS_ISFCONNECTED;
+    so->so_expire = curtime + SO_EXPIRE;
+
+    addr.sin_family = AF_INET;
+    addr.sin_addr = so->so_faddr;
+
+    insque(so, &so->slirp->icmp);
+
+    if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0,
+               (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+        DEBUG_MISC("icmp_input icmp sendto tx errno = %d-%s",
+                   errno, strerror(errno));
+        icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
+        icmp_detach(so);
+    }
+
+    return 0;
+}
+
+void icmp_detach(struct socket *so)
+{
+    so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
+    closesocket(so->s);
+    sofree(so);
+}
+
+/*
+ * Process a received ICMP message.
+ */
+void
+icmp_input(struct mbuf *m, int hlen)
+{
+  register struct icmp *icp;
+  register struct ip *ip=mtod(m, struct ip *);
+  int icmplen=ip->ip_len;
+  Slirp *slirp = m->slirp;
+
+  DEBUG_CALL("icmp_input");
+  DEBUG_ARG("m = %p", m);
+  DEBUG_ARG("m_len = %d", m->m_len);
+
+  /*
+   * Locate icmp structure in mbuf, and check
+   * that its not corrupted and of at least minimum length.
+   */
+  if (icmplen < ICMP_MINLEN) {          /* min 8 bytes payload */
+  freeit:
+    m_free(m);
+    goto end_error;
+  }
+
+  m->m_len -= hlen;
+  m->m_data += hlen;
+  icp = mtod(m, struct icmp *);
+  if (cksum(m, icmplen)) {
+    goto freeit;
+  }
+  m->m_len += hlen;
+  m->m_data -= hlen;
+
+  DEBUG_ARG("icmp_type = %d", icp->icmp_type);
+  switch (icp->icmp_type) {
+  case ICMP_ECHO:
+    ip->ip_len += hlen;                     /* since ip_input subtracts this */
+    if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
+        ip->ip_dst.s_addr == slirp->vnameserver_addr.s_addr) {
+        icmp_reflect(m);
+    } else if (slirp->restricted) {
+        goto freeit;
+    } else {
+      struct socket *so;
+      struct sockaddr_storage addr;
+      so = socreate(slirp);
+      if (icmp_send(so, m, hlen) == 0) {
+        return;
+      }
+      if (udp_attach(so, AF_INET) == -1) {
+       DEBUG_MISC("icmp_input udp_attach errno = %d-%s",
+               errno,strerror(errno));
+       sofree(so);
+       m_free(m);
+       goto end_error;
+      }
+      so->so_m = m;
+      so->so_ffamily = AF_INET;
+      so->so_faddr = ip->ip_dst;
+      so->so_fport = htons(7);
+      so->so_lfamily = AF_INET;
+      so->so_laddr = ip->ip_src;
+      so->so_lport = htons(9);
+      so->so_iptos = ip->ip_tos;
+      so->so_type = IPPROTO_ICMP;
+      so->so_state = SS_ISFCONNECTED;
+
+      /* Send the packet */
+      addr = so->fhost.ss;
+      sotranslate_out(so, &addr);
+
+      if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
+               (struct sockaddr *)&addr, sockaddr_size(&addr)) == -1) {
+       DEBUG_MISC("icmp_input udp sendto tx errno = %d-%s",
+               errno,strerror(errno));
+       icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
+       udp_detach(so);
+      }
+    } /* if ip->ip_dst.s_addr == alias_addr.s_addr */
+    break;
+  case ICMP_UNREACH:
+    /* XXX? report error? close socket? */
+  case ICMP_TIMXCEED:
+  case ICMP_PARAMPROB:
+  case ICMP_SOURCEQUENCH:
+  case ICMP_TSTAMP:
+  case ICMP_MASKREQ:
+  case ICMP_REDIRECT:
+    m_free(m);
+    break;
+
+  default:
+    m_free(m);
+  } /* swith */
+
+end_error:
+  /* m is m_free()'d xor put in a socket xor or given to ip_send */
+  return;
+}
+
+
+/*
+ *     Send an ICMP message in response to a situation
+ *
+ *     RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do).
+ *                     MUST NOT change this header information.
+ *                     MUST NOT reply to a multicast/broadcast IP address.
+ *                     MUST NOT reply to a multicast/broadcast MAC address.
+ *                     MUST reply to only the first fragment.
+ */
+/*
+ * Send ICMP_UNREACH back to the source regarding msrc.
+ * mbuf *msrc is used as a template, but is NOT m_free()'d.
+ * It is reported as the bad ip packet.  The header should
+ * be fully correct and in host byte order.
+ * ICMP fragmentation is illegal.  All machines must accept 576 bytes in one
+ * packet.  The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548
+ */
+
+#define ICMP_MAXDATALEN (IP_MSS-28)
+void
+icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
+           const char *message)
+{
+  unsigned hlen, shlen, s_ip_len;
+  register struct ip *ip;
+  register struct icmp *icp;
+  register struct mbuf *m;
+
+  DEBUG_CALL("icmp_send_error");
+  DEBUG_ARG("msrc = %p", msrc);
+  DEBUG_ARG("msrc_len = %d", msrc->m_len);
+
+  if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error;
+
+  /* check msrc */
+  if(!msrc) goto end_error;
+  ip = mtod(msrc, struct ip *);
+  if (slirp_debug & DBG_MISC) {
+    char bufa[20], bufb[20];
+    strcpy(bufa, inet_ntoa(ip->ip_src));
+    strcpy(bufb, inet_ntoa(ip->ip_dst));
+    DEBUG_MISC(" %.16s to %.16s", bufa, bufb);
+  }
+  if(ip->ip_off & IP_OFFMASK) goto end_error;    /* Only reply to fragment 0 */
+
+  /* Do not reply to source-only IPs */
+  if ((ip->ip_src.s_addr & htonl(~(0xf << 28))) == 0) {
+      goto end_error;
+  }
+
+  shlen=ip->ip_hl << 2;
+  s_ip_len=ip->ip_len;
+  if(ip->ip_p == IPPROTO_ICMP) {
+    icp = (struct icmp *)((char *)ip + shlen);
+    /*
+     * Assume any unknown ICMP type is an error. This isn't
+     * specified by the RFC, but think about it..
+     */
+    if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error;
+  }
+
+  /* make a copy */
+  m = m_get(msrc->slirp);
+  if (!m) {
+      goto end_error;
+  }
+
+  { int new_m_size;
+    new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN;
+    if(new_m_size>m->m_size) m_inc(m, new_m_size);
+  }
+  memcpy(m->m_data, msrc->m_data, msrc->m_len);
+  m->m_len = msrc->m_len;                        /* copy msrc to m */
+
+  /* make the header of the reply packet */
+  ip  = mtod(m, struct ip *);
+  hlen= sizeof(struct ip );     /* no options in reply */
+
+  /* fill in icmp */
+  m->m_data += hlen;
+  m->m_len -= hlen;
+
+  icp = mtod(m, struct icmp *);
+
+  if(minsize) s_ip_len=shlen+ICMP_MINLEN;   /* return header+8b only */
+  else if(s_ip_len>ICMP_MAXDATALEN)         /* maximum size */
+    s_ip_len=ICMP_MAXDATALEN;
+
+  m->m_len=ICMP_MINLEN+s_ip_len;        /* 8 bytes ICMP header */
+
+  /* min. size = 8+sizeof(struct ip)+8 */
+
+  icp->icmp_type = type;
+  icp->icmp_code = code;
+  icp->icmp_id = 0;
+  icp->icmp_seq = 0;
+
+  memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len);   /* report the ip packet */
+  HTONS(icp->icmp_ip.ip_len);
+  HTONS(icp->icmp_ip.ip_id);
+  HTONS(icp->icmp_ip.ip_off);
+
+  if (message && WITH_ICMP_ERROR_MSG) { /* append message to ICMP packet */
+    int message_len;
+    char *cpnt;
+    message_len=strlen(message);
+    if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN;
+    cpnt=(char *)m->m_data+m->m_len;
+    memcpy(cpnt, message, message_len);
+    m->m_len+=message_len;
+  }
+
+  icp->icmp_cksum = 0;
+  icp->icmp_cksum = cksum(m, m->m_len);
+
+  m->m_data -= hlen;
+  m->m_len += hlen;
+
+  /* fill in ip */
+  ip->ip_hl = hlen >> 2;
+  ip->ip_len = m->m_len;
+
+  ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0);  /* high priority for errors */
+
+  ip->ip_ttl = MAXTTL;
+  ip->ip_p = IPPROTO_ICMP;
+  ip->ip_dst = ip->ip_src;    /* ip addresses */
+  ip->ip_src = m->slirp->vhost_addr;
+
+  (void ) ip_output((struct socket *)NULL, m);
+
+end_error:
+  return;
+}
+#undef ICMP_MAXDATALEN
+
+/*
+ * Reflect the ip packet back to the source
+ */
+void
+icmp_reflect(struct mbuf *m)
+{
+  register struct ip *ip = mtod(m, struct ip *);
+  int hlen = ip->ip_hl << 2;
+  int optlen = hlen - sizeof(struct ip );
+  register struct icmp *icp;
+
+  /*
+   * Send an icmp packet back to the ip level,
+   * after supplying a checksum.
+   */
+  m->m_data += hlen;
+  m->m_len -= hlen;
+  icp = mtod(m, struct icmp *);
+
+  icp->icmp_type = ICMP_ECHOREPLY;
+  icp->icmp_cksum = 0;
+  icp->icmp_cksum = cksum(m, ip->ip_len - hlen);
+
+  m->m_data -= hlen;
+  m->m_len += hlen;
+
+  /* fill in ip */
+  if (optlen > 0) {
+    /*
+     * Strip out original options by copying rest of first
+     * mbuf's data back, and adjust the IP length.
+     */
+    memmove((char *)(ip + 1), (char *)ip + hlen,
+           (unsigned )(m->m_len - hlen));
+    hlen -= optlen;
+    ip->ip_hl = hlen >> 2;
+    ip->ip_len -= optlen;
+    m->m_len -= optlen;
+  }
+
+  ip->ip_ttl = MAXTTL;
+  { /* swap */
+    struct in_addr icmp_dst;
+    icmp_dst = ip->ip_dst;
+    ip->ip_dst = ip->ip_src;
+    ip->ip_src = icmp_dst;
+  }
+
+  (void ) ip_output((struct socket *)NULL, m);
+}
+
+void icmp_receive(struct socket *so)
+{
+    struct mbuf *m = so->so_m;
+    struct ip *ip = mtod(m, struct ip *);
+    int hlen = ip->ip_hl << 2;
+    uint8_t error_code;
+    struct icmp *icp;
+    int id, len;
+
+    m->m_data += hlen;
+    m->m_len -= hlen;
+    icp = mtod(m, struct icmp *);
+
+    id = icp->icmp_id;
+    len = recv(so->s, icp, M_ROOM(m), 0);
+    /*
+     * The behavior of reading SOCK_DGRAM+IPPROTO_ICMP sockets is inconsistent
+     * between host OSes.  On Linux, only the ICMP header and payload is
+     * included.  On macOS/Darwin, the socket acts like a raw socket and
+     * includes the IP header as well.  On other BSDs, SOCK_DGRAM+IPPROTO_ICMP
+     * sockets aren't supported at all, so we treat them like raw sockets.  It
+     * isn't possible to detect this difference at runtime, so we must use an
+     * #ifdef to determine if we need to remove the IP header.
+     */
+#ifdef CONFIG_BSD
+    if (len >= sizeof(struct ip)) {
+        struct ip *inner_ip = mtod(m, struct ip *);
+        int inner_hlen = inner_ip->ip_hl << 2;
+        if (inner_hlen > len) {
+            len = -1;
+            errno = -EINVAL;
+        } else {
+            len -= inner_hlen;
+            memmove(icp, (unsigned char *)icp + inner_hlen, len);
+        }
+    } else {
+      len = -1;
+      errno = -EINVAL;
+    }
+#endif
+    icp->icmp_id = id;
+
+    m->m_data -= hlen;
+    m->m_len += hlen;
+
+    if (len == -1 || len == 0) {
+        if (errno == ENETUNREACH) {
+            error_code = ICMP_UNREACH_NET;
+        } else {
+            error_code = ICMP_UNREACH_HOST;
+        }
+        DEBUG_MISC(" udp icmp rx errno = %d-%s", errno,
+                   strerror(errno));
+        icmp_send_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno));
+    } else {
+        icmp_reflect(so->so_m);
+        so->so_m = NULL; /* Don't m_free() it again! */
+    }
+    icmp_detach(so);
+}
diff --git a/slirp/src/ip_icmp.h b/slirp/src/ip_icmp.h
new file mode 100644 (file)
index 0000000..a4e5b8b
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 1982, 1986, 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. 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.
+ *
+ *     @(#)ip_icmp.h   8.1 (Berkeley) 6/10/93
+ * ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp
+ */
+
+#ifndef NETINET_IP_ICMP_H
+#define NETINET_IP_ICMP_H
+
+/*
+ * Interface Control Message Protocol Definitions.
+ * Per RFC 792, September 1981.
+ */
+
+typedef uint32_t n_time;
+
+/*
+ * Structure of an icmp header.
+ */
+struct icmp {
+       uint8_t icmp_type;              /* type of message, see below */
+       uint8_t icmp_code;              /* type sub code */
+       uint16_t        icmp_cksum;             /* ones complement cksum of struct */
+       union {
+               uint8_t ih_pptr;                        /* ICMP_PARAMPROB */
+               struct in_addr ih_gwaddr;       /* ICMP_REDIRECT */
+               struct ih_idseq {
+                       uint16_t        icd_id;
+                       uint16_t        icd_seq;
+               } ih_idseq;
+               int ih_void;
+
+               /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
+               struct ih_pmtu {
+                       uint16_t ipm_void;
+                       uint16_t ipm_nextmtu;
+               } ih_pmtu;
+       } icmp_hun;
+#define        icmp_pptr       icmp_hun.ih_pptr
+#define        icmp_gwaddr     icmp_hun.ih_gwaddr
+#define        icmp_id         icmp_hun.ih_idseq.icd_id
+#define        icmp_seq        icmp_hun.ih_idseq.icd_seq
+#define        icmp_void       icmp_hun.ih_void
+#define        icmp_pmvoid     icmp_hun.ih_pmtu.ipm_void
+#define        icmp_nextmtu    icmp_hun.ih_pmtu.ipm_nextmtu
+       union {
+               struct id_ts {
+                       n_time its_otime;
+                       n_time its_rtime;
+                       n_time its_ttime;
+               } id_ts;
+               struct id_ip  {
+                       struct ip idi_ip;
+                       /* options and then 64 bits of data */
+               } id_ip;
+               uint32_t        id_mask;
+               char            id_data[1];
+       } icmp_dun;
+#define        icmp_otime      icmp_dun.id_ts.its_otime
+#define        icmp_rtime      icmp_dun.id_ts.its_rtime
+#define        icmp_ttime      icmp_dun.id_ts.its_ttime
+#define        icmp_ip         icmp_dun.id_ip.idi_ip
+#define        icmp_mask       icmp_dun.id_mask
+#define        icmp_data       icmp_dun.id_data
+};
+
+/*
+ * Lower bounds on packet lengths for various types.
+ * For the error advice packets must first ensure that the
+ * packet is large enough to contain the returned ip header.
+ * Only then can we do the check to see if 64 bits of packet
+ * data have been returned, since we need to check the returned
+ * ip header length.
+ */
+#define        ICMP_MINLEN     8                               /* abs minimum */
+#define        ICMP_TSLEN      (8 + 3 * sizeof (n_time))       /* timestamp */
+#define        ICMP_MASKLEN    12                              /* address mask */
+#define        ICMP_ADVLENMIN  (8 + sizeof (struct ip) + 8)    /* min */
+#define        ICMP_ADVLEN(p)  (8 + ((p)->icmp_ip.ip_hl << 2) + 8)
+       /* N.B.: must separately check that ip_hl >= 5 */
+
+/*
+ * Definition of type and code field values.
+ */
+#define        ICMP_ECHOREPLY          0               /* echo reply */
+#define        ICMP_UNREACH            3               /* dest unreachable, codes: */
+#define                ICMP_UNREACH_NET        0               /* bad net */
+#define                ICMP_UNREACH_HOST       1               /* bad host */
+#define                ICMP_UNREACH_PROTOCOL   2               /* bad protocol */
+#define                ICMP_UNREACH_PORT       3               /* bad port */
+#define                ICMP_UNREACH_NEEDFRAG   4               /* IP_DF caused drop */
+#define                ICMP_UNREACH_SRCFAIL    5               /* src route failed */
+#define                ICMP_UNREACH_NET_UNKNOWN 6              /* unknown net */
+#define                ICMP_UNREACH_HOST_UNKNOWN 7             /* unknown host */
+#define                ICMP_UNREACH_ISOLATED   8               /* src host isolated */
+#define                ICMP_UNREACH_NET_PROHIB 9               /* prohibited access */
+#define                ICMP_UNREACH_HOST_PROHIB 10             /* ditto */
+#define                ICMP_UNREACH_TOSNET     11              /* bad tos for net */
+#define                ICMP_UNREACH_TOSHOST    12              /* bad tos for host */
+#define        ICMP_SOURCEQUENCH       4               /* packet lost, slow down */
+#define        ICMP_REDIRECT           5               /* shorter route, codes: */
+#define                ICMP_REDIRECT_NET       0               /* for network */
+#define                ICMP_REDIRECT_HOST      1               /* for host */
+#define                ICMP_REDIRECT_TOSNET    2               /* for tos and net */
+#define                ICMP_REDIRECT_TOSHOST   3               /* for tos and host */
+#define        ICMP_ECHO               8               /* echo service */
+#define        ICMP_ROUTERADVERT       9               /* router advertisement */
+#define        ICMP_ROUTERSOLICIT      10              /* router solicitation */
+#define        ICMP_TIMXCEED           11              /* time exceeded, code: */
+#define                ICMP_TIMXCEED_INTRANS   0               /* ttl==0 in transit */
+#define                ICMP_TIMXCEED_REASS     1               /* ttl==0 in reass */
+#define        ICMP_PARAMPROB          12              /* ip header bad */
+#define                ICMP_PARAMPROB_OPTABSENT 1              /* req. opt. absent */
+#define        ICMP_TSTAMP             13              /* timestamp request */
+#define        ICMP_TSTAMPREPLY        14              /* timestamp reply */
+#define        ICMP_IREQ               15              /* information request */
+#define        ICMP_IREQREPLY          16              /* information reply */
+#define        ICMP_MASKREQ            17              /* address mask request */
+#define        ICMP_MASKREPLY          18              /* address mask reply */
+
+#define        ICMP_MAXTYPE            18
+
+#define        ICMP_INFOTYPE(type) \
+       ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
+       (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \
+       (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
+       (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
+       (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
+
+void icmp_init(Slirp *slirp);
+void icmp_cleanup(Slirp *slirp);
+void icmp_input(struct mbuf *, int);
+void icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
+                     const char *message);
+void icmp_reflect(struct mbuf *);
+void icmp_receive(struct socket *so);
+void icmp_detach(struct socket *so);
+
+#endif
diff --git a/slirp/src/ip_input.c b/slirp/src/ip_input.c
new file mode 100644 (file)
index 0000000..e0b94b0
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 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. 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.
+ *
+ *     @(#)ip_input.c  8.2 (Berkeley) 1/4/94
+ * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp
+ */
+
+/*
+ * Changes and additions relating to SLiRP are
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include "slirp.h"
+#include "ip_icmp.h"
+
+static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp);
+static void ip_freef(Slirp *slirp, struct ipq *fp);
+static void ip_enq(register struct ipasfrag *p,
+                   register struct ipasfrag *prev);
+static void ip_deq(register struct ipasfrag *p);
+
+/*
+ * IP initialization: fill in IP protocol switch table.
+ * All protocols not implemented in kernel go to raw IP protocol handler.
+ */
+void
+ip_init(Slirp *slirp)
+{
+    slirp->ipq.ip_link.next = slirp->ipq.ip_link.prev = &slirp->ipq.ip_link;
+    udp_init(slirp);
+    tcp_init(slirp);
+    icmp_init(slirp);
+}
+
+void ip_cleanup(Slirp *slirp)
+{
+    udp_cleanup(slirp);
+    tcp_cleanup(slirp);
+    icmp_cleanup(slirp);
+}
+
+/*
+ * Ip input routine.  Checksum and byte swap header.  If fragmented
+ * try to reassemble.  Process options.  Pass to next level.
+ */
+void
+ip_input(struct mbuf *m)
+{
+       Slirp *slirp = m->slirp;
+       register struct ip *ip;
+       int hlen;
+
+       if (!slirp->in_enabled) {
+               goto bad;
+       }
+
+       DEBUG_CALL("ip_input");
+       DEBUG_ARG("m = %p", m);
+       DEBUG_ARG("m_len = %d", m->m_len);
+
+       if (m->m_len < sizeof (struct ip)) {
+               goto bad;
+       }
+
+       ip = mtod(m, struct ip *);
+
+       if (ip->ip_v != IPVERSION) {
+               goto bad;
+       }
+
+       hlen = ip->ip_hl << 2;
+       if (hlen<sizeof(struct ip ) || hlen>m->m_len) {/* min header length */
+         goto bad;                                  /* or packet too short */
+       }
+
+        /* keep ip header intact for ICMP reply
+        * ip->ip_sum = cksum(m, hlen);
+        * if (ip->ip_sum) {
+        */
+       if(cksum(m,hlen)) {
+         goto bad;
+       }
+
+       /*
+        * Convert fields to host representation.
+        */
+       NTOHS(ip->ip_len);
+       if (ip->ip_len < hlen) {
+               goto bad;
+       }
+       NTOHS(ip->ip_id);
+       NTOHS(ip->ip_off);
+
+       /*
+        * Check that the amount of data in the buffers
+        * is as at least much as the IP header would have us expect.
+        * Trim mbufs if longer than we expect.
+        * Drop packet if shorter than we expect.
+        */
+       if (m->m_len < ip->ip_len) {
+               goto bad;
+       }
+
+       /* Should drop packet if mbuf too long? hmmm... */
+       if (m->m_len > ip->ip_len)
+          m_adj(m, ip->ip_len - m->m_len);
+
+       /* check ip_ttl for a correct ICMP reply */
+       if (ip->ip_ttl == 0) {
+           icmp_send_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, "ttl");
+           goto bad;
+       }
+
+       /*
+        * If offset or IP_MF are set, must reassemble.
+        * Otherwise, nothing need be done.
+        * (We could look in the reassembly queue to see
+        * if the packet was previously fragmented,
+        * but it's not worth the time; just let them time out.)
+        *
+        * XXX This should fail, don't fragment yet
+        */
+       if (ip->ip_off &~ IP_DF) {
+         register struct ipq *fp;
+      struct qlink *l;
+               /*
+                * Look for queue of fragments
+                * of this datagram.
+                */
+               for (l = slirp->ipq.ip_link.next; l != &slirp->ipq.ip_link;
+                    l = l->next) {
+            fp = container_of(l, struct ipq, ip_link);
+            if (ip->ip_id == fp->ipq_id &&
+                    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
+                    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
+                    ip->ip_p == fp->ipq_p)
+                   goto found;
+        }
+        fp = NULL;
+       found:
+
+               /*
+                * Adjust ip_len to not reflect header,
+                * set ip_mff if more fragments are expected,
+                * convert offset of this to bytes.
+                */
+               ip->ip_len -= hlen;
+               if (ip->ip_off & IP_MF)
+                 ip->ip_tos |= 1;
+               else
+                 ip->ip_tos &= ~1;
+
+               ip->ip_off <<= 3;
+
+               /*
+                * If datagram marked as having more fragments
+                * or if this is not the first fragment,
+                * attempt reassembly; if it succeeds, proceed.
+                */
+               if (ip->ip_tos & 1 || ip->ip_off) {
+                       ip = ip_reass(slirp, ip, fp);
+                        if (ip == NULL)
+                               return;
+                       m = dtom(slirp, ip);
+               } else
+                       if (fp)
+                          ip_freef(slirp, fp);
+
+       } else
+               ip->ip_len -= hlen;
+
+       /*
+        * Switch out to protocol's input routine.
+        */
+       switch (ip->ip_p) {
+        case IPPROTO_TCP:
+               tcp_input(m, hlen, (struct socket *)NULL, AF_INET);
+               break;
+        case IPPROTO_UDP:
+               udp_input(m, hlen);
+               break;
+        case IPPROTO_ICMP:
+               icmp_input(m, hlen);
+               break;
+        default:
+               m_free(m);
+       }
+       return;
+bad:
+       m_free(m);
+}
+
+#define iptofrag(P) ((struct ipasfrag *)(((char*)(P)) - sizeof(struct qlink)))
+#define fragtoip(P) ((struct ip*)(((char*)(P)) + sizeof(struct qlink)))
+/*
+ * Take incoming datagram fragment and try to
+ * reassemble it into whole datagram.  If a chain for
+ * reassembly of this datagram already exists, then it
+ * is given as fp; otherwise have to make a chain.
+ */
+static struct ip *
+ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)
+{
+       register struct mbuf *m = dtom(slirp, ip);
+       register struct ipasfrag *q;
+       int hlen = ip->ip_hl << 2;
+       int i, next;
+
+       DEBUG_CALL("ip_reass");
+       DEBUG_ARG("ip = %p", ip);
+       DEBUG_ARG("fp = %p", fp);
+       DEBUG_ARG("m = %p", m);
+
+       /*
+        * Presence of header sizes in mbufs
+        * would confuse code below.
+         * Fragment m_data is concatenated.
+        */
+       m->m_data += hlen;
+       m->m_len -= hlen;
+
+       /*
+        * If first fragment to arrive, create a reassembly queue.
+        */
+        if (fp == NULL) {
+         struct mbuf *t = m_get(slirp);
+
+         if (t == NULL) {
+             goto dropfrag;
+         }
+         fp = mtod(t, struct ipq *);
+         insque(&fp->ip_link, &slirp->ipq.ip_link);
+         fp->ipq_ttl = IPFRAGTTL;
+         fp->ipq_p = ip->ip_p;
+         fp->ipq_id = ip->ip_id;
+         fp->frag_link.next = fp->frag_link.prev = &fp->frag_link;
+         fp->ipq_src = ip->ip_src;
+         fp->ipq_dst = ip->ip_dst;
+         q = (struct ipasfrag *)fp;
+         goto insert;
+       }
+
+       /*
+        * Find a segment which begins after this one does.
+        */
+       for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
+            q = q->ipf_next)
+               if (q->ipf_off > ip->ip_off)
+                       break;
+
+       /*
+        * If there is a preceding segment, it may provide some of
+        * our data already.  If so, drop the data from the incoming
+        * segment.  If it provides all of our data, drop us.
+        */
+       if (q->ipf_prev != &fp->frag_link) {
+        struct ipasfrag *pq = q->ipf_prev;
+               i = pq->ipf_off + pq->ipf_len - ip->ip_off;
+               if (i > 0) {
+                       if (i >= ip->ip_len)
+                               goto dropfrag;
+                       m_adj(dtom(slirp, ip), i);
+                       ip->ip_off += i;
+                       ip->ip_len -= i;
+               }
+       }
+
+       /*
+        * While we overlap succeeding segments trim them or,
+        * if they are completely covered, dequeue them.
+        */
+       while (q != (struct ipasfrag*)&fp->frag_link &&
+            ip->ip_off + ip->ip_len > q->ipf_off) {
+               i = (ip->ip_off + ip->ip_len) - q->ipf_off;
+               if (i < q->ipf_len) {
+                       q->ipf_len -= i;
+                       q->ipf_off += i;
+                       m_adj(dtom(slirp, q), i);
+                       break;
+               }
+               q = q->ipf_next;
+               m_free(dtom(slirp, q->ipf_prev));
+               ip_deq(q->ipf_prev);
+       }
+
+insert:
+       /*
+        * Stick new segment in its place;
+        * check for complete reassembly.
+        */
+       ip_enq(iptofrag(ip), q->ipf_prev);
+       next = 0;
+       for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link;
+            q = q->ipf_next) {
+               if (q->ipf_off != next)
+                        return NULL;
+               next += q->ipf_len;
+       }
+       if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1)
+                return NULL;
+
+       /*
+        * Reassembly is complete; concatenate fragments.
+        */
+    q = fp->frag_link.next;
+       m = dtom(slirp, q);
+
+       q = (struct ipasfrag *) q->ipf_next;
+       while (q != (struct ipasfrag*)&fp->frag_link) {
+         struct mbuf *t = dtom(slirp, q);
+         q = (struct ipasfrag *) q->ipf_next;
+         m_cat(m, t);
+       }
+
+       /*
+        * Create header for new ip packet by
+        * modifying header of first packet;
+        * dequeue and discard fragment reassembly header.
+        * Make header visible.
+        */
+       q = fp->frag_link.next;
+
+       /*
+        * If the fragments concatenated to an mbuf that's
+        * bigger than the total size of the fragment, then and
+        * m_ext buffer was alloced. But fp->ipq_next points to
+        * the old buffer (in the mbuf), so we must point ip
+        * into the new buffer.
+        */
+       if (m->m_flags & M_EXT) {
+         int delta = (char *)q - m->m_dat;
+         q = (struct ipasfrag *)(m->m_ext + delta);
+       }
+
+    ip = fragtoip(q);
+       ip->ip_len = next;
+       ip->ip_tos &= ~1;
+       ip->ip_src = fp->ipq_src;
+       ip->ip_dst = fp->ipq_dst;
+       remque(&fp->ip_link);
+       (void) m_free(dtom(slirp, fp));
+       m->m_len += (ip->ip_hl << 2);
+       m->m_data -= (ip->ip_hl << 2);
+
+       return ip;
+
+dropfrag:
+       m_free(m);
+        return NULL;
+}
+
+/*
+ * Free a fragment reassembly header and all
+ * associated datagrams.
+ */
+static void
+ip_freef(Slirp *slirp, struct ipq *fp)
+{
+       register struct ipasfrag *q, *p;
+
+       for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link; q = p) {
+               p = q->ipf_next;
+               ip_deq(q);
+               m_free(dtom(slirp, q));
+       }
+       remque(&fp->ip_link);
+       (void) m_free(dtom(slirp, fp));
+}
+
+/*
+ * Put an ip fragment on a reassembly chain.
+ * Like insque, but pointers in middle of structure.
+ */
+static void
+ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev)
+{
+       DEBUG_CALL("ip_enq");
+       DEBUG_ARG("prev = %p", prev);
+       p->ipf_prev =  prev;
+       p->ipf_next = prev->ipf_next;
+       ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p;
+       prev->ipf_next = p;
+}
+
+/*
+ * To ip_enq as remque is to insque.
+ */
+static void
+ip_deq(register struct ipasfrag *p)
+{
+       ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next;
+       ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev;
+}
+
+/*
+ * IP timer processing;
+ * if a timer expires on a reassembly
+ * queue, discard it.
+ */
+void
+ip_slowtimo(Slirp *slirp)
+{
+    struct qlink *l;
+
+       DEBUG_CALL("ip_slowtimo");
+
+    l = slirp->ipq.ip_link.next;
+
+        if (l == NULL)
+          return;
+
+    while (l != &slirp->ipq.ip_link) {
+        struct ipq *fp = container_of(l, struct ipq, ip_link);
+        l = l->next;
+               if (--fp->ipq_ttl == 0) {
+                       ip_freef(slirp, fp);
+               }
+    }
+}
+
+/*
+ * Strip out IP options, at higher
+ * level protocol in the kernel.
+ * Second argument is buffer to which options
+ * will be moved, and return value is their length.
+ * (XXX) should be deleted; last arg currently ignored.
+ */
+void
+ip_stripoptions(register struct mbuf *m, struct mbuf *mopt)
+{
+       register int i;
+       struct ip *ip = mtod(m, struct ip *);
+       register char *opts;
+       int olen;
+
+       olen = (ip->ip_hl<<2) - sizeof (struct ip);
+       opts = (char *)(ip + 1);
+       i = m->m_len - (sizeof (struct ip) + olen);
+       memcpy(opts, opts  + olen, (unsigned)i);
+       m->m_len -= olen;
+
+       ip->ip_hl = sizeof(struct ip) >> 2;
+}
diff --git a/slirp/src/ip_output.c b/slirp/src/ip_output.c
new file mode 100644 (file)
index 0000000..f6ec141
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 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. 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.
+ *
+ *     @(#)ip_output.c 8.3 (Berkeley) 1/21/94
+ * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp
+ */
+
+/*
+ * Changes and additions relating to SLiRP are
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include "slirp.h"
+
+/* Number of packets queued before we start sending
+ * (to prevent allocing too many mbufs) */
+#define IF_THRESH 10
+
+/*
+ * IP output.  The packet in mbuf chain m contains a skeletal IP
+ * header (with len, off, ttl, proto, tos, src, dst).
+ * The mbuf chain containing the packet will be freed.
+ * The mbuf opt, if present, will not be freed.
+ */
+int
+ip_output(struct socket *so, struct mbuf *m0)
+{
+       Slirp *slirp = m0->slirp;
+       register struct ip *ip;
+       register struct mbuf *m = m0;
+       register int hlen = sizeof(struct ip );
+       int len, off, error = 0;
+
+       DEBUG_CALL("ip_output");
+       DEBUG_ARG("so = %p", so);
+       DEBUG_ARG("m0 = %p", m0);
+
+       ip = mtod(m, struct ip *);
+       /*
+        * Fill in IP header.
+        */
+       ip->ip_v = IPVERSION;
+       ip->ip_off &= IP_DF;
+       ip->ip_id = htons(slirp->ip_id++);
+       ip->ip_hl = hlen >> 2;
+
+       /*
+        * If small enough for interface, can just send directly.
+        */
+       if ((uint16_t)ip->ip_len <= IF_MTU) {
+               ip->ip_len = htons((uint16_t)ip->ip_len);
+               ip->ip_off = htons((uint16_t)ip->ip_off);
+               ip->ip_sum = 0;
+               ip->ip_sum = cksum(m, hlen);
+
+               if_output(so, m);
+               goto done;
+       }
+
+       /*
+        * Too large for interface; fragment if possible.
+        * Must be able to put at least 8 bytes per fragment.
+        */
+       if (ip->ip_off & IP_DF) {
+               error = -1;
+               goto bad;
+       }
+
+       len = (IF_MTU - hlen) &~ 7;       /* ip databytes per packet */
+       if (len < 8) {
+               error = -1;
+               goto bad;
+       }
+
+    {
+       int mhlen, firstlen = len;
+       struct mbuf **mnext = &m->m_nextpkt;
+
+       /*
+        * Loop through length of segment after first fragment,
+        * make new header and copy data of each part and link onto chain.
+        */
+       m0 = m;
+       mhlen = sizeof (struct ip);
+       for (off = hlen + len; off < (uint16_t)ip->ip_len; off += len) {
+         register struct ip *mhip;
+         m = m_get(slirp);
+          if (m == NULL) {
+           error = -1;
+           goto sendorfree;
+         }
+         m->m_data += IF_MAXLINKHDR;
+         mhip = mtod(m, struct ip *);
+         *mhip = *ip;
+
+         m->m_len = mhlen;
+         mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
+         if (ip->ip_off & IP_MF)
+           mhip->ip_off |= IP_MF;
+         if (off + len >= (uint16_t)ip->ip_len)
+           len = (uint16_t)ip->ip_len - off;
+         else
+           mhip->ip_off |= IP_MF;
+         mhip->ip_len = htons((uint16_t)(len + mhlen));
+
+         if (m_copy(m, m0, off, len) < 0) {
+           error = -1;
+           goto sendorfree;
+         }
+
+         mhip->ip_off = htons((uint16_t)mhip->ip_off);
+         mhip->ip_sum = 0;
+         mhip->ip_sum = cksum(m, mhlen);
+         *mnext = m;
+         mnext = &m->m_nextpkt;
+       }
+       /*
+        * Update first fragment by trimming what's been copied out
+        * and updating header, then send each fragment (in order).
+        */
+       m = m0;
+       m_adj(m, hlen + firstlen - (uint16_t)ip->ip_len);
+       ip->ip_len = htons((uint16_t)m->m_len);
+       ip->ip_off = htons((uint16_t)(ip->ip_off | IP_MF));
+       ip->ip_sum = 0;
+       ip->ip_sum = cksum(m, hlen);
+sendorfree:
+       for (m = m0; m; m = m0) {
+               m0 = m->m_nextpkt;
+                m->m_nextpkt = NULL;
+               if (error == 0)
+                       if_output(so, m);
+               else
+                       m_free(m);
+       }
+    }
+
+done:
+       return (error);
+
+bad:
+       m_free(m0);
+       goto done;
+}
diff --git a/slirp/src/libslirp.h b/slirp/src/libslirp.h
new file mode 100644 (file)
index 0000000..2d13950
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef LIBSLIRP_H
+#define LIBSLIRP_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <in6addr.h>
+#else
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Slirp Slirp;
+
+enum {
+    SLIRP_POLL_IN  = 1 << 0,
+    SLIRP_POLL_OUT = 1 << 1,
+    SLIRP_POLL_PRI = 1 << 2,
+    SLIRP_POLL_ERR = 1 << 3,
+    SLIRP_POLL_HUP = 1 << 4,
+};
+
+typedef ssize_t (*SlirpReadCb)(void *buf, size_t len, void *opaque);
+typedef ssize_t (*SlirpWriteCb)(const void *buf, size_t len, void *opaque);
+typedef void (*SlirpTimerCb)(void *opaque);
+typedef int (*SlirpAddPollCb)(int fd, int events, void *opaque);
+typedef int (*SlirpGetREventsCb)(int idx, void *opaque);
+
+/*
+ * Callbacks from slirp
+ */
+typedef struct SlirpCb {
+    /*
+     * Send an ethernet frame to the guest network. The opaque
+     * parameter is the one given to slirp_init(). The function
+     * doesn't need to send all the data and may return <len (no
+     * buffering is done on libslirp side, so the data will be dropped
+     * in this case). <0 reports an IO error.
+     */
+    SlirpWriteCb send_packet;
+    /* Print a message for an error due to guest misbehavior.  */
+    void (*guest_error)(const char *msg, void *opaque);
+    /* Return the virtual clock value in nanoseconds */
+    int64_t (*clock_get_ns)(void *opaque);
+    /* Create a new timer with the given callback and opaque data */
+    void *(*timer_new)(SlirpTimerCb cb, void *cb_opaque, void *opaque);
+    /* Remove and free a timer */
+    void (*timer_free)(void *timer, void *opaque);
+    /* Modify a timer to expire at @expire_time */
+    void (*timer_mod)(void *timer, int64_t expire_time, void *opaque);
+    /* Register a fd for future polling */
+    void (*register_poll_fd)(int fd, void *opaque);
+    /* Unregister a fd */
+    void (*unregister_poll_fd)(int fd, void *opaque);
+    /* Kick the io-thread, to signal that new events may be processed */
+    void (*notify)(void *opaque);
+} SlirpCb;
+
+
+Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
+                  struct in_addr vnetmask, struct in_addr vhost,
+                  bool in6_enabled,
+                  struct in6_addr vprefix_addr6, uint8_t vprefix_len,
+                  struct in6_addr vhost6, const char *vhostname,
+                  const char *tftp_server_name,
+                  const char *tftp_path, const char *bootfile,
+                  struct in_addr vdhcp_start, struct in_addr vnameserver,
+                  struct in6_addr vnameserver6, const char **vdnssearch,
+                  const char *vdomainname,
+                  const SlirpCb *callbacks,
+                  void *opaque);
+void slirp_cleanup(Slirp *slirp);
+
+void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
+                        SlirpAddPollCb add_poll, void *opaque);
+
+void slirp_pollfds_poll(Slirp *slirp, int select_error,
+                        SlirpGetREventsCb get_revents, void *opaque);
+
+void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
+
+int slirp_add_hostfwd(Slirp *slirp, int is_udp,
+                      struct in_addr host_addr, int host_port,
+                      struct in_addr guest_addr, int guest_port);
+int slirp_remove_hostfwd(Slirp *slirp, int is_udp,
+                         struct in_addr host_addr, int host_port);
+int slirp_add_exec(Slirp *slirp, const char *cmdline,
+                   struct in_addr *guest_addr, int guest_port);
+int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
+                   struct in_addr *guest_addr, int guest_port);
+
+char *slirp_connection_info(Slirp *slirp);
+
+void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr,
+                       int guest_port, const uint8_t *buf, int size);
+size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
+                             int guest_port);
+
+void slirp_state_save(Slirp *s, SlirpWriteCb write_cb, void *opaque);
+
+int slirp_state_load(Slirp *s, int version_id,
+                     SlirpReadCb read_cb, void *opaque);
+
+int slirp_state_version(void);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LIBSLIRP_H */
diff --git a/slirp/src/main.h b/slirp/src/main.h
new file mode 100644 (file)
index 0000000..f11d457
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef SLIRP_MAIN_H
+#define SLIRP_MAIN_H
+
+extern unsigned curtime;
+extern struct in_addr loopback_addr;
+extern unsigned long loopback_mask;
+
+int if_encap(Slirp *slirp, struct mbuf *ifm);
+ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags);
+
+#endif
diff --git a/slirp/src/mbuf.c b/slirp/src/mbuf.c
new file mode 100644 (file)
index 0000000..521c02c
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+/*
+ * mbuf's in SLiRP are much simpler than the real mbufs in
+ * FreeBSD.  They are fixed size, determined by the MTU,
+ * so that one whole packet can fit.  Mbuf's cannot be
+ * chained together.  If there's more data than the mbuf
+ * could hold, an external g_malloced buffer is pointed to
+ * by m_ext (and the data pointers) and M_EXT is set in
+ * the flags
+ */
+
+#include "slirp.h"
+
+#define MBUF_THRESH 30
+
+/*
+ * Find a nice value for msize
+ */
+#define SLIRP_MSIZE\
+    (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + IF_MTU)
+
+void
+m_init(Slirp *slirp)
+{
+    slirp->m_freelist.qh_link = slirp->m_freelist.qh_rlink = &slirp->m_freelist;
+    slirp->m_usedlist.qh_link = slirp->m_usedlist.qh_rlink = &slirp->m_usedlist;
+}
+
+void m_cleanup(Slirp *slirp)
+{
+    struct mbuf *m, *next;
+
+    m = (struct mbuf *) slirp->m_usedlist.qh_link;
+    while ((struct quehead *) m != &slirp->m_usedlist) {
+        next = m->m_next;
+        if (m->m_flags & M_EXT) {
+            g_free(m->m_ext);
+        }
+        g_free(m);
+        m = next;
+    }
+    m = (struct mbuf *) slirp->m_freelist.qh_link;
+    while ((struct quehead *) m != &slirp->m_freelist) {
+        next = m->m_next;
+        g_free(m);
+        m = next;
+    }
+}
+
+/*
+ * Get an mbuf from the free list, if there are none
+ * allocate one
+ *
+ * Because fragmentation can occur if we alloc new mbufs and
+ * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE,
+ * which tells m_free to actually g_free() it
+ */
+struct mbuf *
+m_get(Slirp *slirp)
+{
+       register struct mbuf *m;
+       int flags = 0;
+
+       DEBUG_CALL("m_get");
+
+       if (slirp->m_freelist.qh_link == &slirp->m_freelist) {
+                m = g_malloc(SLIRP_MSIZE);
+               slirp->mbuf_alloced++;
+               if (slirp->mbuf_alloced > MBUF_THRESH)
+                       flags = M_DOFREE;
+               m->slirp = slirp;
+       } else {
+               m = (struct mbuf *) slirp->m_freelist.qh_link;
+               remque(m);
+       }
+
+       /* Insert it in the used list */
+       insque(m,&slirp->m_usedlist);
+       m->m_flags = (flags | M_USEDLIST);
+
+       /* Initialise it */
+       m->m_size = SLIRP_MSIZE - offsetof(struct mbuf, m_dat);
+       m->m_data = m->m_dat;
+       m->m_len = 0;
+        m->m_nextpkt = NULL;
+        m->m_prevpkt = NULL;
+        m->resolution_requested = false;
+        m->expiration_date = (uint64_t)-1;
+       DEBUG_ARG("m = %p", m);
+       return m;
+}
+
+void
+m_free(struct mbuf *m)
+{
+
+  DEBUG_CALL("m_free");
+  DEBUG_ARG("m = %p", m);
+
+  if(m) {
+       /* Remove from m_usedlist */
+       if (m->m_flags & M_USEDLIST)
+          remque(m);
+
+       /* If it's M_EXT, free() it */
+        if (m->m_flags & M_EXT) {
+                g_free(m->m_ext);
+        }
+       /*
+        * Either free() it or put it on the free list
+        */
+       if (m->m_flags & M_DOFREE) {
+               m->slirp->mbuf_alloced--;
+                g_free(m);
+       } else if ((m->m_flags & M_FREELIST) == 0) {
+               insque(m,&m->slirp->m_freelist);
+               m->m_flags = M_FREELIST; /* Clobber other flags */
+       }
+  } /* if(m) */
+}
+
+/*
+ * Copy data from one mbuf to the end of
+ * the other.. if result is too big for one mbuf, allocate
+ * an M_EXT data segment
+ */
+void
+m_cat(struct mbuf *m, struct mbuf *n)
+{
+       /*
+        * If there's no room, realloc
+        */
+       if (M_FREEROOM(m) < n->m_len)
+               m_inc(m, m->m_len + n->m_len);
+
+       memcpy(m->m_data+m->m_len, n->m_data, n->m_len);
+       m->m_len += n->m_len;
+
+       m_free(n);
+}
+
+
+/* make m 'size' bytes large from m_data */
+void
+m_inc(struct mbuf *m, int size)
+{
+    int gapsize;
+
+    /* some compilers throw up on gotos.  This one we can fake. */
+    if (M_ROOM(m) > size) {
+        return;
+    }
+
+    if (m->m_flags & M_EXT) {
+        gapsize = m->m_data - m->m_ext;
+        m->m_ext = g_realloc(m->m_ext, size + gapsize);
+    } else {
+        gapsize = m->m_data - m->m_dat;
+        m->m_ext = g_malloc(size + gapsize);
+        memcpy(m->m_ext, m->m_dat, m->m_size);
+        m->m_flags |= M_EXT;
+    }
+
+    m->m_data = m->m_ext + gapsize;
+    m->m_size = size + gapsize;
+}
+
+
+
+void
+m_adj(struct mbuf *m, int len)
+{
+       if (m == NULL)
+               return;
+       if (len >= 0) {
+               /* Trim from head */
+               m->m_data += len;
+               m->m_len -= len;
+       } else {
+               /* Trim from tail */
+               len = -len;
+               m->m_len -= len;
+       }
+}
+
+
+/*
+ * Copy len bytes from m, starting off bytes into n
+ */
+int
+m_copy(struct mbuf *n, struct mbuf *m, int off, int len)
+{
+       if (len > M_FREEROOM(n))
+               return -1;
+
+       memcpy((n->m_data + n->m_len), (m->m_data + off), len);
+       n->m_len += len;
+       return 0;
+}
+
+
+/*
+ * Given a pointer into an mbuf, return the mbuf
+ * XXX This is a kludge, I should eliminate the need for it
+ * Fortunately, it's not used often
+ */
+struct mbuf *
+dtom(Slirp *slirp, void *dat)
+{
+       struct mbuf *m;
+
+       DEBUG_CALL("dtom");
+       DEBUG_ARG("dat = %p", dat);
+
+       /* bug corrected for M_EXT buffers */
+       for (m = (struct mbuf *) slirp->m_usedlist.qh_link;
+            (struct quehead *) m != &slirp->m_usedlist;
+            m = m->m_next) {
+         if (m->m_flags & M_EXT) {
+           if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) )
+             return m;
+         } else {
+           if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) )
+             return m;
+         }
+       }
+
+       DEBUG_ERROR("dtom failed");
+
+       return (struct mbuf *)0;
+}
diff --git a/slirp/src/mbuf.h b/slirp/src/mbuf.h
new file mode 100644 (file)
index 0000000..e2d4434
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 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. 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.
+ *
+ *     @(#)mbuf.h      8.3 (Berkeley) 1/21/94
+ * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp
+ */
+
+#ifndef MBUF_H
+#define MBUF_H
+
+/*
+ * Macros for type conversion
+ * mtod(m,t) - convert mbuf pointer to data pointer of correct type
+ */
+#define mtod(m,t)      ((t)(m)->m_data)
+
+/* XXX About mbufs for slirp:
+ * Only one mbuf is ever used in a chain, for each "cell" of data.
+ * m_nextpkt points to the next packet, if fragmented.
+ * If the data is too large, the M_EXT is used, and a larger block
+ * is alloced.  Therefore, m_free[m] must check for M_EXT and if set
+ * free the m_ext.  This is inefficient memory-wise, but who cares.
+ */
+
+/*
+ * mbufs allow to have a gap between the start of the allocated buffer (m_ext if
+ * M_EXT is set, m_dat otherwise) and the in-use data:
+ *
+ *  |--gapsize----->|---m_len------->
+ *  |----------m_size------------------------------>
+ *                  |----M_ROOM-------------------->
+ *                                   |-M_FREEROOM-->
+ *
+ *  ^               ^                               ^
+ *  m_dat/m_ext     m_data                          end of buffer
+ */
+
+/*
+ * How much room is in the mbuf, from m_data to the end of the mbuf
+ */
+#define M_ROOM(m) ((m->m_flags & M_EXT)? \
+                       (((m)->m_ext + (m)->m_size) - (m)->m_data) \
+                  : \
+                       (((m)->m_dat + (m)->m_size) - (m)->m_data))
+
+/*
+ * How much free room there is
+ */
+#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len)
+
+struct mbuf {
+       /* XXX should union some of these! */
+       /* header at beginning of each mbuf: */
+       struct  mbuf *m_next;           /* Linked list of mbufs */
+       struct  mbuf *m_prev;
+       struct  mbuf *m_nextpkt;        /* Next packet in queue/record */
+       struct  mbuf *m_prevpkt;        /* Flags aren't used in the output queue */
+       int     m_flags;                /* Misc flags */
+
+       int     m_size;                 /* Size of mbuf, from m_dat or m_ext */
+       struct  socket *m_so;
+
+       char *m_data;                   /* Current location of data */
+       int     m_len;                  /* Amount of data in this mbuf, from m_data */
+
+       Slirp *slirp;
+       bool    resolution_requested;
+       uint64_t expiration_date;
+       char   *m_ext;
+       /* start of dynamic buffer area, must be last element */
+       char    m_dat[];
+};
+
+#define ifq_prev m_prev
+#define ifq_next m_next
+#define ifs_prev m_prevpkt
+#define ifs_next m_nextpkt
+#define ifq_so m_so
+
+#define M_EXT                  0x01    /* m_ext points to more (malloced) data */
+#define M_FREELIST             0x02    /* mbuf is on free list */
+#define M_USEDLIST             0x04    /* XXX mbuf is on used list (for dtom()) */
+#define M_DOFREE               0x08    /* when m_free is called on the mbuf, free()
+                                        * it rather than putting it on the free list */
+
+void m_init(Slirp *);
+void m_cleanup(Slirp *slirp);
+struct mbuf * m_get(Slirp *);
+void m_free(struct mbuf *);
+void m_cat(register struct mbuf *, register struct mbuf *);
+void m_inc(struct mbuf *, int);
+void m_adj(struct mbuf *, int);
+int m_copy(struct mbuf *, struct mbuf *, int, int);
+struct mbuf * dtom(Slirp *, void *);
+
+static inline void ifs_init(struct mbuf *ifm)
+{
+    ifm->ifs_next = ifm->ifs_prev = ifm;
+}
+
+#endif
diff --git a/slirp/src/misc.c b/slirp/src/misc.c
new file mode 100644 (file)
index 0000000..937a418
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include "slirp.h"
+
+inline void
+insque(void *a, void *b)
+{
+       register struct quehead *element = (struct quehead *) a;
+       register struct quehead *head = (struct quehead *) b;
+       element->qh_link = head->qh_link;
+       head->qh_link = (struct quehead *)element;
+       element->qh_rlink = (struct quehead *)head;
+       ((struct quehead *)(element->qh_link))->qh_rlink
+       = (struct quehead *)element;
+}
+
+inline void
+remque(void *a)
+{
+  register struct quehead *element = (struct quehead *) a;
+  ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
+  ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
+  element->qh_rlink = NULL;
+}
+
+/* TODO: IPv6 */
+struct gfwd_list *
+add_guestfwd(struct gfwd_list **ex_ptr,
+             SlirpWriteCb write_cb, void *opaque,
+             struct in_addr addr, int port)
+{
+    struct gfwd_list *f = g_new0(struct gfwd_list, 1);
+
+    f->write_cb = write_cb;
+    f->opaque = opaque;
+    f->ex_fport = port;
+    f->ex_addr = addr;
+    f->ex_next = *ex_ptr;
+    *ex_ptr = f;
+
+    return f;
+}
+
+struct gfwd_list *
+add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
+         struct in_addr addr, int port)
+{
+    struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port);
+
+    f->ex_exec = g_strdup(cmdline);
+
+    return f;
+}
+
+static int
+slirp_socketpair_with_oob(int sv[2])
+{
+    struct sockaddr_in addr = {
+        .sin_family = AF_INET,
+        .sin_port = 0,
+        .sin_addr.s_addr = INADDR_ANY,
+    };
+    socklen_t addrlen = sizeof(addr);
+    int ret, s;
+
+    sv[1] = -1;
+    s = slirp_socket(AF_INET, SOCK_STREAM, 0);
+    if (s < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
+        listen(s, 1) < 0 ||
+        getsockname(s, (struct sockaddr *)&addr, &addrlen) < 0) {
+        goto err;
+    }
+
+    sv[1] = slirp_socket(AF_INET, SOCK_STREAM, 0);
+    if (sv[1] < 0) {
+        goto err;
+    }
+    /*
+     * This connect won't block because we've already listen()ed on
+     * the server end (even though we won't accept() the connection
+     * until later on).
+     */
+    do {
+        ret = connect(sv[1], (struct sockaddr *)&addr, addrlen);
+    } while (ret < 0 && errno == EINTR);
+    if (ret < 0) {
+        goto err;
+    }
+
+    do {
+        sv[0] = accept(s, (struct sockaddr *)&addr, &addrlen);
+    } while (sv[0] < 0 && errno == EINTR);
+    if (sv[0] < 0) {
+        goto err;
+    }
+
+    closesocket(s);
+    return 0;
+
+err:
+    g_critical("slirp_socketpair(): %s", strerror(errno));
+    if (s >= 0) {
+        closesocket(s);
+    }
+    if (sv[1] >= 0) {
+        closesocket(sv[1]);
+    }
+    return -1;
+}
+
+static void
+fork_exec_child_setup(gpointer data)
+{
+#ifndef _WIN32
+    setsid();
+#endif
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+#if !GLIB_CHECK_VERSION(2, 58, 0)
+typedef struct SlirpGSpawnFds {
+    GSpawnChildSetupFunc child_setup;
+    gpointer user_data;
+    gint stdin_fd;
+    gint stdout_fd;
+    gint stderr_fd;
+} SlirpGSpawnFds;
+
+static inline void
+slirp_gspawn_fds_setup(gpointer user_data)
+{
+    SlirpGSpawnFds *q = (SlirpGSpawnFds *)user_data;
+
+    dup2(q->stdin_fd, 0);
+    dup2(q->stdout_fd, 1);
+    dup2(q->stderr_fd, 2);
+    q->child_setup(q->user_data);
+}
+#endif
+
+static inline gboolean
+g_spawn_async_with_fds_slirp(const gchar *working_directory,
+                            gchar **argv,
+                            gchar **envp,
+                            GSpawnFlags flags,
+                            GSpawnChildSetupFunc child_setup,
+                            gpointer user_data,
+                            GPid *child_pid,
+                            gint stdin_fd,
+                            gint stdout_fd,
+                            gint stderr_fd,
+                            GError **error)
+{
+#if GLIB_CHECK_VERSION(2, 58, 0)
+    return g_spawn_async_with_fds(working_directory, argv, envp, flags,
+                                  child_setup, user_data,
+                                  child_pid, stdin_fd, stdout_fd, stderr_fd,
+                                  error);
+#else
+    SlirpGSpawnFds setup = {
+        .child_setup = child_setup,
+        .user_data = user_data,
+        .stdin_fd = stdin_fd,
+        .stdout_fd = stdout_fd,
+        .stderr_fd = stderr_fd,
+    };
+
+    return g_spawn_async(working_directory, argv, envp, flags,
+                         slirp_gspawn_fds_setup, &setup,
+                         child_pid, error);
+#endif
+}
+
+#define g_spawn_async_with_fds(wd, argv, env, f, c, d, p, ifd, ofd, efd, err) \
+    g_spawn_async_with_fds_slirp(wd, argv, env, f, c, d, p, ifd, ofd, efd, err)
+
+#pragma GCC diagnostic pop
+
+int
+fork_exec(struct socket *so, const char *ex)
+{
+    GError *err = NULL;
+    char **argv;
+    int opt, sp[2];
+
+    DEBUG_CALL("fork_exec");
+    DEBUG_ARG("so = %p", so);
+    DEBUG_ARG("ex = %p", ex);
+
+    if (slirp_socketpair_with_oob(sp) < 0) {
+        return 0;
+    }
+
+    argv = g_strsplit(ex, " ", -1);
+    g_spawn_async_with_fds(NULL /* cwd */,
+                           argv,
+                           NULL /* env */,
+                           G_SPAWN_SEARCH_PATH,
+                           fork_exec_child_setup, NULL /* data */,
+                           NULL /* child_pid */,
+                           sp[1], sp[1], sp[1],
+                           &err);
+    g_strfreev(argv);
+
+    if (err) {
+        g_critical("fork_exec: %s", err->message);
+        g_error_free(err);
+        closesocket(sp[0]);
+        closesocket(sp[1]);
+        return 0;
+    }
+
+    so->s = sp[0];
+    closesocket(sp[1]);
+    slirp_socket_set_fast_reuse(so->s);
+    opt = 1;
+    setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
+    slirp_set_nonblock(so->s);
+    so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
+    return 1;
+}
+
+char *slirp_connection_info(Slirp *slirp)
+{
+    GString *str = g_string_new(NULL);
+    const char * const tcpstates[] = {
+        [TCPS_CLOSED]       = "CLOSED",
+        [TCPS_LISTEN]       = "LISTEN",
+        [TCPS_SYN_SENT]     = "SYN_SENT",
+        [TCPS_SYN_RECEIVED] = "SYN_RCVD",
+        [TCPS_ESTABLISHED]  = "ESTABLISHED",
+        [TCPS_CLOSE_WAIT]   = "CLOSE_WAIT",
+        [TCPS_FIN_WAIT_1]   = "FIN_WAIT_1",
+        [TCPS_CLOSING]      = "CLOSING",
+        [TCPS_LAST_ACK]     = "LAST_ACK",
+        [TCPS_FIN_WAIT_2]   = "FIN_WAIT_2",
+        [TCPS_TIME_WAIT]    = "TIME_WAIT",
+    };
+    struct in_addr dst_addr;
+    struct sockaddr_in src;
+    socklen_t src_len;
+    uint16_t dst_port;
+    struct socket *so;
+    const char *state;
+    char buf[20];
+
+    g_string_append_printf(str,
+        "  Protocol[State]    FD  Source Address  Port   "
+        "Dest. Address  Port RecvQ SendQ\n");
+
+    /* TODO: IPv6 */
+
+    for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
+        if (so->so_state & SS_HOSTFWD) {
+            state = "HOST_FORWARD";
+        } else if (so->so_tcpcb) {
+            state = tcpstates[so->so_tcpcb->t_state];
+        } else {
+            state = "NONE";
+        }
+        if (so->so_state & (SS_HOSTFWD | SS_INCOMING)) {
+            src_len = sizeof(src);
+            getsockname(so->s, (struct sockaddr *)&src, &src_len);
+            dst_addr = so->so_laddr;
+            dst_port = so->so_lport;
+        } else {
+            src.sin_addr = so->so_laddr;
+            src.sin_port = so->so_lport;
+            dst_addr = so->so_faddr;
+            dst_port = so->so_fport;
+        }
+        snprintf(buf, sizeof(buf), "  TCP[%s]", state);
+        g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s,
+                       src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
+                       ntohs(src.sin_port));
+        g_string_append_printf(str, "%15s %5d %5d %5d\n",
+                       inet_ntoa(dst_addr), ntohs(dst_port),
+                       so->so_rcv.sb_cc, so->so_snd.sb_cc);
+    }
+
+    for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) {
+        if (so->so_state & SS_HOSTFWD) {
+            snprintf(buf, sizeof(buf), "  UDP[HOST_FORWARD]");
+            src_len = sizeof(src);
+            getsockname(so->s, (struct sockaddr *)&src, &src_len);
+            dst_addr = so->so_laddr;
+            dst_port = so->so_lport;
+        } else {
+            snprintf(buf, sizeof(buf), "  UDP[%d sec]",
+                         (so->so_expire - curtime) / 1000);
+            src.sin_addr = so->so_laddr;
+            src.sin_port = so->so_lport;
+            dst_addr = so->so_faddr;
+            dst_port = so->so_fport;
+        }
+        g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s,
+                       src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
+                       ntohs(src.sin_port));
+        g_string_append_printf(str, "%15s %5d %5d %5d\n",
+                       inet_ntoa(dst_addr), ntohs(dst_port),
+                       so->so_rcv.sb_cc, so->so_snd.sb_cc);
+    }
+
+    for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) {
+        snprintf(buf, sizeof(buf), "  ICMP[%d sec]",
+                     (so->so_expire - curtime) / 1000);
+        src.sin_addr = so->so_laddr;
+        dst_addr = so->so_faddr;
+        g_string_append_printf(str, "%-19s %3d %15s  -    ", buf, so->s,
+                       src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*");
+        g_string_append_printf(str, "%15s  -    %5d %5d\n", inet_ntoa(dst_addr),
+                       so->so_rcv.sb_cc, so->so_snd.sb_cc);
+    }
+
+    return g_string_free(str, FALSE);
+}
diff --git a/slirp/src/misc.h b/slirp/src/misc.h
new file mode 100644 (file)
index 0000000..c2ceadb
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef MISC_H
+#define MISC_H
+
+#include "libslirp.h"
+
+struct gfwd_list {
+       SlirpWriteCb write_cb;
+       void *opaque;
+       struct in_addr ex_addr;         /* Server address */
+       int ex_fport;                   /* Port to telnet to */
+       char *ex_exec;                  /* Command line of what to exec */
+       struct gfwd_list *ex_next;
+};
+
+#define EMU_NONE 0x0
+
+/* TCP emulations */
+#define EMU_CTL 0x1
+#define EMU_FTP 0x2
+#define EMU_KSH 0x3
+#define EMU_IRC 0x4
+#define EMU_REALAUDIO 0x5
+#define EMU_RLOGIN 0x6
+#define EMU_IDENT 0x7
+
+#define EMU_NOCONNECT 0x10     /* Don't connect */
+
+struct tos_t {
+    uint16_t lport;
+    uint16_t fport;
+    uint8_t tos;
+    uint8_t emu;
+};
+
+struct emu_t {
+    uint16_t lport;
+    uint16_t fport;
+    uint8_t tos;
+    uint8_t emu;
+    struct emu_t *next;
+};
+
+struct slirp_quehead {
+    struct slirp_quehead *qh_link;
+    struct slirp_quehead *qh_rlink;
+};
+
+void slirp_insque(void *, void *);
+void slirp_remque(void *);
+int fork_exec(struct socket *so, const char *ex);
+
+struct gfwd_list *
+add_guestfwd(struct gfwd_list **ex_ptr,
+             SlirpWriteCb write_cb, void *opaque,
+             struct in_addr addr, int port);
+
+struct gfwd_list *
+add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
+         struct in_addr addr, int port);
+
+#endif
diff --git a/slirp/src/ncsi-pkt.h b/slirp/src/ncsi-pkt.h
new file mode 100644 (file)
index 0000000..ea07d1c
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * Copyright Gavin Shan, IBM Corporation 2016.
+ *
+ * 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.
+ */
+
+#ifndef NCSI_PKT_H
+#define NCSI_PKT_H
+
+/* from linux/net/ncsi/ncsi-pkt.h */
+#define __be32 uint32_t
+#define __be16 uint16_t
+
+struct ncsi_pkt_hdr {
+        unsigned char mc_id;        /* Management controller ID */
+        unsigned char revision;     /* NCSI version - 0x01      */
+        unsigned char reserved;     /* Reserved                 */
+        unsigned char id;           /* Packet sequence number   */
+        unsigned char type;         /* Packet type              */
+        unsigned char channel;      /* Network controller ID    */
+        __be16        length;       /* Payload length           */
+        __be32        reserved1[2]; /* Reserved                 */
+};
+
+struct ncsi_cmd_pkt_hdr {
+        struct ncsi_pkt_hdr common; /* Common NCSI packet header */
+};
+
+struct ncsi_rsp_pkt_hdr {
+        struct ncsi_pkt_hdr common; /* Common NCSI packet header */
+        __be16              code;   /* Response code             */
+        __be16              reason; /* Response reason           */
+};
+
+struct ncsi_aen_pkt_hdr {
+        struct ncsi_pkt_hdr common;       /* Common NCSI packet header */
+        unsigned char       reserved2[3]; /* Reserved                  */
+        unsigned char       type;         /* AEN packet type           */
+};
+
+/* NCSI common command packet */
+struct ncsi_cmd_pkt {
+        struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+        __be32                  checksum; /* Checksum       */
+        unsigned char           pad[26];
+};
+
+struct ncsi_rsp_pkt {
+        struct ncsi_rsp_pkt_hdr rsp;      /* Response header */
+        __be32                  checksum; /* Checksum        */
+        unsigned char           pad[22];
+};
+
+/* Select Package */
+struct ncsi_cmd_sp_pkt {
+        struct ncsi_cmd_pkt_hdr cmd;            /* Command header */
+        unsigned char           reserved[3];    /* Reserved       */
+        unsigned char           hw_arbitration; /* HW arbitration */
+        __be32                  checksum;       /* Checksum       */
+        unsigned char           pad[22];
+};
+
+/* Disable Channel */
+struct ncsi_cmd_dc_pkt {
+        struct ncsi_cmd_pkt_hdr cmd;         /* Command header  */
+        unsigned char           reserved[3]; /* Reserved        */
+        unsigned char           ald;         /* Allow link down */
+        __be32                  checksum;    /* Checksum        */
+        unsigned char           pad[22];
+};
+
+/* Reset Channel */
+struct ncsi_cmd_rc_pkt {
+        struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+        __be32                  reserved; /* Reserved       */
+        __be32                  checksum; /* Checksum       */
+        unsigned char           pad[22];
+};
+
+/* AEN Enable */
+struct ncsi_cmd_ae_pkt {
+        struct ncsi_cmd_pkt_hdr cmd;         /* Command header   */
+        unsigned char           reserved[3]; /* Reserved         */
+        unsigned char           mc_id;       /* MC ID            */
+        __be32                  mode;        /* AEN working mode */
+        __be32                  checksum;    /* Checksum         */
+        unsigned char           pad[18];
+};
+
+/* Set Link */
+struct ncsi_cmd_sl_pkt {
+        struct ncsi_cmd_pkt_hdr cmd;      /* Command header    */
+        __be32                  mode;     /* Link working mode */
+        __be32                  oem_mode; /* OEM link mode     */
+        __be32                  checksum; /* Checksum          */
+        unsigned char           pad[18];
+};
+
+/* Set VLAN Filter */
+struct ncsi_cmd_svf_pkt {
+        struct ncsi_cmd_pkt_hdr cmd;       /* Command header    */
+        __be16                  reserved;  /* Reserved          */
+        __be16                  vlan;      /* VLAN ID           */
+        __be16                  reserved1; /* Reserved          */
+        unsigned char           index;     /* VLAN table index  */
+        unsigned char           enable;    /* Enable or disable */
+        __be32                  checksum;  /* Checksum          */
+        unsigned char           pad[14];
+};
+
+/* Enable VLAN */
+struct ncsi_cmd_ev_pkt {
+        struct ncsi_cmd_pkt_hdr cmd;         /* Command header   */
+        unsigned char           reserved[3]; /* Reserved         */
+        unsigned char           mode;        /* VLAN filter mode */
+        __be32                  checksum;    /* Checksum         */
+        unsigned char           pad[22];
+};
+
+/* Set MAC Address */
+struct ncsi_cmd_sma_pkt {
+        struct ncsi_cmd_pkt_hdr cmd;      /* Command header          */
+        unsigned char           mac[6];   /* MAC address             */
+        unsigned char           index;    /* MAC table index         */
+        unsigned char           at_e;     /* Addr type and operation */
+        __be32                  checksum; /* Checksum                */
+        unsigned char           pad[18];
+};
+
+/* Enable Broadcast Filter */
+struct ncsi_cmd_ebf_pkt {
+        struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+        __be32                  mode;     /* Filter mode    */
+        __be32                  checksum; /* Checksum       */
+        unsigned char           pad[22];
+};
+
+/* Enable Global Multicast Filter */
+struct ncsi_cmd_egmf_pkt {
+        struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+        __be32                  mode;     /* Global MC mode */
+        __be32                  checksum; /* Checksum       */
+        unsigned char           pad[22];
+};
+
+/* Set NCSI Flow Control */
+struct ncsi_cmd_snfc_pkt {
+        struct ncsi_cmd_pkt_hdr cmd;         /* Command header    */
+        unsigned char           reserved[3]; /* Reserved          */
+        unsigned char           mode;        /* Flow control mode */
+        __be32                  checksum;    /* Checksum          */
+        unsigned char           pad[22];
+};
+
+/* Get Link Status */
+struct ncsi_rsp_gls_pkt {
+        struct ncsi_rsp_pkt_hdr rsp;        /* Response header   */
+        __be32                  status;     /* Link status       */
+        __be32                  other;      /* Other indications */
+        __be32                  oem_status; /* OEM link status   */
+        __be32                  checksum;
+        unsigned char           pad[10];
+};
+
+/* Get Version ID */
+struct ncsi_rsp_gvi_pkt {
+        struct ncsi_rsp_pkt_hdr rsp;          /* Response header */
+        __be32                  ncsi_version; /* NCSI version    */
+        unsigned char           reserved[3];  /* Reserved        */
+        unsigned char           alpha2;       /* NCSI version    */
+        unsigned char           fw_name[12];  /* f/w name string */
+        __be32                  fw_version;   /* f/w version     */
+        __be16                  pci_ids[4];   /* PCI IDs         */
+        __be32                  mf_id;        /* Manufacture ID  */
+        __be32                  checksum;
+};
+
+/* Get Capabilities */
+struct ncsi_rsp_gc_pkt {
+        struct ncsi_rsp_pkt_hdr rsp;         /* Response header   */
+        __be32                  cap;         /* Capabilities      */
+        __be32                  bc_cap;      /* Broadcast cap     */
+        __be32                  mc_cap;      /* Multicast cap     */
+        __be32                  buf_cap;     /* Buffering cap     */
+        __be32                  aen_cap;     /* AEN cap           */
+        unsigned char           vlan_cnt;    /* VLAN filter count */
+        unsigned char           mixed_cnt;   /* Mix filter count  */
+        unsigned char           mc_cnt;      /* MC filter count   */
+        unsigned char           uc_cnt;      /* UC filter count   */
+        unsigned char           reserved[2]; /* Reserved          */
+        unsigned char           vlan_mode;   /* VLAN mode         */
+        unsigned char           channel_cnt; /* Channel count     */
+        __be32                  checksum;    /* Checksum          */
+};
+
+/* Get Parameters */
+struct ncsi_rsp_gp_pkt {
+        struct ncsi_rsp_pkt_hdr rsp;          /* Response header       */
+        unsigned char           mac_cnt;      /* Number of MAC addr    */
+        unsigned char           reserved[2];  /* Reserved              */
+        unsigned char           mac_enable;   /* MAC addr enable flags */
+        unsigned char           vlan_cnt;     /* VLAN tag count        */
+        unsigned char           reserved1;    /* Reserved              */
+        __be16                  vlan_enable;  /* VLAN tag enable flags */
+        __be32                  link_mode;    /* Link setting          */
+        __be32                  bc_mode;      /* BC filter mode        */
+        __be32                  valid_modes;  /* Valid mode parameters */
+        unsigned char           vlan_mode;    /* VLAN mode             */
+        unsigned char           fc_mode;      /* Flow control mode     */
+        unsigned char           reserved2[2]; /* Reserved              */
+        __be32                  aen_mode;     /* AEN mode              */
+        unsigned char           mac[6];       /* Supported MAC addr    */
+        __be16                  vlan;         /* Supported VLAN tags   */
+        __be32                  checksum;     /* Checksum              */
+};
+
+/* Get Controller Packet Statistics */
+struct ncsi_rsp_gcps_pkt {
+        struct ncsi_rsp_pkt_hdr rsp;            /* Response header            */
+        __be32                  cnt_hi;         /* Counter cleared            */
+        __be32                  cnt_lo;         /* Counter cleared            */
+        __be32                  rx_bytes;       /* Rx bytes                   */
+        __be32                  tx_bytes;       /* Tx bytes                   */
+        __be32                  rx_uc_pkts;     /* Rx UC packets              */
+        __be32                  rx_mc_pkts;     /* Rx MC packets              */
+        __be32                  rx_bc_pkts;     /* Rx BC packets              */
+        __be32                  tx_uc_pkts;     /* Tx UC packets              */
+        __be32                  tx_mc_pkts;     /* Tx MC packets              */
+        __be32                  tx_bc_pkts;     /* Tx BC packets              */
+        __be32                  fcs_err;        /* FCS errors                 */
+        __be32                  align_err;      /* Alignment errors           */
+        __be32                  false_carrier;  /* False carrier detection    */
+        __be32                  runt_pkts;      /* Rx runt packets            */
+        __be32                  jabber_pkts;    /* Rx jabber packets          */
+        __be32                  rx_pause_xon;   /* Rx pause XON frames        */
+        __be32                  rx_pause_xoff;  /* Rx XOFF frames             */
+        __be32                  tx_pause_xon;   /* Tx XON frames              */
+        __be32                  tx_pause_xoff;  /* Tx XOFF frames             */
+        __be32                  tx_s_collision; /* Single collision frames    */
+        __be32                  tx_m_collision; /* Multiple collision frames  */
+        __be32                  l_collision;    /* Late collision frames      */
+        __be32                  e_collision;    /* Excessive collision frames */
+        __be32                  rx_ctl_frames;  /* Rx control frames          */
+        __be32                  rx_64_frames;   /* Rx 64-bytes frames         */
+        __be32                  rx_127_frames;  /* Rx 65-127 bytes frames     */
+        __be32                  rx_255_frames;  /* Rx 128-255 bytes frames    */
+        __be32                  rx_511_frames;  /* Rx 256-511 bytes frames    */
+        __be32                  rx_1023_frames; /* Rx 512-1023 bytes frames   */
+        __be32                  rx_1522_frames; /* Rx 1024-1522 bytes frames  */
+        __be32                  rx_9022_frames; /* Rx 1523-9022 bytes frames  */
+        __be32                  tx_64_frames;   /* Tx 64-bytes frames         */
+        __be32                  tx_127_frames;  /* Tx 65-127 bytes frames     */
+        __be32                  tx_255_frames;  /* Tx 128-255 bytes frames    */
+        __be32                  tx_511_frames;  /* Tx 256-511 bytes frames    */
+        __be32                  tx_1023_frames; /* Tx 512-1023 bytes frames   */
+        __be32                  tx_1522_frames; /* Tx 1024-1522 bytes frames  */
+        __be32                  tx_9022_frames; /* Tx 1523-9022 bytes frames  */
+        __be32                  rx_valid_bytes; /* Rx valid bytes             */
+        __be32                  rx_runt_pkts;   /* Rx error runt packets      */
+        __be32                  rx_jabber_pkts; /* Rx error jabber packets    */
+        __be32                  checksum;       /* Checksum                   */
+};
+
+/* Get NCSI Statistics */
+struct ncsi_rsp_gns_pkt {
+        struct ncsi_rsp_pkt_hdr rsp;           /* Response header         */
+        __be32                  rx_cmds;       /* Rx NCSI commands        */
+        __be32                  dropped_cmds;  /* Dropped commands        */
+        __be32                  cmd_type_errs; /* Command type errors     */
+        __be32                  cmd_csum_errs; /* Command checksum errors */
+        __be32                  rx_pkts;       /* Rx NCSI packets         */
+        __be32                  tx_pkts;       /* Tx NCSI packets         */
+        __be32                  tx_aen_pkts;   /* Tx AEN packets          */
+        __be32                  checksum;      /* Checksum                */
+};
+
+/* Get NCSI Pass-through Statistics */
+struct ncsi_rsp_gnpts_pkt {
+        struct ncsi_rsp_pkt_hdr rsp;            /* Response header     */
+        __be32                  tx_pkts;        /* Tx packets          */
+        __be32                  tx_dropped;     /* Tx dropped packets  */
+        __be32                  tx_channel_err; /* Tx channel errors   */
+        __be32                  tx_us_err;      /* Tx undersize errors */
+        __be32                  rx_pkts;        /* Rx packets          */
+        __be32                  rx_dropped;     /* Rx dropped packets  */
+        __be32                  rx_channel_err; /* Rx channel errors   */
+        __be32                  rx_us_err;      /* Rx undersize errors */
+        __be32                  rx_os_err;      /* Rx oversize errors  */
+        __be32                  checksum;       /* Checksum            */
+};
+
+/* Get package status */
+struct ncsi_rsp_gps_pkt {
+        struct ncsi_rsp_pkt_hdr rsp;      /* Response header             */
+        __be32                  status;   /* Hardware arbitration status */
+        __be32                  checksum;
+};
+
+/* Get package UUID */
+struct ncsi_rsp_gpuuid_pkt {
+        struct ncsi_rsp_pkt_hdr rsp;      /* Response header */
+        unsigned char           uuid[16]; /* UUID            */
+        __be32                  checksum;
+};
+
+/* AEN: Link State Change */
+struct ncsi_aen_lsc_pkt {
+        struct ncsi_aen_pkt_hdr aen;        /* AEN header      */
+        __be32                  status;     /* Link status     */
+        __be32                  oem_status; /* OEM link status */
+        __be32                  checksum;   /* Checksum        */
+        unsigned char           pad[14];
+};
+
+/* AEN: Configuration Required */
+struct ncsi_aen_cr_pkt {
+        struct ncsi_aen_pkt_hdr aen;      /* AEN header */
+        __be32                  checksum; /* Checksum   */
+        unsigned char           pad[22];
+};
+
+/* AEN: Host Network Controller Driver Status Change */
+struct ncsi_aen_hncdsc_pkt {
+        struct ncsi_aen_pkt_hdr aen;      /* AEN header */
+        __be32                  status;   /* Status     */
+        __be32                  checksum; /* Checksum   */
+        unsigned char           pad[18];
+};
+
+/* NCSI packet revision */
+#define NCSI_PKT_REVISION       0x01
+
+/* NCSI packet commands */
+#define NCSI_PKT_CMD_CIS        0x00 /* Clear Initial State              */
+#define NCSI_PKT_CMD_SP         0x01 /* Select Package                   */
+#define NCSI_PKT_CMD_DP         0x02 /* Deselect Package                 */
+#define NCSI_PKT_CMD_EC         0x03 /* Enable Channel                   */
+#define NCSI_PKT_CMD_DC         0x04 /* Disable Channel                  */
+#define NCSI_PKT_CMD_RC         0x05 /* Reset Channel                    */
+#define NCSI_PKT_CMD_ECNT       0x06 /* Enable Channel Network Tx        */
+#define NCSI_PKT_CMD_DCNT       0x07 /* Disable Channel Network Tx       */
+#define NCSI_PKT_CMD_AE         0x08 /* AEN Enable                       */
+#define NCSI_PKT_CMD_SL         0x09 /* Set Link                         */
+#define NCSI_PKT_CMD_GLS        0x0a /* Get Link                         */
+#define NCSI_PKT_CMD_SVF        0x0b /* Set VLAN Filter                  */
+#define NCSI_PKT_CMD_EV         0x0c /* Enable VLAN                      */
+#define NCSI_PKT_CMD_DV         0x0d /* Disable VLAN                     */
+#define NCSI_PKT_CMD_SMA        0x0e /* Set MAC address                  */
+#define NCSI_PKT_CMD_EBF        0x10 /* Enable Broadcast Filter          */
+#define NCSI_PKT_CMD_DBF        0x11 /* Disable Broadcast Filter         */
+#define NCSI_PKT_CMD_EGMF       0x12 /* Enable Global Multicast Filter   */
+#define NCSI_PKT_CMD_DGMF       0x13 /* Disable Global Multicast Filter  */
+#define NCSI_PKT_CMD_SNFC       0x14 /* Set NCSI Flow Control            */
+#define NCSI_PKT_CMD_GVI        0x15 /* Get Version ID                   */
+#define NCSI_PKT_CMD_GC         0x16 /* Get Capabilities                 */
+#define NCSI_PKT_CMD_GP         0x17 /* Get Parameters                   */
+#define NCSI_PKT_CMD_GCPS       0x18 /* Get Controller Packet Statistics */
+#define NCSI_PKT_CMD_GNS        0x19 /* Get NCSI Statistics              */
+#define NCSI_PKT_CMD_GNPTS      0x1a /* Get NCSI Pass-throu Statistics   */
+#define NCSI_PKT_CMD_GPS        0x1b /* Get package status               */
+#define NCSI_PKT_CMD_OEM        0x50 /* OEM                              */
+#define NCSI_PKT_CMD_PLDM       0x51 /* PLDM request over NCSI over RBT  */
+#define NCSI_PKT_CMD_GPUUID     0x52 /* Get package UUID                 */
+
+/* NCSI packet responses */
+#define NCSI_PKT_RSP_CIS        (NCSI_PKT_CMD_CIS    + 0x80)
+#define NCSI_PKT_RSP_SP         (NCSI_PKT_CMD_SP     + 0x80)
+#define NCSI_PKT_RSP_DP         (NCSI_PKT_CMD_DP     + 0x80)
+#define NCSI_PKT_RSP_EC         (NCSI_PKT_CMD_EC     + 0x80)
+#define NCSI_PKT_RSP_DC         (NCSI_PKT_CMD_DC     + 0x80)
+#define NCSI_PKT_RSP_RC         (NCSI_PKT_CMD_RC     + 0x80)
+#define NCSI_PKT_RSP_ECNT       (NCSI_PKT_CMD_ECNT   + 0x80)
+#define NCSI_PKT_RSP_DCNT       (NCSI_PKT_CMD_DCNT   + 0x80)
+#define NCSI_PKT_RSP_AE         (NCSI_PKT_CMD_AE     + 0x80)
+#define NCSI_PKT_RSP_SL         (NCSI_PKT_CMD_SL     + 0x80)
+#define NCSI_PKT_RSP_GLS        (NCSI_PKT_CMD_GLS    + 0x80)
+#define NCSI_PKT_RSP_SVF        (NCSI_PKT_CMD_SVF    + 0x80)
+#define NCSI_PKT_RSP_EV         (NCSI_PKT_CMD_EV     + 0x80)
+#define NCSI_PKT_RSP_DV         (NCSI_PKT_CMD_DV     + 0x80)
+#define NCSI_PKT_RSP_SMA        (NCSI_PKT_CMD_SMA    + 0x80)
+#define NCSI_PKT_RSP_EBF        (NCSI_PKT_CMD_EBF    + 0x80)
+#define NCSI_PKT_RSP_DBF        (NCSI_PKT_CMD_DBF    + 0x80)
+#define NCSI_PKT_RSP_EGMF       (NCSI_PKT_CMD_EGMF   + 0x80)
+#define NCSI_PKT_RSP_DGMF       (NCSI_PKT_CMD_DGMF   + 0x80)
+#define NCSI_PKT_RSP_SNFC       (NCSI_PKT_CMD_SNFC   + 0x80)
+#define NCSI_PKT_RSP_GVI        (NCSI_PKT_CMD_GVI    + 0x80)
+#define NCSI_PKT_RSP_GC         (NCSI_PKT_CMD_GC     + 0x80)
+#define NCSI_PKT_RSP_GP         (NCSI_PKT_CMD_GP     + 0x80)
+#define NCSI_PKT_RSP_GCPS       (NCSI_PKT_CMD_GCPS   + 0x80)
+#define NCSI_PKT_RSP_GNS        (NCSI_PKT_CMD_GNS    + 0x80)
+#define NCSI_PKT_RSP_GNPTS      (NCSI_PKT_CMD_GNPTS  + 0x80)
+#define NCSI_PKT_RSP_GPS        (NCSI_PKT_CMD_GPS    + 0x80)
+#define NCSI_PKT_RSP_OEM        (NCSI_PKT_CMD_OEM    + 0x80)
+#define NCSI_PKT_RSP_PLDM       (NCSI_PKT_CMD_PLDM   + 0x80)
+#define NCSI_PKT_RSP_GPUUID     (NCSI_PKT_CMD_GPUUID + 0x80)
+
+/* NCSI response code/reason */
+#define NCSI_PKT_RSP_C_COMPLETED        0x0000 /* Command Completed        */
+#define NCSI_PKT_RSP_C_FAILED           0x0001 /* Command Failed           */
+#define NCSI_PKT_RSP_C_UNAVAILABLE      0x0002 /* Command Unavailable      */
+#define NCSI_PKT_RSP_C_UNSUPPORTED      0x0003 /* Command Unsupported      */
+#define NCSI_PKT_RSP_R_NO_ERROR         0x0000 /* No Error                 */
+#define NCSI_PKT_RSP_R_INTERFACE        0x0001 /* Interface not ready      */
+#define NCSI_PKT_RSP_R_PARAM            0x0002 /* Invalid Parameter        */
+#define NCSI_PKT_RSP_R_CHANNEL          0x0003 /* Channel not Ready        */
+#define NCSI_PKT_RSP_R_PACKAGE          0x0004 /* Package not Ready        */
+#define NCSI_PKT_RSP_R_LENGTH           0x0005 /* Invalid payload length   */
+#define NCSI_PKT_RSP_R_UNKNOWN          0x7fff /* Command type unsupported */
+
+/* NCSI AEN packet type */
+#define NCSI_PKT_AEN            0xFF /* AEN Packet               */
+#define NCSI_PKT_AEN_LSC        0x00 /* Link status change       */
+#define NCSI_PKT_AEN_CR         0x01 /* Configuration required   */
+#define NCSI_PKT_AEN_HNCDSC     0x02 /* HNC driver status change */
+
+#endif /* NCSI_PKT_H */
diff --git a/slirp/src/ncsi.c b/slirp/src/ncsi.c
new file mode 100644 (file)
index 0000000..359f52c
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * NC-SI (Network Controller Sideband Interface) "echo" model
+ *
+ * Copyright (C) 2016-2018 IBM Corp.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+#include "slirp.h"
+
+#include "ncsi-pkt.h"
+
+static uint32_t ncsi_calculate_checksum(uint16_t *data, int len)
+{
+    uint32_t checksum = 0;
+    int i;
+
+    /*
+     * 32-bit unsigned sum of the NC-SI packet header and NC-SI packet
+     * payload interpreted as a series of 16-bit unsigned integer values.
+     */
+    for (i = 0; i < len; i++) {
+        checksum += htons(data[i]);
+    }
+
+    checksum = (~checksum + 1);
+    return checksum;
+}
+
+/* Get Capabilities */
+static int ncsi_rsp_handler_gc(struct ncsi_rsp_pkt_hdr *rnh)
+{
+    struct ncsi_rsp_gc_pkt *rsp = (struct ncsi_rsp_gc_pkt *) rnh;
+
+    rsp->cap = htonl(~0);
+    rsp->bc_cap = htonl(~0);
+    rsp->mc_cap = htonl(~0);
+    rsp->buf_cap = htonl(~0);
+    rsp->aen_cap = htonl(~0);
+    rsp->vlan_mode = 0xff;
+    rsp->uc_cnt = 2;
+    return 0;
+}
+
+/* Get Link status */
+static int ncsi_rsp_handler_gls(struct ncsi_rsp_pkt_hdr *rnh)
+{
+    struct ncsi_rsp_gls_pkt *rsp = (struct ncsi_rsp_gls_pkt *) rnh;
+
+    rsp->status = htonl(0x1);
+    return 0;
+}
+
+/* Get Parameters */
+static int ncsi_rsp_handler_gp(struct ncsi_rsp_pkt_hdr *rnh)
+{
+    struct ncsi_rsp_gp_pkt *rsp = (struct ncsi_rsp_gp_pkt *) rnh;
+
+    /* no MAC address filters or VLAN filters on the channel */
+    rsp->mac_cnt = 0;
+    rsp->mac_enable = 0;
+    rsp->vlan_cnt = 0;
+    rsp->vlan_enable = 0;
+
+    return 0;
+}
+
+static const struct ncsi_rsp_handler {
+        unsigned char   type;
+        int             payload;
+        int             (*handler)(struct ncsi_rsp_pkt_hdr *rnh);
+} ncsi_rsp_handlers[] = {
+        { NCSI_PKT_RSP_CIS,     4, NULL },
+        { NCSI_PKT_RSP_SP,      4, NULL },
+        { NCSI_PKT_RSP_DP,      4, NULL },
+        { NCSI_PKT_RSP_EC,      4, NULL },
+        { NCSI_PKT_RSP_DC,      4, NULL },
+        { NCSI_PKT_RSP_RC,      4, NULL },
+        { NCSI_PKT_RSP_ECNT,    4, NULL },
+        { NCSI_PKT_RSP_DCNT,    4, NULL },
+        { NCSI_PKT_RSP_AE,      4, NULL },
+        { NCSI_PKT_RSP_SL,      4, NULL },
+        { NCSI_PKT_RSP_GLS,    16, ncsi_rsp_handler_gls },
+        { NCSI_PKT_RSP_SVF,     4, NULL },
+        { NCSI_PKT_RSP_EV,      4, NULL },
+        { NCSI_PKT_RSP_DV,      4, NULL },
+        { NCSI_PKT_RSP_SMA,     4, NULL },
+        { NCSI_PKT_RSP_EBF,     4, NULL },
+        { NCSI_PKT_RSP_DBF,     4, NULL },
+        { NCSI_PKT_RSP_EGMF,    4, NULL },
+        { NCSI_PKT_RSP_DGMF,    4, NULL },
+        { NCSI_PKT_RSP_SNFC,    4, NULL },
+        { NCSI_PKT_RSP_GVI,    40, NULL },
+        { NCSI_PKT_RSP_GC,     32, ncsi_rsp_handler_gc },
+        { NCSI_PKT_RSP_GP,     40, ncsi_rsp_handler_gp },
+        { NCSI_PKT_RSP_GCPS,  172, NULL },
+        { NCSI_PKT_RSP_GNS,   172, NULL },
+        { NCSI_PKT_RSP_GNPTS, 172, NULL },
+        { NCSI_PKT_RSP_GPS,     8, NULL },
+        { NCSI_PKT_RSP_OEM,     0, NULL },
+        { NCSI_PKT_RSP_PLDM,    0, NULL },
+        { NCSI_PKT_RSP_GPUUID, 20, NULL }
+};
+
+/*
+ * packet format : ncsi header + payload + checksum
+ */
+#define NCSI_MAX_PAYLOAD 172
+#define NCSI_MAX_LEN     (sizeof(struct ncsi_pkt_hdr) + NCSI_MAX_PAYLOAD + 4)
+
+void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
+{
+    struct ncsi_pkt_hdr *nh = (struct ncsi_pkt_hdr *)(pkt + ETH_HLEN);
+    uint8_t ncsi_reply[ETH_HLEN + NCSI_MAX_LEN];
+    struct ethhdr *reh = (struct ethhdr *)ncsi_reply;
+    struct ncsi_rsp_pkt_hdr *rnh = (struct ncsi_rsp_pkt_hdr *)
+        (ncsi_reply + ETH_HLEN);
+    const struct ncsi_rsp_handler *handler = NULL;
+    int i;
+    int ncsi_rsp_len = sizeof(*nh);
+    uint32_t checksum;
+    uint32_t *pchecksum;
+
+    memset(ncsi_reply, 0, sizeof(ncsi_reply));
+
+    memset(reh->h_dest, 0xff, ETH_ALEN);
+    memset(reh->h_source, 0xff, ETH_ALEN);
+    reh->h_proto = htons(ETH_P_NCSI);
+
+    for (i = 0; i < G_N_ELEMENTS(ncsi_rsp_handlers); i++) {
+        if (ncsi_rsp_handlers[i].type == nh->type + 0x80) {
+            handler = &ncsi_rsp_handlers[i];
+            break;
+        }
+    }
+
+    rnh->common.mc_id      = nh->mc_id;
+    rnh->common.revision   = NCSI_PKT_REVISION;
+    rnh->common.id         = nh->id;
+    rnh->common.type       = nh->type + 0x80;
+    rnh->common.channel    = nh->channel;
+
+    if (handler) {
+        rnh->common.length = htons(handler->payload);
+        rnh->code          = htons(NCSI_PKT_RSP_C_COMPLETED);
+        rnh->reason        = htons(NCSI_PKT_RSP_R_NO_ERROR);
+
+        if (handler->handler) {
+            /* TODO: handle errors */
+            handler->handler(rnh);
+        }
+        ncsi_rsp_len += handler->payload;
+    } else {
+        rnh->common.length = 0;
+        rnh->code          = htons(NCSI_PKT_RSP_C_UNAVAILABLE);
+        rnh->reason        = htons(NCSI_PKT_RSP_R_UNKNOWN);
+    }
+
+    /* Add the optional checksum at the end of the frame. */
+    checksum = ncsi_calculate_checksum((uint16_t *) rnh, ncsi_rsp_len);
+    pchecksum = (uint32_t *)((void *) rnh + ncsi_rsp_len);
+    *pchecksum = htonl(checksum);
+    ncsi_rsp_len += 4;
+
+    slirp_send_packet_all(slirp, ncsi_reply, ETH_HLEN + ncsi_rsp_len);
+}
diff --git a/slirp/src/ndp_table.c b/slirp/src/ndp_table.c
new file mode 100644 (file)
index 0000000..34ea4fd
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ */
+
+#include "slirp.h"
+
+void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
+                    uint8_t ethaddr[ETH_ALEN])
+{
+    char addrstr[INET6_ADDRSTRLEN];
+    NdpTable *ndp_table = &slirp->ndp_table;
+    int i;
+
+    inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
+
+    DEBUG_CALL("ndp_table_add");
+    DEBUG_ARG("ip = %s", addrstr);
+    DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
+              ethaddr[0], ethaddr[1], ethaddr[2],
+              ethaddr[3], ethaddr[4], ethaddr[5]);
+
+    if (IN6_IS_ADDR_MULTICAST(&ip_addr) || in6_zero(&ip_addr)) {
+        /* Do not register multicast or unspecified addresses */
+        DEBUG_CALL(" abort: do not register multicast or unspecified address");
+        return;
+    }
+
+    /* Search for an entry */
+    for (i = 0; i < NDP_TABLE_SIZE; i++) {
+        if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) {
+            DEBUG_CALL(" already in table: update the entry");
+            /* Update the entry */
+            memcpy(ndp_table->table[i].eth_addr, ethaddr, ETH_ALEN);
+            return;
+        }
+    }
+
+    /* No entry found, create a new one */
+    DEBUG_CALL(" create new entry");
+    ndp_table->table[ndp_table->next_victim].ip_addr = ip_addr;
+    memcpy(ndp_table->table[ndp_table->next_victim].eth_addr,
+            ethaddr, ETH_ALEN);
+    ndp_table->next_victim = (ndp_table->next_victim + 1) % NDP_TABLE_SIZE;
+}
+
+bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
+                      uint8_t out_ethaddr[ETH_ALEN])
+{
+    char addrstr[INET6_ADDRSTRLEN];
+    NdpTable *ndp_table = &slirp->ndp_table;
+    int i;
+
+    inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
+
+    DEBUG_CALL("ndp_table_search");
+    DEBUG_ARG("ip = %s", addrstr);
+
+    assert(!in6_zero(&ip_addr));
+
+    /* Multicast address: fec0::abcd:efgh/8 -> 33:33:ab:cd:ef:gh */
+    if (IN6_IS_ADDR_MULTICAST(&ip_addr)) {
+        out_ethaddr[0] = 0x33; out_ethaddr[1] = 0x33;
+        out_ethaddr[2] = ip_addr.s6_addr[12];
+        out_ethaddr[3] = ip_addr.s6_addr[13];
+        out_ethaddr[4] = ip_addr.s6_addr[14];
+        out_ethaddr[5] = ip_addr.s6_addr[15];
+        DEBUG_ARG("multicast addr = %02x:%02x:%02x:%02x:%02x:%02x",
+                  out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
+                  out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
+        return 1;
+    }
+
+    for (i = 0; i < NDP_TABLE_SIZE; i++) {
+        if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) {
+            memcpy(out_ethaddr, ndp_table->table[i].eth_addr,  ETH_ALEN);
+            DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
+                      out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
+                      out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
+            return 1;
+        }
+    }
+
+    DEBUG_CALL(" ip not found in table");
+    return 0;
+}
diff --git a/slirp/src/qtailq.h b/slirp/src/qtailq.h
new file mode 100644 (file)
index 0000000..a89b0c4
--- /dev/null
@@ -0,0 +1,193 @@
+/*      $NetBSD: queue.h,v 1.52 2009/04/20 09:56:08 mschuett Exp $ */
+
+/*
+ * slirp version: Copy from QEMU, removed all but tail queues.
+ */
+
+/*
+ * Copyright (c) 1991, 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. 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.
+ *
+ *      @(#)queue.h     8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef QTAILQ_H
+#define QTAILQ_H
+
+/*
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ */
+typedef struct QTailQLink {
+    void *tql_next;
+    struct QTailQLink *tql_prev;
+} QTailQLink;
+
+/*
+ * Tail queue definitions.  The union acts as a poor man template, as if
+ * it were QTailQLink<type>.
+ */
+#define QTAILQ_HEAD(name, type)                                         \
+    union name {                                                        \
+        struct type *tqh_first;       /* first element */               \
+        QTailQLink tqh_circ;          /* link for circular backwards list */ \
+    }
+
+#define QTAILQ_HEAD_INITIALIZER(head)           \
+    { .tqh_circ = { NULL, &(head).tqh_circ } }
+
+#define QTAILQ_ENTRY(type)                                              \
+    union {                                                             \
+        struct type *tqe_next;        /* next element */                \
+        QTailQLink tqe_circ;          /* link for circular backwards list */ \
+    }
+
+#define QTAILQ_INIT(head) do {                                          \
+        (head)->tqh_first = NULL;                                       \
+        (head)->tqh_circ.tql_prev = &(head)->tqh_circ;                  \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_INSERT_HEAD(head, elm, field) do {                       \
+        if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)        \
+            (head)->tqh_first->field.tqe_circ.tql_prev =                \
+                &(elm)->field.tqe_circ;                                 \
+        else                                                            \
+            (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ;         \
+        (head)->tqh_first = (elm);                                      \
+        (elm)->field.tqe_circ.tql_prev = &(head)->tqh_circ;             \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_INSERT_TAIL(head, elm, field) do {                       \
+        (elm)->field.tqe_next = NULL;                                   \
+        (elm)->field.tqe_circ.tql_prev = (head)->tqh_circ.tql_prev;     \
+        (head)->tqh_circ.tql_prev->tql_next = (elm);                    \
+        (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ;             \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_INSERT_AFTER(head, listelm, elm, field) do {             \
+        if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+            (elm)->field.tqe_next->field.tqe_circ.tql_prev =            \
+                &(elm)->field.tqe_circ;                                 \
+        else                                                            \
+            (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ;         \
+        (listelm)->field.tqe_next = (elm);                              \
+        (elm)->field.tqe_circ.tql_prev = &(listelm)->field.tqe_circ;    \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_INSERT_BEFORE(listelm, elm, field) do {                       \
+        (elm)->field.tqe_circ.tql_prev = (listelm)->field.tqe_circ.tql_prev; \
+        (elm)->field.tqe_next = (listelm);                                   \
+        (listelm)->field.tqe_circ.tql_prev->tql_next = (elm);                \
+        (listelm)->field.tqe_circ.tql_prev = &(elm)->field.tqe_circ;         \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_REMOVE(head, elm, field) do {                            \
+        if (((elm)->field.tqe_next) != NULL)                            \
+            (elm)->field.tqe_next->field.tqe_circ.tql_prev =            \
+                (elm)->field.tqe_circ.tql_prev;                         \
+        else                                                            \
+            (head)->tqh_circ.tql_prev = (elm)->field.tqe_circ.tql_prev; \
+        (elm)->field.tqe_circ.tql_prev->tql_next = (elm)->field.tqe_next; \
+        (elm)->field.tqe_circ.tql_prev = NULL;                          \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_FOREACH(var, head, field)                                \
+        for ((var) = ((head)->tqh_first);                               \
+                (var);                                                  \
+                (var) = ((var)->field.tqe_next))
+
+#define QTAILQ_FOREACH_SAFE(var, head, field, next_var)                 \
+        for ((var) = ((head)->tqh_first);                               \
+                (var) && ((next_var) = ((var)->field.tqe_next), 1);     \
+                (var) = (next_var))
+
+#define QTAILQ_FOREACH_REVERSE(var, head, field)                        \
+        for ((var) = QTAILQ_LAST(head);                                 \
+                (var);                                                  \
+                (var) = QTAILQ_PREV(var, field))
+
+#define QTAILQ_FOREACH_REVERSE_SAFE(var, head, field, prev_var)         \
+        for ((var) = QTAILQ_LAST(head);                                 \
+             (var) && ((prev_var) = QTAILQ_PREV(var, field));           \
+             (var) = (prev_var))
+
+/*
+ * Tail queue access methods.
+ */
+#define QTAILQ_EMPTY(head)               ((head)->tqh_first == NULL)
+#define QTAILQ_FIRST(head)               ((head)->tqh_first)
+#define QTAILQ_NEXT(elm, field)          ((elm)->field.tqe_next)
+#define QTAILQ_IN_USE(elm, field)        ((elm)->field.tqe_circ.tql_prev != NULL)
+
+#define QTAILQ_LINK_PREV(link)                                          \
+        ((link).tql_prev->tql_prev->tql_next)
+#define QTAILQ_LAST(head)                                               \
+        ((typeof((head)->tqh_first)) QTAILQ_LINK_PREV((head)->tqh_circ))
+#define QTAILQ_PREV(elm, field)                                         \
+        ((typeof((elm)->field.tqe_next)) QTAILQ_LINK_PREV((elm)->field.tqe_circ))
+
+#define field_at_offset(base, offset, type)                                    \
+        ((type *) (((char *) (base)) + (offset)))
+
+/*
+ * Raw access of elements of a tail queue head.  Offsets are all zero
+ * because it's a union.
+ */
+#define QTAILQ_RAW_FIRST(head)                                                 \
+        field_at_offset(head, 0, void *)
+#define QTAILQ_RAW_TQH_CIRC(head)                                              \
+        field_at_offset(head, 0, QTailQLink)
+
+/*
+ * Raw access of elements of a tail entry
+ */
+#define QTAILQ_RAW_NEXT(elm, entry)                                            \
+        field_at_offset(elm, entry, void *)
+#define QTAILQ_RAW_TQE_CIRC(elm, entry)                                        \
+        field_at_offset(elm, entry, QTailQLink)
+/*
+ * Tail queue traversal using pointer arithmetic.
+ */
+#define QTAILQ_RAW_FOREACH(elm, head, entry)                                   \
+        for ((elm) = *QTAILQ_RAW_FIRST(head);                                  \
+             (elm);                                                            \
+             (elm) = *QTAILQ_RAW_NEXT(elm, entry))
+/*
+ * Tail queue insertion using pointer arithmetic.
+ */
+#define QTAILQ_RAW_INSERT_TAIL(head, elm, entry) do {                           \
+        *QTAILQ_RAW_NEXT(elm, entry) = NULL;                                    \
+        QTAILQ_RAW_TQE_CIRC(elm, entry)->tql_prev = QTAILQ_RAW_TQH_CIRC(head)->tql_prev; \
+        QTAILQ_RAW_TQH_CIRC(head)->tql_prev->tql_next = (elm);                  \
+        QTAILQ_RAW_TQH_CIRC(head)->tql_prev = QTAILQ_RAW_TQE_CIRC(elm, entry);  \
+} while (/*CONSTCOND*/0)
+
+#endif /* QTAILQ_H */
diff --git a/slirp/src/sbuf.c b/slirp/src/sbuf.c
new file mode 100644 (file)
index 0000000..51a9f0c
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include "slirp.h"
+
+static void sbappendsb(struct sbuf *sb, struct mbuf *m);
+
+void
+sbfree(struct sbuf *sb)
+{
+       free(sb->sb_data);
+}
+
+bool
+sbdrop(struct sbuf *sb, int num)
+{
+    int limit = sb->sb_datalen / 2;
+
+       /*
+        * We can only drop how much we have
+        * This should never succeed
+        */
+       if(num > sb->sb_cc)
+               num = sb->sb_cc;
+       sb->sb_cc -= num;
+       sb->sb_rptr += num;
+       if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen)
+               sb->sb_rptr -= sb->sb_datalen;
+
+    if (sb->sb_cc < limit && sb->sb_cc + num >= limit) {
+        return true;
+    }
+
+    return false;
+}
+
+void
+sbreserve(struct sbuf *sb, int size)
+{
+       if (sb->sb_data) {
+               /* Already alloced, realloc if necessary */
+               if (sb->sb_datalen != size) {
+                       sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size);
+                       sb->sb_cc = 0;
+                       if (sb->sb_wptr)
+                          sb->sb_datalen = size;
+                       else
+                          sb->sb_datalen = 0;
+               }
+       } else {
+               sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size);
+               sb->sb_cc = 0;
+               if (sb->sb_wptr)
+                  sb->sb_datalen = size;
+               else
+                  sb->sb_datalen = 0;
+       }
+}
+
+/*
+ * Try and write() to the socket, whatever doesn't get written
+ * append to the buffer... for a host with a fast net connection,
+ * this prevents an unnecessary copy of the data
+ * (the socket is non-blocking, so we won't hang)
+ */
+void
+sbappend(struct socket *so, struct mbuf *m)
+{
+       int ret = 0;
+
+       DEBUG_CALL("sbappend");
+       DEBUG_ARG("so = %p", so);
+       DEBUG_ARG("m = %p", m);
+       DEBUG_ARG("m->m_len = %d", m->m_len);
+
+       /* Shouldn't happen, but...  e.g. foreign host closes connection */
+       if (m->m_len <= 0) {
+               m_free(m);
+               return;
+       }
+
+       /*
+        * If there is urgent data, call sosendoob
+        * if not all was sent, sowrite will take care of the rest
+        * (The rest of this function is just an optimisation)
+        */
+       if (so->so_urgc) {
+               sbappendsb(&so->so_rcv, m);
+               m_free(m);
+               (void)sosendoob(so);
+               return;
+       }
+
+       /*
+        * We only write if there's nothing in the buffer,
+        * ottherwise it'll arrive out of order, and hence corrupt
+        */
+       if (!so->so_rcv.sb_cc)
+          ret = slirp_send(so, m->m_data, m->m_len, 0);
+
+       if (ret <= 0) {
+               /*
+                * Nothing was written
+                * It's possible that the socket has closed, but
+                * we don't need to check because if it has closed,
+                * it will be detected in the normal way by soread()
+                */
+               sbappendsb(&so->so_rcv, m);
+       } else if (ret != m->m_len) {
+               /*
+                * Something was written, but not everything..
+                * sbappendsb the rest
+                */
+               m->m_len -= ret;
+               m->m_data += ret;
+               sbappendsb(&so->so_rcv, m);
+       } /* else */
+       /* Whatever happened, we free the mbuf */
+       m_free(m);
+}
+
+/*
+ * Copy the data from m into sb
+ * The caller is responsible to make sure there's enough room
+ */
+static void
+sbappendsb(struct sbuf *sb, struct mbuf *m)
+{
+       int len, n,  nn;
+
+       len = m->m_len;
+
+       if (sb->sb_wptr < sb->sb_rptr) {
+               n = sb->sb_rptr - sb->sb_wptr;
+               if (n > len) n = len;
+               memcpy(sb->sb_wptr, m->m_data, n);
+       } else {
+               /* Do the right edge first */
+               n = sb->sb_data + sb->sb_datalen - sb->sb_wptr;
+               if (n > len) n = len;
+               memcpy(sb->sb_wptr, m->m_data, n);
+               len -= n;
+               if (len) {
+                       /* Now the left edge */
+                       nn = sb->sb_rptr - sb->sb_data;
+                       if (nn > len) nn = len;
+                       memcpy(sb->sb_data,m->m_data+n,nn);
+                       n += nn;
+               }
+       }
+
+       sb->sb_cc += n;
+       sb->sb_wptr += n;
+       if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen)
+               sb->sb_wptr -= sb->sb_datalen;
+}
+
+/*
+ * Copy data from sbuf to a normal, straight buffer
+ * Don't update the sbuf rptr, this will be
+ * done in sbdrop when the data is acked
+ */
+void
+sbcopy(struct sbuf *sb, int off, int len, char *to)
+{
+       char *from;
+
+       from = sb->sb_rptr + off;
+       if (from >= sb->sb_data + sb->sb_datalen)
+               from -= sb->sb_datalen;
+
+       if (from < sb->sb_wptr) {
+               if (len > sb->sb_cc) len = sb->sb_cc;
+               memcpy(to,from,len);
+       } else {
+               /* re-use off */
+               off = (sb->sb_data + sb->sb_datalen) - from;
+               if (off > len) off = len;
+               memcpy(to,from,off);
+               len -= off;
+               if (len)
+                  memcpy(to+off,sb->sb_data,len);
+       }
+}
diff --git a/slirp/src/sbuf.h b/slirp/src/sbuf.h
new file mode 100644 (file)
index 0000000..1cb9a42
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef SBUF_H
+#define SBUF_H
+
+#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc)
+
+struct sbuf {
+       uint32_t sb_cc;         /* actual chars in buffer */
+       uint32_t sb_datalen;    /* Length of data  */
+       char    *sb_wptr;       /* write pointer. points to where the next
+                                * bytes should be written in the sbuf */
+       char    *sb_rptr;       /* read pointer. points to where the next
+                                * byte should be read from the sbuf */
+       char    *sb_data;       /* Actual data */
+};
+
+void sbfree(struct sbuf *);
+bool sbdrop(struct sbuf *, int);
+void sbreserve(struct sbuf *, int);
+void sbappend(struct socket *, struct mbuf *);
+void sbcopy(struct sbuf *, int, int, char *);
+
+#endif
diff --git a/slirp/src/slirp.c b/slirp/src/slirp.c
new file mode 100644 (file)
index 0000000..18af670
--- /dev/null
@@ -0,0 +1,1117 @@
+/*
+ * libslirp glue
+ *
+ * Copyright (c) 2004-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "slirp.h"
+
+
+#ifndef _WIN32
+#include <net/if.h>
+#endif
+
+int slirp_debug;
+
+/* Define to 1 if you want KEEPALIVE timers */
+bool slirp_do_keepalive;
+
+/* host loopback address */
+struct in_addr loopback_addr;
+/* host loopback network mask */
+unsigned long loopback_mask;
+
+/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
+static const uint8_t special_ethaddr[ETH_ALEN] = {
+    0x52, 0x55, 0x00, 0x00, 0x00, 0x00
+};
+
+unsigned curtime;
+
+static struct in_addr dns_addr;
+#ifndef _WIN32
+static struct in6_addr dns6_addr;
+#endif
+static unsigned dns_addr_time;
+#ifndef _WIN32
+static unsigned dns6_addr_time;
+#endif
+
+#define TIMEOUT_FAST 2  /* milliseconds */
+#define TIMEOUT_SLOW 499  /* milliseconds */
+/* for the aging of certain requests like DNS */
+#define TIMEOUT_DEFAULT 1000  /* milliseconds */
+
+#ifdef _WIN32
+
+int get_dns_addr(struct in_addr *pdns_addr)
+{
+    FIXED_INFO *FixedInfo=NULL;
+    ULONG    BufLen;
+    DWORD    ret;
+    IP_ADDR_STRING *pIPAddr;
+    struct in_addr tmp_addr;
+
+    if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < TIMEOUT_DEFAULT) {
+        *pdns_addr = dns_addr;
+        return 0;
+    }
+
+    FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
+    BufLen = sizeof(FIXED_INFO);
+
+    if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
+        if (FixedInfo) {
+            GlobalFree(FixedInfo);
+            FixedInfo = NULL;
+        }
+        FixedInfo = GlobalAlloc(GPTR, BufLen);
+    }
+
+    if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
+        printf("GetNetworkParams failed. ret = %08x\n", (unsigned)ret );
+        if (FixedInfo) {
+            GlobalFree(FixedInfo);
+            FixedInfo = NULL;
+        }
+        return -1;
+    }
+
+    pIPAddr = &(FixedInfo->DnsServerList);
+    inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
+    *pdns_addr = tmp_addr;
+    dns_addr = tmp_addr;
+    dns_addr_time = curtime;
+    if (FixedInfo) {
+        GlobalFree(FixedInfo);
+        FixedInfo = NULL;
+    }
+    return 0;
+}
+
+int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id)
+{
+    return -1;
+}
+
+static void winsock_cleanup(void)
+{
+    WSACleanup();
+}
+
+#else
+
+static int get_dns_addr_cached(void *pdns_addr, void *cached_addr,
+                               socklen_t addrlen,
+                               struct stat *cached_stat, unsigned *cached_time)
+{
+    struct stat old_stat;
+    if (curtime - *cached_time < TIMEOUT_DEFAULT) {
+        memcpy(pdns_addr, cached_addr, addrlen);
+        return 0;
+    }
+    old_stat = *cached_stat;
+    if (stat("/etc/resolv.conf", cached_stat) != 0) {
+        return -1;
+    }
+    if (cached_stat->st_dev == old_stat.st_dev
+        && cached_stat->st_ino == old_stat.st_ino
+        && cached_stat->st_size == old_stat.st_size
+        && cached_stat->st_mtime == old_stat.st_mtime) {
+        memcpy(pdns_addr, cached_addr, addrlen);
+        return 0;
+    }
+    return 1;
+}
+
+static int get_dns_addr_resolv_conf(int af, void *pdns_addr, void *cached_addr,
+                                    socklen_t addrlen, uint32_t *scope_id,
+                                    unsigned *cached_time)
+{
+    char buff[512];
+    char buff2[257];
+    FILE *f;
+    int found = 0;
+    void *tmp_addr = alloca(addrlen);
+    unsigned if_index;
+
+    f = fopen("/etc/resolv.conf", "r");
+    if (!f)
+        return -1;
+
+    DEBUG_MISC("IP address of your DNS(s):");
+    while (fgets(buff, 512, f) != NULL) {
+        if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
+            char *c = strchr(buff2, '%');
+            if (c) {
+                if_index = if_nametoindex(c + 1);
+                *c = '\0';
+            } else {
+                if_index = 0;
+            }
+
+            if (!inet_pton(af, buff2, tmp_addr)) {
+                continue;
+            }
+            /* If it's the first one, set it to dns_addr */
+            if (!found) {
+                memcpy(pdns_addr, tmp_addr, addrlen);
+                memcpy(cached_addr, tmp_addr, addrlen);
+                if (scope_id) {
+                    *scope_id = if_index;
+                }
+                *cached_time = curtime;
+            }
+
+            if (++found > 3) {
+                DEBUG_MISC("  (more)");
+                break;
+            } else if (slirp_debug & DBG_MISC) {
+                char s[INET6_ADDRSTRLEN];
+                const char *res = inet_ntop(af, tmp_addr, s, sizeof(s));
+                if (!res) {
+                    res = "  (string conversion error)";
+                }
+                DEBUG_MISC("  %s", res);
+            }
+        }
+    }
+    fclose(f);
+    if (!found)
+        return -1;
+    return 0;
+}
+
+int get_dns_addr(struct in_addr *pdns_addr)
+{
+    static struct stat dns_addr_stat;
+
+    if (dns_addr.s_addr != 0) {
+        int ret;
+        ret = get_dns_addr_cached(pdns_addr, &dns_addr, sizeof(dns_addr),
+                                  &dns_addr_stat, &dns_addr_time);
+        if (ret <= 0) {
+            return ret;
+        }
+    }
+    return get_dns_addr_resolv_conf(AF_INET, pdns_addr, &dns_addr,
+                                    sizeof(dns_addr), NULL, &dns_addr_time);
+}
+
+int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id)
+{
+    static struct stat dns6_addr_stat;
+
+    if (!in6_zero(&dns6_addr)) {
+        int ret;
+        ret = get_dns_addr_cached(pdns6_addr, &dns6_addr, sizeof(dns6_addr),
+                                  &dns6_addr_stat, &dns6_addr_time);
+        if (ret <= 0) {
+            return ret;
+        }
+    }
+    return get_dns_addr_resolv_conf(AF_INET6, pdns6_addr, &dns6_addr,
+                                    sizeof(dns6_addr),
+                                    scope_id, &dns6_addr_time);
+}
+
+#endif
+
+static void slirp_init_once(void)
+{
+    static int initialized;
+    const char *debug;
+#ifdef _WIN32
+    WSADATA Data;
+#endif
+
+    if (initialized) {
+        return;
+    }
+    initialized = 1;
+
+#ifdef _WIN32
+    WSAStartup(MAKEWORD(2,0), &Data);
+    atexit(winsock_cleanup);
+#endif
+
+    loopback_addr.s_addr = htonl(INADDR_LOOPBACK);
+    loopback_mask = htonl(IN_CLASSA_NET);
+
+    debug = g_getenv("SLIRP_DEBUG");
+    if (debug) {
+        const GDebugKey keys[] = {
+            { "call", DBG_CALL },
+            { "misc", DBG_MISC },
+            { "error", DBG_ERROR },
+            { "tftp", DBG_TFTP },
+        };
+        slirp_debug = g_parse_debug_string(debug, keys, G_N_ELEMENTS(keys));
+    }
+
+
+}
+
+Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
+                  struct in_addr vnetmask, struct in_addr vhost,
+                  bool in6_enabled,
+                  struct in6_addr vprefix_addr6, uint8_t vprefix_len,
+                  struct in6_addr vhost6, const char *vhostname,
+                  const char *tftp_server_name,
+                  const char *tftp_path, const char *bootfile,
+                  struct in_addr vdhcp_start, struct in_addr vnameserver,
+                  struct in6_addr vnameserver6, const char **vdnssearch,
+                  const char *vdomainname,
+                  const SlirpCb *callbacks,
+                  void *opaque)
+{
+    Slirp *slirp = g_malloc0(sizeof(Slirp));
+
+    slirp_init_once();
+
+    slirp->opaque = opaque;
+    slirp->cb = callbacks;
+    slirp->grand = g_rand_new();
+    slirp->restricted = restricted;
+
+    slirp->in_enabled = in_enabled;
+    slirp->in6_enabled = in6_enabled;
+
+    if_init(slirp);
+    ip_init(slirp);
+    ip6_init(slirp);
+
+    /* Initialise mbufs *after* setting the MTU */
+    m_init(slirp);
+
+    slirp->vnetwork_addr = vnetwork;
+    slirp->vnetwork_mask = vnetmask;
+    slirp->vhost_addr = vhost;
+    slirp->vprefix_addr6 = vprefix_addr6;
+    slirp->vprefix_len = vprefix_len;
+    slirp->vhost_addr6 = vhost6;
+    if (vhostname) {
+        slirp_pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
+                      vhostname);
+    }
+    slirp->tftp_prefix = g_strdup(tftp_path);
+    slirp->bootp_filename = g_strdup(bootfile);
+    slirp->vdomainname = g_strdup(vdomainname);
+    slirp->vdhcp_startaddr = vdhcp_start;
+    slirp->vnameserver_addr = vnameserver;
+    slirp->vnameserver_addr6 = vnameserver6;
+    slirp->tftp_server_name = g_strdup(tftp_server_name);
+
+    if (vdnssearch) {
+        translate_dnssearch(slirp, vdnssearch);
+    }
+
+    return slirp;
+}
+
+void slirp_cleanup(Slirp *slirp)
+{
+    struct gfwd_list *e, *next;
+
+    for (e = slirp->guestfwd_list; e; e = next) {
+        next = e->ex_next;
+        g_free(e->ex_exec);
+        g_free(e);
+    }
+
+    ip_cleanup(slirp);
+    ip6_cleanup(slirp);
+    m_cleanup(slirp);
+
+    g_rand_free(slirp->grand);
+
+    g_free(slirp->vdnssearch);
+    g_free(slirp->tftp_prefix);
+    g_free(slirp->bootp_filename);
+    g_free(slirp->vdomainname);
+    g_free(slirp);
+}
+
+#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
+#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
+
+static void slirp_update_timeout(Slirp *slirp, uint32_t *timeout)
+{
+    uint32_t t;
+
+    if (*timeout <= TIMEOUT_FAST) {
+        return;
+    }
+
+    t = MIN(1000, *timeout);
+
+    /* If we have tcp timeout with slirp, then we will fill @timeout with
+     * more precise value.
+     */
+    if (slirp->time_fasttimo) {
+        *timeout = TIMEOUT_FAST;
+        return;
+    }
+    if (slirp->do_slowtimo) {
+        t = MIN(TIMEOUT_SLOW, t);
+    }
+    *timeout = t;
+}
+
+void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
+                        SlirpAddPollCb add_poll, void *opaque)
+{
+    struct socket *so, *so_next;
+
+    /*
+     * First, TCP sockets
+     */
+
+    /*
+     * *_slowtimo needs calling if there are IP fragments
+     * in the fragment queue, or there are TCP connections active
+     */
+    slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) ||
+                          (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
+
+    for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) {
+        int events = 0;
+
+        so_next = so->so_next;
+
+        so->pollfds_idx = -1;
+
+        /*
+         * See if we need a tcp_fasttimo
+         */
+        if (slirp->time_fasttimo == 0 &&
+            so->so_tcpcb->t_flags & TF_DELACK) {
+            slirp->time_fasttimo = curtime; /* Flag when want a fasttimo */
+        }
+
+        /*
+         * NOFDREF can include still connecting to local-host,
+         * newly socreated() sockets etc. Don't want to select these.
+         */
+        if (so->so_state & SS_NOFDREF || so->s == -1) {
+            continue;
+        }
+
+        /*
+         * Set for reading sockets which are accepting
+         */
+        if (so->so_state & SS_FACCEPTCONN) {
+            so->pollfds_idx = add_poll(so->s,
+                SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
+            continue;
+        }
+
+        /*
+         * Set for writing sockets which are connecting
+         */
+        if (so->so_state & SS_ISFCONNECTING) {
+            so->pollfds_idx = add_poll(so->s,
+                SLIRP_POLL_OUT | SLIRP_POLL_ERR, opaque);
+            continue;
+        }
+
+        /*
+         * Set for writing if we are connected, can send more, and
+         * we have something to send
+         */
+        if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
+            events |= SLIRP_POLL_OUT | SLIRP_POLL_ERR;
+        }
+
+        /*
+         * Set for reading (and urgent data) if we are connected, can
+         * receive more, and we have room for it XXX /2 ?
+         */
+        if (CONN_CANFRCV(so) &&
+            (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
+            events |= SLIRP_POLL_IN | SLIRP_POLL_HUP |
+                      SLIRP_POLL_ERR | SLIRP_POLL_PRI;
+        }
+
+        if (events) {
+            so->pollfds_idx = add_poll(so->s, events, opaque);
+        }
+    }
+
+    /*
+     * UDP sockets
+     */
+    for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) {
+        so_next = so->so_next;
+
+        so->pollfds_idx = -1;
+
+        /*
+         * See if it's timed out
+         */
+        if (so->so_expire) {
+            if (so->so_expire <= curtime) {
+                udp_detach(so);
+                continue;
+            } else {
+                slirp->do_slowtimo = true; /* Let socket expire */
+            }
+        }
+
+        /*
+         * When UDP packets are received from over the
+         * link, they're sendto()'d straight away, so
+         * no need for setting for writing
+         * Limit the number of packets queued by this session
+         * to 4.  Note that even though we try and limit this
+         * to 4 packets, the session could have more queued
+         * if the packets needed to be fragmented
+         * (XXX <= 4 ?)
+         */
+        if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
+            so->pollfds_idx = add_poll(so->s,
+                SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
+        }
+    }
+
+    /*
+     * ICMP sockets
+     */
+    for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) {
+        so_next = so->so_next;
+
+        so->pollfds_idx = -1;
+
+        /*
+         * See if it's timed out
+         */
+        if (so->so_expire) {
+            if (so->so_expire <= curtime) {
+                icmp_detach(so);
+                continue;
+            } else {
+                slirp->do_slowtimo = true; /* Let socket expire */
+            }
+        }
+
+        if (so->so_state & SS_ISFCONNECTED) {
+            so->pollfds_idx = add_poll(so->s,
+                SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
+        }
+    }
+
+    slirp_update_timeout(slirp, timeout);
+}
+
+void slirp_pollfds_poll(Slirp *slirp, int select_error,
+                        SlirpGetREventsCb get_revents, void *opaque)
+{
+    struct socket *so, *so_next;
+    int ret;
+
+    curtime = slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS;
+
+    /*
+     * See if anything has timed out
+     */
+    if (slirp->time_fasttimo &&
+        ((curtime - slirp->time_fasttimo) >= TIMEOUT_FAST)) {
+        tcp_fasttimo(slirp);
+        slirp->time_fasttimo = 0;
+    }
+    if (slirp->do_slowtimo &&
+        ((curtime - slirp->last_slowtimo) >= TIMEOUT_SLOW)) {
+        ip_slowtimo(slirp);
+        tcp_slowtimo(slirp);
+        slirp->last_slowtimo = curtime;
+    }
+
+    /*
+     * Check sockets
+     */
+    if (!select_error) {
+        /*
+         * Check TCP sockets
+         */
+        for (so = slirp->tcb.so_next; so != &slirp->tcb;
+             so = so_next) {
+            int revents;
+
+            so_next = so->so_next;
+
+            revents = 0;
+            if (so->pollfds_idx != -1) {
+                revents = get_revents(so->pollfds_idx, opaque);
+            }
+
+            if (so->so_state & SS_NOFDREF || so->s == -1) {
+                continue;
+            }
+
+            /*
+             * Check for URG data
+             * This will soread as well, so no need to
+             * test for SLIRP_POLL_IN below if this succeeds
+             */
+            if (revents & SLIRP_POLL_PRI) {
+                ret = sorecvoob(so);
+                if (ret < 0) {
+                    /* Socket error might have resulted in the socket being
+                     * removed, do not try to do anything more with it. */
+                    continue;
+                }
+            }
+            /*
+             * Check sockets for reading
+             */
+            else if (revents &
+                     (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR)) {
+                /*
+                 * Check for incoming connections
+                 */
+                if (so->so_state & SS_FACCEPTCONN) {
+                    tcp_connect(so);
+                    continue;
+                } /* else */
+                ret = soread(so);
+
+                /* Output it if we read something */
+                if (ret > 0) {
+                    tcp_output(sototcpcb(so));
+                }
+                if (ret < 0) {
+                    /* Socket error might have resulted in the socket being
+                     * removed, do not try to do anything more with it. */
+                    continue;
+                }
+            }
+
+            /*
+             * Check sockets for writing
+             */
+            if (!(so->so_state & SS_NOFDREF) &&
+                (revents & (SLIRP_POLL_OUT | SLIRP_POLL_ERR))) {
+                /*
+                 * Check for non-blocking, still-connecting sockets
+                 */
+                if (so->so_state & SS_ISFCONNECTING) {
+                    /* Connected */
+                    so->so_state &= ~SS_ISFCONNECTING;
+
+                    ret = send(so->s, (const void *) &ret, 0, 0);
+                    if (ret < 0) {
+                        /* XXXXX Must fix, zero bytes is a NOP */
+                        if (errno == EAGAIN || errno == EWOULDBLOCK ||
+                            errno == EINPROGRESS || errno == ENOTCONN) {
+                            continue;
+                        }
+
+                        /* else failed */
+                        so->so_state &= SS_PERSISTENT_MASK;
+                        so->so_state |= SS_NOFDREF;
+                    }
+                    /* else so->so_state &= ~SS_ISFCONNECTING; */
+
+                    /*
+                     * Continue tcp_input
+                     */
+                    tcp_input((struct mbuf *)NULL, sizeof(struct ip), so,
+                              so->so_ffamily);
+                    /* continue; */
+                } else {
+                    ret = sowrite(so);
+                    if (ret > 0) {
+                        /* Call tcp_output in case we need to send a window
+                         * update to the guest, otherwise it will be stuck
+                         * until it sends a window probe. */
+                        tcp_output(sototcpcb(so));
+                    }
+                }
+            }
+        }
+
+        /*
+         * Now UDP sockets.
+         * Incoming packets are sent straight away, they're not buffered.
+         * Incoming UDP data isn't buffered either.
+         */
+        for (so = slirp->udb.so_next; so != &slirp->udb;
+             so = so_next) {
+            int revents;
+
+            so_next = so->so_next;
+
+            revents = 0;
+            if (so->pollfds_idx != -1) {
+                revents = get_revents(so->pollfds_idx, opaque);
+            }
+
+            if (so->s != -1 &&
+                (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) {
+                sorecvfrom(so);
+            }
+        }
+
+        /*
+         * Check incoming ICMP relies.
+         */
+        for (so = slirp->icmp.so_next; so != &slirp->icmp;
+             so = so_next) {
+            int revents;
+
+            so_next = so->so_next;
+
+            revents = 0;
+            if (so->pollfds_idx != -1) {
+                revents = get_revents(so->pollfds_idx, opaque);
+            }
+
+            if (so->s != -1 &&
+                (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) {
+                icmp_receive(so);
+            }
+        }
+    }
+
+    if_start(slirp);
+}
+
+static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
+{
+    struct slirp_arphdr *ah = (struct slirp_arphdr *)(pkt + ETH_HLEN);
+    uint8_t arp_reply[MAX(ETH_HLEN + sizeof(struct slirp_arphdr), 64)];
+    struct ethhdr *reh = (struct ethhdr *)arp_reply;
+    struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_reply + ETH_HLEN);
+    int ar_op;
+    struct gfwd_list *ex_ptr;
+
+    if (!slirp->in_enabled) {
+        return;
+    }
+
+    ar_op = ntohs(ah->ar_op);
+    switch(ar_op) {
+    case ARPOP_REQUEST:
+        if (ah->ar_tip == ah->ar_sip) {
+            /* Gratuitous ARP */
+            arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
+            return;
+        }
+
+        if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) ==
+            slirp->vnetwork_addr.s_addr) {
+            if (ah->ar_tip == slirp->vnameserver_addr.s_addr ||
+                ah->ar_tip == slirp->vhost_addr.s_addr)
+                goto arp_ok;
+            /* TODO: IPv6 */
+            for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+                if (ex_ptr->ex_addr.s_addr == ah->ar_tip)
+                    goto arp_ok;
+            }
+            return;
+        arp_ok:
+            memset(arp_reply, 0, sizeof(arp_reply));
+
+            arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
+
+            /* ARP request for alias/dns mac address */
+            memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
+            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
+            memcpy(&reh->h_source[2], &ah->ar_tip, 4);
+            reh->h_proto = htons(ETH_P_ARP);
+
+            rah->ar_hrd = htons(1);
+            rah->ar_pro = htons(ETH_P_IP);
+            rah->ar_hln = ETH_ALEN;
+            rah->ar_pln = 4;
+            rah->ar_op = htons(ARPOP_REPLY);
+            memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
+            rah->ar_sip = ah->ar_tip;
+            memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
+            rah->ar_tip = ah->ar_sip;
+            slirp_send_packet_all(slirp, arp_reply, sizeof(arp_reply));
+        }
+        break;
+    case ARPOP_REPLY:
+        arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
+        break;
+    default:
+        break;
+    }
+}
+
+void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
+{
+    struct mbuf *m;
+    int proto;
+
+    if (pkt_len < ETH_HLEN)
+        return;
+
+    proto = (((uint16_t) pkt[12]) << 8) + pkt[13];
+    switch(proto) {
+    case ETH_P_ARP:
+        arp_input(slirp, pkt, pkt_len);
+        break;
+    case ETH_P_IP:
+    case ETH_P_IPV6:
+        m = m_get(slirp);
+        if (!m)
+            return;
+        /* Note: we add 2 to align the IP header on 4 bytes,
+         * and add the margin for the tcpiphdr overhead  */
+        if (M_FREEROOM(m) < pkt_len + TCPIPHDR_DELTA + 2) {
+            m_inc(m, pkt_len + TCPIPHDR_DELTA + 2);
+        }
+        m->m_len = pkt_len + TCPIPHDR_DELTA + 2;
+        memcpy(m->m_data + TCPIPHDR_DELTA + 2, pkt, pkt_len);
+
+        m->m_data += TCPIPHDR_DELTA + 2 + ETH_HLEN;
+        m->m_len -= TCPIPHDR_DELTA + 2 + ETH_HLEN;
+
+        if (proto == ETH_P_IP) {
+            ip_input(m);
+        } else if (proto == ETH_P_IPV6) {
+            ip6_input(m);
+        }
+        break;
+
+    case ETH_P_NCSI:
+        ncsi_input(slirp, pkt, pkt_len);
+        break;
+
+    default:
+        break;
+    }
+}
+
+/* Prepare the IPv4 packet to be sent to the ethernet device. Returns 1 if no
+ * packet should be sent, 0 if the packet must be re-queued, 2 if the packet
+ * is ready to go.
+ */
+static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
+        uint8_t ethaddr[ETH_ALEN])
+{
+    const struct ip *iph = (const struct ip *)ifm->m_data;
+
+    if (iph->ip_dst.s_addr == 0) {
+        /* 0.0.0.0 can not be a destination address, something went wrong,
+         * avoid making it worse */
+        return 1;
+    }
+    if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
+        uint8_t arp_req[ETH_HLEN + sizeof(struct slirp_arphdr)];
+        struct ethhdr *reh = (struct ethhdr *)arp_req;
+        struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_req + ETH_HLEN);
+
+        if (!ifm->resolution_requested) {
+            /* If the client addr is not known, send an ARP request */
+            memset(reh->h_dest, 0xff, ETH_ALEN);
+            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
+            memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
+            reh->h_proto = htons(ETH_P_ARP);
+            rah->ar_hrd = htons(1);
+            rah->ar_pro = htons(ETH_P_IP);
+            rah->ar_hln = ETH_ALEN;
+            rah->ar_pln = 4;
+            rah->ar_op = htons(ARPOP_REQUEST);
+
+            /* source hw addr */
+            memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
+            memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);
+
+            /* source IP */
+            rah->ar_sip = slirp->vhost_addr.s_addr;
+
+            /* target hw addr (none) */
+            memset(rah->ar_tha, 0, ETH_ALEN);
+
+            /* target IP */
+            rah->ar_tip = iph->ip_dst.s_addr;
+            slirp->client_ipaddr = iph->ip_dst;
+            slirp_send_packet_all(slirp, arp_req, sizeof(arp_req));
+            ifm->resolution_requested = true;
+
+            /* Expire request and drop outgoing packet after 1 second */
+            ifm->expiration_date =
+                slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL;
+        }
+        return 0;
+    } else {
+        memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
+        /* XXX: not correct */
+        memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
+        eh->h_proto = htons(ETH_P_IP);
+
+        /* Send this */
+        return 2;
+    }
+}
+
+/* Prepare the IPv6 packet to be sent to the ethernet device. Returns 1 if no
+ * packet should be sent, 0 if the packet must be re-queued, 2 if the packet
+ * is ready to go.
+ */
+static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
+        uint8_t ethaddr[ETH_ALEN])
+{
+    const struct ip6 *ip6h = mtod(ifm, const struct ip6 *);
+    if (!ndp_table_search(slirp, ip6h->ip_dst, ethaddr)) {
+        if (!ifm->resolution_requested) {
+            ndp_send_ns(slirp, ip6h->ip_dst);
+            ifm->resolution_requested = true;
+            ifm->expiration_date = slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL;
+        }
+        return 0;
+    } else {
+        eh->h_proto = htons(ETH_P_IPV6);
+        in6_compute_ethaddr(ip6h->ip_src, eh->h_source);
+
+        /* Send this */
+        return 2;
+    }
+}
+
+/* Output the IP packet to the ethernet device. Returns 0 if the packet must be
+ * re-queued.
+ */
+int if_encap(Slirp *slirp, struct mbuf *ifm)
+{
+    uint8_t buf[1600];
+    struct ethhdr *eh = (struct ethhdr *)buf;
+    uint8_t ethaddr[ETH_ALEN];
+    const struct ip *iph = (const struct ip *)ifm->m_data;
+    int ret;
+
+    if (ifm->m_len + ETH_HLEN > sizeof(buf)) {
+        return 1;
+    }
+
+    switch (iph->ip_v) {
+    case IPVERSION:
+        ret = if_encap4(slirp, ifm, eh, ethaddr);
+        if (ret < 2) {
+            return ret;
+        }
+        break;
+
+    case IP6VERSION:
+        ret = if_encap6(slirp, ifm, eh, ethaddr);
+        if (ret < 2) {
+            return ret;
+        }
+        break;
+
+    default:
+        g_assert_not_reached();
+        break;
+    }
+
+    memcpy(eh->h_dest, ethaddr, ETH_ALEN);
+    DEBUG_ARG("src = %02x:%02x:%02x:%02x:%02x:%02x",
+              eh->h_source[0], eh->h_source[1], eh->h_source[2],
+              eh->h_source[3], eh->h_source[4], eh->h_source[5]);
+    DEBUG_ARG("dst = %02x:%02x:%02x:%02x:%02x:%02x",
+              eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
+              eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]);
+    memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
+    slirp_send_packet_all(slirp, buf, ifm->m_len + ETH_HLEN);
+    return 1;
+}
+
+/* Drop host forwarding rule, return 0 if found. */
+/* TODO: IPv6 */
+int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
+                         int host_port)
+{
+    struct socket *so;
+    struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb);
+    struct sockaddr_in addr;
+    int port = htons(host_port);
+    socklen_t addr_len;
+
+    for (so = head->so_next; so != head; so = so->so_next) {
+        addr_len = sizeof(addr);
+        if ((so->so_state & SS_HOSTFWD) &&
+            getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
+            addr.sin_addr.s_addr == host_addr.s_addr &&
+            addr.sin_port == port) {
+            so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
+            closesocket(so->s);
+            sofree(so);
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+/* TODO: IPv6 */
+int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
+                      int host_port, struct in_addr guest_addr, int guest_port)
+{
+    if (!guest_addr.s_addr) {
+        guest_addr = slirp->vdhcp_startaddr;
+    }
+    if (is_udp) {
+        if (!udp_listen(slirp, host_addr.s_addr, htons(host_port),
+                        guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
+            return -1;
+    } else {
+        if (!tcp_listen(slirp, host_addr.s_addr, htons(host_port),
+                        guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
+            return -1;
+    }
+    return 0;
+}
+
+/* TODO: IPv6 */
+static bool
+check_guestfwd(Slirp *slirp, struct in_addr *guest_addr, int guest_port)
+{
+    struct gfwd_list *tmp_ptr;
+
+    if (!guest_addr->s_addr) {
+        guest_addr->s_addr = slirp->vnetwork_addr.s_addr |
+            (htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
+    }
+    if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) !=
+        slirp->vnetwork_addr.s_addr ||
+        guest_addr->s_addr == slirp->vhost_addr.s_addr ||
+        guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
+        return false;
+    }
+
+    /* check if the port is "bound" */
+    for (tmp_ptr = slirp->guestfwd_list; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
+        if (guest_port == tmp_ptr->ex_fport &&
+            guest_addr->s_addr == tmp_ptr->ex_addr.s_addr)
+            return false;
+    }
+
+    return true;
+}
+
+int slirp_add_exec(Slirp *slirp, const char *cmdline,
+                   struct in_addr *guest_addr, int guest_port)
+{
+    if (!check_guestfwd(slirp, guest_addr, guest_port)) {
+        return -1;
+    }
+
+    add_exec(&slirp->guestfwd_list, cmdline, *guest_addr, htons(guest_port));
+    return 0;
+}
+
+int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
+                       struct in_addr *guest_addr, int guest_port)
+{
+    if (!check_guestfwd(slirp, guest_addr, guest_port)) {
+        return -1;
+    }
+
+    add_guestfwd(&slirp->guestfwd_list, write_cb, opaque,
+                 *guest_addr, htons(guest_port));
+    return 0;
+}
+
+ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
+{
+    if (so->s == -1 && so->guestfwd) {
+        /* XXX this blocks entire thread. Rewrite to use
+         * qemu_chr_fe_write and background I/O callbacks */
+        so->guestfwd->write_cb(buf, len, so->guestfwd->opaque);
+        return len;
+    }
+
+    if (so->s == -1) {
+        /*
+         * This should in theory not happen but it is hard to be
+         * sure because some code paths will end up with so->s == -1
+         * on a failure but don't dispose of the struct socket.
+         * Check specifically, so we don't pass -1 to send().
+         */
+        errno = EBADF;
+        return -1;
+    }
+
+    return send(so->s, buf, len, flags);
+}
+
+struct socket *
+slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port)
+{
+    struct socket *so;
+
+    /* TODO: IPv6 */
+    for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
+        if (so->so_faddr.s_addr == guest_addr.s_addr &&
+            htons(so->so_fport) == guest_port) {
+            return so;
+        }
+    }
+    return NULL;
+}
+
+size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
+                             int guest_port)
+{
+    struct iovec iov[2];
+    struct socket *so;
+
+    so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
+
+    if (!so || so->so_state & SS_NOFDREF) {
+        return 0;
+    }
+
+    if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2)) {
+        return 0;
+    }
+
+    return sopreprbuf(so, iov, NULL);
+}
+
+void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
+                       const uint8_t *buf, int size)
+{
+    int ret;
+    struct socket *so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
+
+    if (!so)
+        return;
+
+    ret = soreadbuf(so, (const char *)buf, size);
+
+    if (ret > 0)
+        tcp_output(sototcpcb(so));
+}
+
+void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len)
+{
+    ssize_t ret = slirp->cb->send_packet(buf, len, slirp->opaque);
+
+    if (ret < 0) {
+        g_critical("Failed to send packet, ret: %ld", (long) ret);
+    } else if (ret < len) {
+        DEBUG_ERROR("send_packet() didn't send all data: %ld < %lu",
+                (long) ret, (unsigned long) len);
+    }
+}
diff --git a/slirp/src/slirp.h b/slirp/src/slirp.h
new file mode 100644 (file)
index 0000000..8068ba1
--- /dev/null
@@ -0,0 +1,274 @@
+#ifndef SLIRP_H
+#define SLIRP_H
+
+#ifdef _WIN32
+
+/* as defined in sdkddkver.h */
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0600 /* Vista */
+#endif
+/* reduces the number of implicitly included headers */
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+# include <winsock2.h>
+# include <windows.h>
+# include <ws2tcpip.h>
+# include <sys/timeb.h>
+# include <iphlpapi.h>
+
+#else
+# if !defined(__HAIKU__)
+#  define O_BINARY 0
+# endif
+#endif
+
+#ifndef _WIN32
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#endif
+
+#ifdef __APPLE__
+# include <sys/filio.h>
+#endif
+
+/* Avoid conflicting with the libc insque() and remque(), which
+   have different prototypes. */
+#define insque slirp_insque
+#define remque slirp_remque
+#define quehead slirp_quehead
+
+#include "debug.h"
+#include "util.h"
+#include "qtailq.h"
+
+#include "libslirp.h"
+#include "ip.h"
+#include "ip6.h"
+#include "tcp.h"
+#include "tcp_timer.h"
+#include "tcp_var.h"
+#include "tcpip.h"
+#include "udp.h"
+#include "ip_icmp.h"
+#include "ip6_icmp.h"
+#include "mbuf.h"
+#include "sbuf.h"
+#include "socket.h"
+#include "if.h"
+#include "main.h"
+#include "misc.h"
+
+#include "bootp.h"
+#include "tftp.h"
+
+#define ARPOP_REQUEST 1         /* ARP request */
+#define ARPOP_REPLY   2         /* ARP reply   */
+
+struct ethhdr {
+    unsigned char  h_dest[ETH_ALEN];   /* destination eth addr */
+    unsigned char  h_source[ETH_ALEN]; /* source ether addr    */
+    unsigned short h_proto;            /* packet type ID field */
+};
+
+struct slirp_arphdr {
+    unsigned short ar_hrd;      /* format of hardware address */
+    unsigned short ar_pro;      /* format of protocol address */
+    unsigned char  ar_hln;      /* length of hardware address */
+    unsigned char  ar_pln;      /* length of protocol address */
+    unsigned short ar_op;       /* ARP opcode (command)       */
+
+    /*
+     *  Ethernet looks like this : This bit is variable sized however...
+     */
+    unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
+    uint32_t      ar_sip;           /* sender IP address       */
+    unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
+    uint32_t      ar_tip;           /* target IP address       */
+} SLIRP_PACKED;
+
+#define ARP_TABLE_SIZE 16
+
+typedef struct ArpTable {
+    struct slirp_arphdr table[ARP_TABLE_SIZE];
+    int next_victim;
+} ArpTable;
+
+void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN]);
+
+bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
+                      uint8_t out_ethaddr[ETH_ALEN]);
+
+struct ndpentry {
+    unsigned char   eth_addr[ETH_ALEN];     /* sender hardware address */
+    struct in6_addr ip_addr;                /* sender IP address       */
+};
+
+#define NDP_TABLE_SIZE 16
+
+typedef struct NdpTable {
+    struct ndpentry table[NDP_TABLE_SIZE];
+    int next_victim;
+} NdpTable;
+
+void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
+                   uint8_t ethaddr[ETH_ALEN]);
+bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
+                      uint8_t out_ethaddr[ETH_ALEN]);
+
+struct Slirp {
+    QTAILQ_ENTRY(Slirp) entry;
+    unsigned time_fasttimo;
+    unsigned last_slowtimo;
+    bool do_slowtimo;
+
+    bool in_enabled, in6_enabled;
+
+    /* virtual network configuration */
+    struct in_addr vnetwork_addr;
+    struct in_addr vnetwork_mask;
+    struct in_addr vhost_addr;
+    struct in6_addr vprefix_addr6;
+    uint8_t vprefix_len;
+    struct in6_addr vhost_addr6;
+    struct in_addr vdhcp_startaddr;
+    struct in_addr vnameserver_addr;
+    struct in6_addr vnameserver_addr6;
+
+    struct in_addr client_ipaddr;
+    char client_hostname[33];
+
+    int restricted;
+    struct gfwd_list *guestfwd_list;
+
+    /* mbuf states */
+    struct quehead m_freelist;
+    struct quehead m_usedlist;
+    int mbuf_alloced;
+
+    /* if states */
+    struct quehead if_fastq;   /* fast queue (for interactive data) */
+    struct quehead if_batchq;  /* queue for non-interactive data */
+    bool if_start_busy;     /* avoid if_start recursion */
+
+    /* ip states */
+    struct ipq ipq;         /* ip reass. queue */
+    uint16_t ip_id;         /* ip packet ctr, for ids */
+
+    /* bootp/dhcp states */
+    BOOTPClient bootp_clients[NB_BOOTP_CLIENTS];
+    char *bootp_filename;
+    size_t vdnssearch_len;
+    uint8_t *vdnssearch;
+    char *vdomainname;
+
+    /* tcp states */
+    struct socket tcb;
+    struct socket *tcp_last_so;
+    tcp_seq tcp_iss;        /* tcp initial send seq # */
+    uint32_t tcp_now;       /* for RFC 1323 timestamps */
+
+    /* udp states */
+    struct socket udb;
+    struct socket *udp_last_so;
+
+    /* icmp states */
+    struct socket icmp;
+    struct socket *icmp_last_so;
+
+    /* tftp states */
+    char *tftp_prefix;
+    struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
+    char *tftp_server_name;
+
+    ArpTable arp_table;
+    NdpTable ndp_table;
+
+    GRand *grand;
+    void *ra_timer;
+
+    const SlirpCb *cb;
+    void *opaque;
+};
+
+void if_start(Slirp *);
+
+int get_dns_addr(struct in_addr *pdns_addr);
+int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id);
+
+/* ncsi.c */
+void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
+
+#ifndef _WIN32
+#include <netdb.h>
+#endif
+
+
+extern bool slirp_do_keepalive;
+
+#define TCP_MAXIDLE (TCPTV_KEEPCNT * TCPTV_KEEPINTVL)
+
+/* dnssearch.c */
+int translate_dnssearch(Slirp *s, const char ** names);
+
+/* cksum.c */
+int cksum(struct mbuf *m, int len);
+int ip6_cksum(struct mbuf *m);
+
+/* if.c */
+void if_init(Slirp *);
+void if_output(struct socket *, struct mbuf *);
+
+/* ip_input.c */
+void ip_init(Slirp *);
+void ip_cleanup(Slirp *);
+void ip_input(struct mbuf *);
+void ip_slowtimo(Slirp *);
+void ip_stripoptions(register struct mbuf *, struct mbuf *);
+
+/* ip_output.c */
+int ip_output(struct socket *, struct mbuf *);
+
+/* ip6_input.c */
+void ip6_init(Slirp *);
+void ip6_cleanup(Slirp *);
+void ip6_input(struct mbuf *);
+
+/* ip6_output */
+int ip6_output(struct socket *, struct mbuf *, int fast);
+
+/* tcp_input.c */
+void tcp_input(register struct mbuf *, int, struct socket *, unsigned short af);
+int tcp_mss(register struct tcpcb *, unsigned);
+
+/* tcp_output.c */
+int tcp_output(register struct tcpcb *);
+void tcp_setpersist(register struct tcpcb *);
+
+/* tcp_subr.c */
+void tcp_init(Slirp *);
+void tcp_cleanup(Slirp *);
+void tcp_template(struct tcpcb *);
+void tcp_respond(struct tcpcb *, register struct tcpiphdr *,
+        register struct mbuf *, tcp_seq, tcp_seq, int, unsigned short);
+struct tcpcb * tcp_newtcpcb(struct socket *);
+struct tcpcb * tcp_close(register struct tcpcb *);
+void tcp_sockclosed(struct tcpcb *);
+int tcp_fconnect(struct socket *, unsigned short af);
+void tcp_connect(struct socket *);
+int tcp_attach(struct socket *);
+uint8_t tcp_tos(struct socket *);
+int tcp_emu(struct socket *, struct mbuf *);
+int tcp_ctl(struct socket *);
+struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
+
+struct socket *
+slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port);
+
+void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len);
+
+#endif
diff --git a/slirp/src/socket.c b/slirp/src/socket.c
new file mode 100644 (file)
index 0000000..f2428a3
--- /dev/null
@@ -0,0 +1,944 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include "slirp.h"
+#include "ip_icmp.h"
+#ifdef __sun__
+#include <sys/filio.h>
+#endif
+
+static void sofcantrcvmore(struct socket *so);
+static void sofcantsendmore(struct socket *so);
+
+struct socket *solookup(struct socket **last, struct socket *head,
+        struct sockaddr_storage *lhost, struct sockaddr_storage *fhost)
+{
+    struct socket *so = *last;
+
+    /* Optimisation */
+    if (so != head && sockaddr_equal(&(so->lhost.ss), lhost)
+            && (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) {
+        return so;
+    }
+
+    for (so = head->so_next; so != head; so = so->so_next) {
+        if (sockaddr_equal(&(so->lhost.ss), lhost)
+                && (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) {
+            *last = so;
+            return so;
+        }
+    }
+
+    return (struct socket *)NULL;
+}
+
+/*
+ * Create a new socket, initialise the fields
+ * It is the responsibility of the caller to
+ * insque() it into the correct linked-list
+ */
+struct socket *
+socreate(Slirp *slirp)
+{
+    struct socket *so = g_new(struct socket, 1);
+
+    memset(so, 0, sizeof(struct socket));
+    so->so_state = SS_NOFDREF;
+    so->s = -1;
+    so->slirp = slirp;
+    so->pollfds_idx = -1;
+
+    return so;
+}
+
+/*
+ * Remove references to so from the given message queue.
+ */
+static void
+soqfree(struct socket *so, struct quehead *qh)
+{
+    struct mbuf *ifq;
+
+    for (ifq = (struct mbuf *) qh->qh_link;
+             (struct quehead *) ifq != qh;
+             ifq = ifq->ifq_next) {
+        if (ifq->ifq_so == so) {
+            struct mbuf *ifm;
+            ifq->ifq_so = NULL;
+            for (ifm = ifq->ifs_next; ifm != ifq; ifm = ifm->ifs_next) {
+                ifm->ifq_so = NULL;
+            }
+        }
+    }
+}
+
+/*
+ * remque and free a socket, clobber cache
+ */
+void
+sofree(struct socket *so)
+{
+  Slirp *slirp = so->slirp;
+
+  soqfree(so, &slirp->if_fastq);
+  soqfree(so, &slirp->if_batchq);
+
+  if (so == slirp->tcp_last_so) {
+      slirp->tcp_last_so = &slirp->tcb;
+  } else if (so == slirp->udp_last_so) {
+      slirp->udp_last_so = &slirp->udb;
+  } else if (so == slirp->icmp_last_so) {
+      slirp->icmp_last_so = &slirp->icmp;
+  }
+  m_free(so->so_m);
+
+  if(so->so_next && so->so_prev)
+    remque(so);  /* crashes if so is not in a queue */
+
+  if (so->so_tcpcb) {
+      free(so->so_tcpcb);
+  }
+  g_free(so);
+}
+
+size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np)
+{
+       int n, lss, total;
+       struct sbuf *sb = &so->so_snd;
+       int len = sb->sb_datalen - sb->sb_cc;
+       int mss = so->so_tcpcb->t_maxseg;
+
+       DEBUG_CALL("sopreprbuf");
+       DEBUG_ARG("so = %p", so);
+
+       if (len <= 0)
+               return 0;
+
+       iov[0].iov_base = sb->sb_wptr;
+        iov[1].iov_base = NULL;
+        iov[1].iov_len = 0;
+       if (sb->sb_wptr < sb->sb_rptr) {
+               iov[0].iov_len = sb->sb_rptr - sb->sb_wptr;
+               /* Should never succeed, but... */
+               if (iov[0].iov_len > len)
+                  iov[0].iov_len = len;
+               if (iov[0].iov_len > mss)
+                  iov[0].iov_len -= iov[0].iov_len%mss;
+               n = 1;
+       } else {
+               iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr;
+               /* Should never succeed, but... */
+               if (iov[0].iov_len > len) iov[0].iov_len = len;
+               len -= iov[0].iov_len;
+               if (len) {
+                       iov[1].iov_base = sb->sb_data;
+                       iov[1].iov_len = sb->sb_rptr - sb->sb_data;
+                       if(iov[1].iov_len > len)
+                          iov[1].iov_len = len;
+                       total = iov[0].iov_len + iov[1].iov_len;
+                       if (total > mss) {
+                               lss = total%mss;
+                               if (iov[1].iov_len > lss) {
+                                       iov[1].iov_len -= lss;
+                                       n = 2;
+                               } else {
+                                       lss -= iov[1].iov_len;
+                                       iov[0].iov_len -= lss;
+                                       n = 1;
+                               }
+                       } else
+                               n = 2;
+               } else {
+                       if (iov[0].iov_len > mss)
+                          iov[0].iov_len -= iov[0].iov_len%mss;
+                       n = 1;
+               }
+       }
+       if (np)
+               *np = n;
+
+       return iov[0].iov_len + (n - 1) * iov[1].iov_len;
+}
+
+/*
+ * Read from so's socket into sb_snd, updating all relevant sbuf fields
+ * NOTE: This will only be called if it is select()ed for reading, so
+ * a read() of 0 (or less) means it's disconnected
+ */
+int
+soread(struct socket *so)
+{
+       int n, nn;
+       struct sbuf *sb = &so->so_snd;
+       struct iovec iov[2];
+
+       DEBUG_CALL("soread");
+       DEBUG_ARG("so = %p", so);
+
+       /*
+        * No need to check if there's enough room to read.
+        * soread wouldn't have been called if there weren't
+        */
+       sopreprbuf(so, iov, &n);
+
+       nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
+       if (nn <= 0) {
+               if (nn < 0 && (errno == EINTR || errno == EAGAIN))
+                       return 0;
+               else {
+                       int err;
+                       socklen_t elen = sizeof err;
+                       struct sockaddr_storage addr;
+                       struct sockaddr *paddr = (struct sockaddr *) &addr;
+                       socklen_t alen = sizeof addr;
+
+                       err = errno;
+                       if (nn == 0) {
+                               if (getpeername(so->s, paddr, &alen) < 0) {
+                                       err = errno;
+                               } else {
+                                       getsockopt(so->s, SOL_SOCKET, SO_ERROR,
+                                               &err, &elen);
+                               }
+                       }
+
+                       DEBUG_MISC(" --- soread() disconnected, nn = %d, errno = %d-%s",
+                       nn, errno,strerror(errno));
+                       sofcantrcvmore(so);
+
+                       if (err == ECONNRESET || err == ECONNREFUSED
+                           || err == ENOTCONN || err == EPIPE) {
+                               tcp_drop(sototcpcb(so), err);
+                       } else {
+                               tcp_sockclosed(sototcpcb(so));
+                       }
+                       return -1;
+               }
+       }
+
+       /*
+        * If there was no error, try and read the second time round
+        * We read again if n = 2 (ie, there's another part of the buffer)
+        * and we read as much as we could in the first read
+        * We don't test for <= 0 this time, because there legitimately
+        * might not be any more data (since the socket is non-blocking),
+        * a close will be detected on next iteration.
+        * A return of -1 won't (shouldn't) happen, since it didn't happen above
+        */
+       if (n == 2 && nn == iov[0].iov_len) {
+            int ret;
+            ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0);
+            if (ret > 0)
+                nn += ret;
+        }
+
+       DEBUG_MISC(" ... read nn = %d bytes", nn);
+
+       /* Update fields */
+       sb->sb_cc += nn;
+       sb->sb_wptr += nn;
+       if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
+               sb->sb_wptr -= sb->sb_datalen;
+       return nn;
+}
+
+int soreadbuf(struct socket *so, const char *buf, int size)
+{
+    int n, nn, copy = size;
+       struct sbuf *sb = &so->so_snd;
+       struct iovec iov[2];
+
+       DEBUG_CALL("soreadbuf");
+       DEBUG_ARG("so = %p", so);
+
+       /*
+        * No need to check if there's enough room to read.
+        * soread wouldn't have been called if there weren't
+        */
+       if (sopreprbuf(so, iov, &n) < size)
+        goto err;
+
+    nn = MIN(iov[0].iov_len, copy);
+    memcpy(iov[0].iov_base, buf, nn);
+
+    copy -= nn;
+    buf += nn;
+
+    if (copy == 0)
+        goto done;
+
+    memcpy(iov[1].iov_base, buf, copy);
+
+done:
+    /* Update fields */
+       sb->sb_cc += size;
+       sb->sb_wptr += size;
+       if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
+               sb->sb_wptr -= sb->sb_datalen;
+    return size;
+err:
+
+    sofcantrcvmore(so);
+    tcp_sockclosed(sototcpcb(so));
+    g_critical("soreadbuf buffer too small");
+    return -1;
+}
+
+/*
+ * Get urgent data
+ *
+ * When the socket is created, we set it SO_OOBINLINE,
+ * so when OOB data arrives, we soread() it and everything
+ * in the send buffer is sent as urgent data
+ */
+int
+sorecvoob(struct socket *so)
+{
+       struct tcpcb *tp = sototcpcb(so);
+       int ret;
+
+       DEBUG_CALL("sorecvoob");
+       DEBUG_ARG("so = %p", so);
+
+       /*
+        * We take a guess at how much urgent data has arrived.
+        * In most situations, when urgent data arrives, the next
+        * read() should get all the urgent data.  This guess will
+        * be wrong however if more data arrives just after the
+        * urgent data, or the read() doesn't return all the
+        * urgent data.
+        */
+       ret = soread(so);
+       if (ret > 0) {
+           tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
+           tp->t_force = 1;
+           tcp_output(tp);
+           tp->t_force = 0;
+       }
+
+       return ret;
+}
+
+/*
+ * Send urgent data
+ * There's a lot duplicated code here, but...
+ */
+int
+sosendoob(struct socket *so)
+{
+       struct sbuf *sb = &so->so_rcv;
+       char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
+
+       int n;
+
+       DEBUG_CALL("sosendoob");
+       DEBUG_ARG("so = %p", so);
+       DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc);
+
+       if (so->so_urgc > 2048)
+          so->so_urgc = 2048; /* XXXX */
+
+       if (sb->sb_rptr < sb->sb_wptr) {
+               /* We can send it directly */
+               n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
+       } else {
+               /*
+                * Since there's no sendv or sendtov like writev,
+                * we must copy all data to a linear buffer then
+                * send it all
+                */
+               uint32_t urgc = so->so_urgc;
+               int len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
+               if (len > urgc) {
+                       len = urgc;
+               }
+               memcpy(buff, sb->sb_rptr, len);
+               urgc -= len;
+               if (urgc) {
+                       n = sb->sb_wptr - sb->sb_data;
+                       if (n > urgc) {
+                               n = urgc;
+                       }
+                       memcpy((buff + len), sb->sb_data, n);
+                       len += n;
+               }
+               n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
+#ifdef DEBUG
+               if (n != len) {
+                       DEBUG_ERROR("Didn't send all data urgently XXXXX");
+               }
+#endif
+       }
+
+       if (n < 0) {
+               return n;
+       }
+       so->so_urgc -= n;
+       DEBUG_MISC(" ---2 sent %d bytes urgent data, %d urgent bytes left", n, so->so_urgc);
+
+       sb->sb_cc -= n;
+       sb->sb_rptr += n;
+       if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
+               sb->sb_rptr -= sb->sb_datalen;
+
+       return n;
+}
+
+/*
+ * Write data from so_rcv to so's socket,
+ * updating all sbuf field as necessary
+ */
+int
+sowrite(struct socket *so)
+{
+       int  n,nn;
+       struct sbuf *sb = &so->so_rcv;
+       int len = sb->sb_cc;
+       struct iovec iov[2];
+
+       DEBUG_CALL("sowrite");
+       DEBUG_ARG("so = %p", so);
+
+       if (so->so_urgc) {
+               uint32_t expected = so->so_urgc;
+               if (sosendoob(so) < expected) {
+                       /* Treat a short write as a fatal error too,
+                        * rather than continuing on and sending the urgent
+                        * data as if it were non-urgent and leaving the
+                        * so_urgc count wrong.
+                        */
+                       goto err_disconnected;
+               }
+               if (sb->sb_cc == 0)
+                       return 0;
+       }
+
+       /*
+        * No need to check if there's something to write,
+        * sowrite wouldn't have been called otherwise
+        */
+
+       iov[0].iov_base = sb->sb_rptr;
+        iov[1].iov_base = NULL;
+        iov[1].iov_len = 0;
+       if (sb->sb_rptr < sb->sb_wptr) {
+               iov[0].iov_len = sb->sb_wptr - sb->sb_rptr;
+               /* Should never succeed, but... */
+               if (iov[0].iov_len > len) iov[0].iov_len = len;
+               n = 1;
+       } else {
+               iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
+               if (iov[0].iov_len > len) iov[0].iov_len = len;
+               len -= iov[0].iov_len;
+               if (len) {
+                       iov[1].iov_base = sb->sb_data;
+                       iov[1].iov_len = sb->sb_wptr - sb->sb_data;
+                       if (iov[1].iov_len > len) iov[1].iov_len = len;
+                       n = 2;
+               } else
+                       n = 1;
+       }
+       /* Check if there's urgent data to send, and if so, send it */
+
+       nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0);
+       /* This should never happen, but people tell me it does *shrug* */
+       if (nn < 0 && (errno == EAGAIN || errno == EINTR))
+               return 0;
+
+       if (nn <= 0) {
+               goto err_disconnected;
+       }
+
+       if (n == 2 && nn == iov[0].iov_len) {
+            int ret;
+            ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len,0);
+            if (ret > 0)
+                nn += ret;
+        }
+        DEBUG_MISC("  ... wrote nn = %d bytes", nn);
+
+       /* Update sbuf */
+       sb->sb_cc -= nn;
+       sb->sb_rptr += nn;
+       if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
+               sb->sb_rptr -= sb->sb_datalen;
+
+       /*
+        * If in DRAIN mode, and there's no more data, set
+        * it CANTSENDMORE
+        */
+       if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0)
+               sofcantsendmore(so);
+
+       return nn;
+
+err_disconnected:
+       DEBUG_MISC(" --- sowrite disconnected, so->so_state = %x, errno = %d",
+               so->so_state, errno);
+       sofcantsendmore(so);
+       tcp_sockclosed(sototcpcb(so));
+       return -1;
+}
+
+/*
+ * recvfrom() a UDP socket
+ */
+void
+sorecvfrom(struct socket *so)
+{
+       struct sockaddr_storage addr;
+       struct sockaddr_storage saddr, daddr;
+       socklen_t addrlen = sizeof(struct sockaddr_storage);
+
+       DEBUG_CALL("sorecvfrom");
+       DEBUG_ARG("so = %p", so);
+
+       if (so->so_type == IPPROTO_ICMP) {   /* This is a "ping" reply */
+         char buff[256];
+         int len;
+
+         len = recvfrom(so->s, buff, 256, 0,
+                        (struct sockaddr *)&addr, &addrlen);
+         /* XXX Check if reply is "correct"? */
+
+         if(len == -1 || len == 0) {
+           uint8_t code=ICMP_UNREACH_PORT;
+
+           if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
+           else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
+
+           DEBUG_MISC(" udp icmp rx errno = %d-%s",
+                   errno,strerror(errno));
+           icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno));
+         } else {
+           icmp_reflect(so->so_m);
+            so->so_m = NULL; /* Don't m_free() it again! */
+         }
+         /* No need for this socket anymore, udp_detach it */
+         udp_detach(so);
+       } else {                                /* A "normal" UDP packet */
+         struct mbuf *m;
+          int len;
+#ifdef _WIN32
+          unsigned long n;
+#else
+          int n;
+#endif
+
+         if (ioctlsocket(so->s, FIONREAD, &n) != 0) {
+             DEBUG_MISC(" ioctlsocket errno = %d-%s\n",
+                        errno,strerror(errno));
+             return;
+         }
+         if (n == 0) {
+             return;
+         }
+
+         m = m_get(so->slirp);
+         if (!m) {
+             return;
+         }
+         switch (so->so_ffamily) {
+         case AF_INET:
+             m->m_data += IF_MAXLINKHDR + sizeof(struct udpiphdr);
+             break;
+         case AF_INET6:
+             m->m_data += IF_MAXLINKHDR + sizeof(struct ip6)
+                                        + sizeof(struct udphdr);
+             break;
+         default:
+             g_assert_not_reached();
+             break;
+         }
+
+         /*
+          * XXX Shouldn't FIONREAD packets destined for port 53,
+          * but I don't know the max packet size for DNS lookups
+          */
+         len = M_FREEROOM(m);
+         /* if (so->so_fport != htons(53)) { */
+
+         if (n > len) {
+           n = (m->m_data - m->m_dat) + m->m_len + n + 1;
+           m_inc(m, n);
+           len = M_FREEROOM(m);
+         }
+         /* } */
+
+         m->m_len = recvfrom(so->s, m->m_data, len, 0,
+                             (struct sockaddr *)&addr, &addrlen);
+         DEBUG_MISC(" did recvfrom %d, errno = %d-%s",
+                 m->m_len, errno,strerror(errno));
+         if(m->m_len<0) {
+           /* Report error as ICMP */
+           switch (so->so_lfamily) {
+           uint8_t code;
+           case AF_INET:
+             code = ICMP_UNREACH_PORT;
+
+             if (errno == EHOSTUNREACH) {
+               code = ICMP_UNREACH_HOST;
+             } else if (errno == ENETUNREACH) {
+               code = ICMP_UNREACH_NET;
+             }
+
+             DEBUG_MISC(" rx error, tx icmp ICMP_UNREACH:%i", code);
+             icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno));
+             break;
+           case AF_INET6:
+             code = ICMP6_UNREACH_PORT;
+
+             if (errno == EHOSTUNREACH) {
+               code = ICMP6_UNREACH_ADDRESS;
+             } else if (errno == ENETUNREACH) {
+               code = ICMP6_UNREACH_NO_ROUTE;
+             }
+
+             DEBUG_MISC(" rx error, tx icmp6 ICMP_UNREACH:%i", code);
+             icmp6_send_error(so->so_m, ICMP6_UNREACH, code);
+             break;
+           default:
+             g_assert_not_reached();
+             break;
+           }
+           m_free(m);
+         } else {
+         /*
+          * Hack: domain name lookup will be used the most for UDP,
+          * and since they'll only be used once there's no need
+          * for the 4 minute (or whatever) timeout... So we time them
+          * out much quicker (10 seconds  for now...)
+          */
+           if (so->so_expire) {
+             if (so->so_fport == htons(53))
+               so->so_expire = curtime + SO_EXPIREFAST;
+             else
+               so->so_expire = curtime + SO_EXPIRE;
+           }
+
+           /*
+            * If this packet was destined for CTL_ADDR,
+            * make it look like that's where it came from
+            */
+           saddr = addr;
+           sotranslate_in(so, &saddr);
+           daddr = so->lhost.ss;
+
+           switch (so->so_ffamily) {
+           case AF_INET:
+               udp_output(so, m, (struct sockaddr_in *) &saddr,
+                          (struct sockaddr_in *) &daddr,
+                          so->so_iptos);
+               break;
+           case AF_INET6:
+               udp6_output(so, m, (struct sockaddr_in6 *) &saddr,
+                           (struct sockaddr_in6 *) &daddr);
+               break;
+           default:
+               g_assert_not_reached();
+               break;
+           }
+         } /* rx error */
+       } /* if ping packet */
+}
+
+/*
+ * sendto() a socket
+ */
+int
+sosendto(struct socket *so, struct mbuf *m)
+{
+       int ret;
+       struct sockaddr_storage addr;
+
+       DEBUG_CALL("sosendto");
+       DEBUG_ARG("so = %p", so);
+       DEBUG_ARG("m = %p", m);
+
+       addr = so->fhost.ss;
+       DEBUG_CALL(" sendto()ing)");
+       sotranslate_out(so, &addr);
+
+       /* Don't care what port we get */
+       ret = sendto(so->s, m->m_data, m->m_len, 0,
+                    (struct sockaddr *)&addr, sockaddr_size(&addr));
+       if (ret < 0)
+               return -1;
+
+       /*
+        * Kill the socket if there's no reply in 4 minutes,
+        * but only if it's an expirable socket
+        */
+       if (so->so_expire)
+               so->so_expire = curtime + SO_EXPIRE;
+       so->so_state &= SS_PERSISTENT_MASK;
+       so->so_state |= SS_ISFCONNECTED; /* So that it gets select()ed */
+       return 0;
+}
+
+/*
+ * Listen for incoming TCP connections
+ */
+struct socket *
+tcp_listen(Slirp *slirp, uint32_t haddr, unsigned hport, uint32_t laddr,
+           unsigned lport, int flags)
+{
+        /* TODO: IPv6 */
+       struct sockaddr_in addr;
+       struct socket *so;
+       int s, opt = 1;
+       socklen_t addrlen = sizeof(addr);
+       memset(&addr, 0, addrlen);
+
+       DEBUG_CALL("tcp_listen");
+       DEBUG_ARG("haddr = %s", inet_ntoa((struct in_addr){.s_addr = haddr}));
+       DEBUG_ARG("hport = %d", ntohs(hport));
+       DEBUG_ARG("laddr = %s", inet_ntoa((struct in_addr){.s_addr = laddr}));
+       DEBUG_ARG("lport = %d", ntohs(lport));
+       DEBUG_ARG("flags = %x", flags);
+
+       so = socreate(slirp);
+
+       /* Don't tcp_attach... we don't need so_snd nor so_rcv */
+       if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) {
+            g_free(so);
+            return NULL;
+       }
+       insque(so, &slirp->tcb);
+
+       /*
+        * SS_FACCEPTONCE sockets must time out.
+        */
+       if (flags & SS_FACCEPTONCE)
+          so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2;
+
+       so->so_state &= SS_PERSISTENT_MASK;
+       so->so_state |= (SS_FACCEPTCONN | flags);
+       so->so_lfamily = AF_INET;
+       so->so_lport = lport; /* Kept in network format */
+       so->so_laddr.s_addr = laddr; /* Ditto */
+
+       addr.sin_family = AF_INET;
+       addr.sin_addr.s_addr = haddr;
+       addr.sin_port = hport;
+
+       if (((s = slirp_socket(AF_INET,SOCK_STREAM,0)) < 0) ||
+           (slirp_socket_set_fast_reuse(s) < 0) ||
+           (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
+           (listen(s,1) < 0)) {
+               int tmperrno = errno; /* Don't clobber the real reason we failed */
+
+                if (s >= 0) {
+                    closesocket(s);
+                }
+               sofree(so);
+               /* Restore the real errno */
+#ifdef _WIN32
+               WSASetLastError(tmperrno);
+#else
+               errno = tmperrno;
+#endif
+               return NULL;
+       }
+       setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
+       opt = 1;
+       setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(int));
+
+       getsockname(s,(struct sockaddr *)&addr,&addrlen);
+       so->so_ffamily = AF_INET;
+       so->so_fport = addr.sin_port;
+       if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
+          so->so_faddr = slirp->vhost_addr;
+       else
+          so->so_faddr = addr.sin_addr;
+
+       so->s = s;
+       return so;
+}
+
+/*
+ * Various session state calls
+ * XXX Should be #define's
+ * The socket state stuff needs work, these often get call 2 or 3
+ * times each when only 1 was needed
+ */
+void
+soisfconnecting(struct socket *so)
+{
+       so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE|
+                         SS_FCANTSENDMORE|SS_FWDRAIN);
+       so->so_state |= SS_ISFCONNECTING; /* Clobber other states */
+}
+
+void
+soisfconnected(struct socket *so)
+{
+       so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF);
+       so->so_state |= SS_ISFCONNECTED; /* Clobber other states */
+}
+
+static void
+sofcantrcvmore(struct socket *so)
+{
+       if ((so->so_state & SS_NOFDREF) == 0) {
+               shutdown(so->s,0);
+       }
+       so->so_state &= ~(SS_ISFCONNECTING);
+       if (so->so_state & SS_FCANTSENDMORE) {
+          so->so_state &= SS_PERSISTENT_MASK;
+          so->so_state |= SS_NOFDREF; /* Don't select it */
+       } else {
+          so->so_state |= SS_FCANTRCVMORE;
+       }
+}
+
+static void
+sofcantsendmore(struct socket *so)
+{
+       if ((so->so_state & SS_NOFDREF) == 0) {
+            shutdown(so->s,1);           /* send FIN to fhost */
+       }
+       so->so_state &= ~(SS_ISFCONNECTING);
+       if (so->so_state & SS_FCANTRCVMORE) {
+          so->so_state &= SS_PERSISTENT_MASK;
+          so->so_state |= SS_NOFDREF; /* as above */
+       } else {
+          so->so_state |= SS_FCANTSENDMORE;
+       }
+}
+
+/*
+ * Set write drain mode
+ * Set CANTSENDMORE once all data has been write()n
+ */
+void
+sofwdrain(struct socket *so)
+{
+       if (so->so_rcv.sb_cc)
+               so->so_state |= SS_FWDRAIN;
+       else
+               sofcantsendmore(so);
+}
+
+/*
+ * Translate addr in host addr when it is a virtual address
+ */
+void sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
+{
+    Slirp *slirp = so->slirp;
+    struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
+
+    switch (addr->ss_family) {
+    case AF_INET:
+        if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+                slirp->vnetwork_addr.s_addr) {
+            /* It's an alias */
+            if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
+                if (get_dns_addr(&sin->sin_addr) < 0) {
+                    sin->sin_addr = loopback_addr;
+                }
+            } else {
+                sin->sin_addr = loopback_addr;
+            }
+        }
+
+        DEBUG_MISC(" addr.sin_port=%d, addr.sin_addr.s_addr=%.16s",
+                   ntohs(sin->sin_port), inet_ntoa(sin->sin_addr));
+        break;
+
+    case AF_INET6:
+        if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6,
+                    slirp->vprefix_len)) {
+            if (in6_equal(&so->so_faddr6, &slirp->vnameserver_addr6)) {
+                uint32_t scope_id;
+                if (get_dns6_addr(&sin6->sin6_addr, &scope_id) >= 0) {
+                    sin6->sin6_scope_id = scope_id;
+                } else {
+                    sin6->sin6_addr = in6addr_loopback;
+                }
+            } else {
+                sin6->sin6_addr = in6addr_loopback;
+            }
+        }
+        break;
+
+    default:
+        break;
+    }
+}
+
+void sotranslate_in(struct socket *so, struct sockaddr_storage *addr)
+{
+    Slirp *slirp = so->slirp;
+    struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
+
+    switch (addr->ss_family) {
+    case AF_INET:
+        if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+            slirp->vnetwork_addr.s_addr) {
+            uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
+
+            if ((so->so_faddr.s_addr & inv_mask) == inv_mask) {
+                sin->sin_addr = slirp->vhost_addr;
+            } else if (sin->sin_addr.s_addr == loopback_addr.s_addr ||
+                       so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
+                sin->sin_addr = so->so_faddr;
+            }
+        }
+        break;
+
+    case AF_INET6:
+        if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6,
+                    slirp->vprefix_len)) {
+            if (in6_equal(&sin6->sin6_addr, &in6addr_loopback)
+                    || !in6_equal(&so->so_faddr6, &slirp->vhost_addr6)) {
+                sin6->sin6_addr = so->so_faddr6;
+            }
+        }
+        break;
+
+    default:
+        break;
+    }
+}
+
+/*
+ * Translate connections from localhost to the real hostname
+ */
+void sotranslate_accept(struct socket *so)
+{
+    Slirp *slirp = so->slirp;
+
+    switch (so->so_ffamily) {
+    case AF_INET:
+        if (so->so_faddr.s_addr == INADDR_ANY ||
+            (so->so_faddr.s_addr & loopback_mask) ==
+            (loopback_addr.s_addr & loopback_mask)) {
+           so->so_faddr = slirp->vhost_addr;
+        }
+        break;
+
+   case AF_INET6:
+        if (in6_equal(&so->so_faddr6, &in6addr_any) ||
+                in6_equal(&so->so_faddr6, &in6addr_loopback)) {
+           so->so_faddr6 = slirp->vhost_addr6;
+        }
+        break;
+
+    default:
+        break;
+    }
+}
+
+void sodrop(struct socket *s, int num)
+{
+    if (sbdrop(&s->so_snd, num)) {
+        s->slirp->cb->notify(s->slirp->opaque);
+    }
+}
diff --git a/slirp/src/socket.h b/slirp/src/socket.h
new file mode 100644 (file)
index 0000000..e4d12cd
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef SLIRP_SOCKET_H
+#define SLIRP_SOCKET_H
+
+#include "misc.h"
+
+#define SO_EXPIRE 240000
+#define SO_EXPIREFAST 10000
+
+/*
+ * Our socket structure
+ */
+
+union slirp_sockaddr {
+    struct sockaddr_storage ss;
+    struct sockaddr_in sin;
+    struct sockaddr_in6 sin6;
+};
+
+struct socket {
+  struct socket *so_next,*so_prev;      /* For a linked list of sockets */
+
+  int s;                           /* The actual socket */
+  struct gfwd_list *guestfwd;
+
+  int pollfds_idx;                 /* GPollFD GArray index */
+
+  Slirp *slirp;                           /* managing slirp instance */
+
+                       /* XXX union these with not-yet-used sbuf params */
+  struct mbuf *so_m;              /* Pointer to the original SYN packet,
+                                   * for non-blocking connect()'s, and
+                                   * PING reply's */
+  struct tcpiphdr *so_ti;         /* Pointer to the original ti within
+                                   * so_mconn, for non-blocking connections */
+  uint32_t      so_urgc;
+  union slirp_sockaddr fhost;      /* Foreign host */
+#define so_faddr fhost.sin.sin_addr
+#define so_fport fhost.sin.sin_port
+#define so_faddr6 fhost.sin6.sin6_addr
+#define so_fport6 fhost.sin6.sin6_port
+#define so_ffamily fhost.ss.ss_family
+
+  union slirp_sockaddr lhost;      /* Local host */
+#define so_laddr lhost.sin.sin_addr
+#define so_lport lhost.sin.sin_port
+#define so_laddr6 lhost.sin6.sin6_addr
+#define so_lport6 lhost.sin6.sin6_port
+#define so_lfamily lhost.ss.ss_family
+
+  uint8_t      so_iptos;       /* Type of service */
+  uint8_t      so_emu;         /* Is the socket emulated? */
+
+  uint8_t       so_type;        /* Type of socket, UDP or TCP */
+  int32_t       so_state;       /* internal state flags SS_*, below */
+
+  struct       tcpcb *so_tcpcb;        /* pointer to TCP protocol control block */
+  unsigned     so_expire;              /* When the socket will expire */
+
+  int  so_queued;              /* Number of packets queued from this socket */
+  int  so_nqueued;             /* Number of packets queued in a row
+                                * Used to determine when to "downgrade" a session
+                                        * from fastq to batchq */
+
+  struct sbuf so_rcv;          /* Receive buffer */
+  struct sbuf so_snd;          /* Send buffer */
+};
+
+
+/*
+ * Socket state bits. (peer means the host on the Internet,
+ * local host means the host on the other end of the modem)
+ */
+#define SS_NOFDREF             0x001   /* No fd reference */
+
+#define SS_ISFCONNECTING       0x002   /* Socket is connecting to peer (non-blocking connect()'s) */
+#define SS_ISFCONNECTED                0x004   /* Socket is connected to peer */
+#define SS_FCANTRCVMORE                0x008   /* Socket can't receive more from peer (for half-closes) */
+#define SS_FCANTSENDMORE       0x010   /* Socket can't send more to peer (for half-closes) */
+#define SS_FWDRAIN             0x040   /* We received a FIN, drain data and set SS_FCANTSENDMORE */
+
+#define SS_CTL                 0x080
+#define SS_FACCEPTCONN         0x100   /* Socket is accepting connections from a host on the internet */
+#define SS_FACCEPTONCE         0x200   /* If set, the SS_FACCEPTCONN socket will die after one accept */
+
+#define SS_PERSISTENT_MASK     0xf000  /* Unremovable state bits */
+#define SS_HOSTFWD             0x1000  /* Socket describes host->guest forwarding */
+#define SS_INCOMING            0x2000  /* Connection was initiated by a host on the internet */
+
+static inline int sockaddr_equal(struct sockaddr_storage *a,
+        struct sockaddr_storage *b)
+{
+    if (a->ss_family != b->ss_family) {
+        return 0;
+    }
+
+    switch (a->ss_family) {
+    case AF_INET:
+    {
+        struct sockaddr_in *a4 = (struct sockaddr_in *) a;
+        struct sockaddr_in *b4 = (struct sockaddr_in *) b;
+        return a4->sin_addr.s_addr == b4->sin_addr.s_addr
+               && a4->sin_port == b4->sin_port;
+    }
+    case AF_INET6:
+    {
+        struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) a;
+        struct sockaddr_in6 *b6 = (struct sockaddr_in6 *) b;
+        return (in6_equal(&a6->sin6_addr, &b6->sin6_addr)
+                && a6->sin6_port == b6->sin6_port);
+    }
+    default:
+        g_assert_not_reached();
+    }
+
+    return 0;
+}
+
+static inline socklen_t sockaddr_size(struct sockaddr_storage *a)
+{
+    switch (a->ss_family) {
+    case AF_INET:
+        return sizeof(struct sockaddr_in);
+    case AF_INET6:
+        return sizeof(struct sockaddr_in6);
+    default:
+        g_assert_not_reached();
+    }
+}
+
+struct socket *solookup(struct socket **, struct socket *,
+        struct sockaddr_storage *, struct sockaddr_storage *);
+struct socket *socreate(Slirp *);
+void sofree(struct socket *);
+int soread(struct socket *);
+int sorecvoob(struct socket *);
+int sosendoob(struct socket *);
+int sowrite(struct socket *);
+void sorecvfrom(struct socket *);
+int sosendto(struct socket *, struct mbuf *);
+struct socket * tcp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned,
+                               int);
+void soisfconnecting(register struct socket *);
+void soisfconnected(register struct socket *);
+void sofwdrain(struct socket *);
+struct iovec; /* For win32 */
+size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
+int soreadbuf(struct socket *so, const char *buf, int size);
+
+void sotranslate_out(struct socket *, struct sockaddr_storage *);
+void sotranslate_in(struct socket *, struct sockaddr_storage *);
+void sotranslate_accept(struct socket *);
+void sodrop(struct socket *, int num);
+
+
+#endif /* SLIRP_SOCKET_H */
diff --git a/slirp/src/state.c b/slirp/src/state.c
new file mode 100644 (file)
index 0000000..f5dd80c
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * libslirp
+ *
+ * Copyright (c) 2004-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "slirp.h"
+#include "vmstate.h"
+#include "state.h"
+#include "stream.h"
+
+static int slirp_tcp_post_load(void *opaque, int version)
+{
+    tcp_template((struct tcpcb *)opaque);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_slirp_tcp = {
+    .name = "slirp-tcp",
+    .version_id = 0,
+    .post_load = slirp_tcp_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT16(t_state, struct tcpcb),
+        VMSTATE_INT16_ARRAY(t_timer, struct tcpcb, TCPT_NTIMERS),
+        VMSTATE_INT16(t_rxtshift, struct tcpcb),
+        VMSTATE_INT16(t_rxtcur, struct tcpcb),
+        VMSTATE_INT16(t_dupacks, struct tcpcb),
+        VMSTATE_UINT16(t_maxseg, struct tcpcb),
+        VMSTATE_UINT8(t_force, struct tcpcb),
+        VMSTATE_UINT16(t_flags, struct tcpcb),
+        VMSTATE_UINT32(snd_una, struct tcpcb),
+        VMSTATE_UINT32(snd_nxt, struct tcpcb),
+        VMSTATE_UINT32(snd_up, struct tcpcb),
+        VMSTATE_UINT32(snd_wl1, struct tcpcb),
+        VMSTATE_UINT32(snd_wl2, struct tcpcb),
+        VMSTATE_UINT32(iss, struct tcpcb),
+        VMSTATE_UINT32(snd_wnd, struct tcpcb),
+        VMSTATE_UINT32(rcv_wnd, struct tcpcb),
+        VMSTATE_UINT32(rcv_nxt, struct tcpcb),
+        VMSTATE_UINT32(rcv_up, struct tcpcb),
+        VMSTATE_UINT32(irs, struct tcpcb),
+        VMSTATE_UINT32(rcv_adv, struct tcpcb),
+        VMSTATE_UINT32(snd_max, struct tcpcb),
+        VMSTATE_UINT32(snd_cwnd, struct tcpcb),
+        VMSTATE_UINT32(snd_ssthresh, struct tcpcb),
+        VMSTATE_INT16(t_idle, struct tcpcb),
+        VMSTATE_INT16(t_rtt, struct tcpcb),
+        VMSTATE_UINT32(t_rtseq, struct tcpcb),
+        VMSTATE_INT16(t_srtt, struct tcpcb),
+        VMSTATE_INT16(t_rttvar, struct tcpcb),
+        VMSTATE_UINT16(t_rttmin, struct tcpcb),
+        VMSTATE_UINT32(max_sndwnd, struct tcpcb),
+        VMSTATE_UINT8(t_oobflags, struct tcpcb),
+        VMSTATE_UINT8(t_iobc, struct tcpcb),
+        VMSTATE_INT16(t_softerror, struct tcpcb),
+        VMSTATE_UINT8(snd_scale, struct tcpcb),
+        VMSTATE_UINT8(rcv_scale, struct tcpcb),
+        VMSTATE_UINT8(request_r_scale, struct tcpcb),
+        VMSTATE_UINT8(requested_s_scale, struct tcpcb),
+        VMSTATE_UINT32(ts_recent, struct tcpcb),
+        VMSTATE_UINT32(ts_recent_age, struct tcpcb),
+        VMSTATE_UINT32(last_ack_sent, struct tcpcb),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* The sbuf has a pair of pointers that are migrated as offsets;
+ * we calculate the offsets and restore the pointers using
+ * pre_save/post_load on a tmp structure.
+ */
+struct sbuf_tmp {
+    struct sbuf *parent;
+    uint32_t roff, woff;
+};
+
+static int sbuf_tmp_pre_save(void *opaque)
+{
+    struct sbuf_tmp *tmp = opaque;
+    tmp->woff = tmp->parent->sb_wptr - tmp->parent->sb_data;
+    tmp->roff = tmp->parent->sb_rptr - tmp->parent->sb_data;
+
+    return 0;
+}
+
+static int sbuf_tmp_post_load(void *opaque, int version)
+{
+    struct sbuf_tmp *tmp = opaque;
+    uint32_t requested_len = tmp->parent->sb_datalen;
+
+    /* Allocate the buffer space used by the field after the tmp */
+    sbreserve(tmp->parent, tmp->parent->sb_datalen);
+
+    if (tmp->parent->sb_datalen != requested_len) {
+        return -ENOMEM;
+    }
+    if (tmp->woff >= requested_len ||
+        tmp->roff >= requested_len) {
+        g_critical("invalid sbuf offsets r/w=%u/%u len=%u",
+                   tmp->roff, tmp->woff, requested_len);
+        return -EINVAL;
+    }
+
+    tmp->parent->sb_wptr = tmp->parent->sb_data + tmp->woff;
+    tmp->parent->sb_rptr = tmp->parent->sb_data + tmp->roff;
+
+    return 0;
+}
+
+
+static const VMStateDescription vmstate_slirp_sbuf_tmp = {
+    .name = "slirp-sbuf-tmp",
+    .post_load = sbuf_tmp_post_load,
+    .pre_save  = sbuf_tmp_pre_save,
+    .version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(woff, struct sbuf_tmp),
+        VMSTATE_UINT32(roff, struct sbuf_tmp),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_slirp_sbuf = {
+    .name = "slirp-sbuf",
+    .version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(sb_cc, struct sbuf),
+        VMSTATE_UINT32(sb_datalen, struct sbuf),
+        VMSTATE_WITH_TMP(struct sbuf, struct sbuf_tmp, vmstate_slirp_sbuf_tmp),
+        VMSTATE_VBUFFER_UINT32(sb_data, struct sbuf, 0, NULL, sb_datalen),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static bool slirp_older_than_v4(void *opaque, int version_id)
+{
+    return version_id < 4;
+}
+
+static bool slirp_family_inet(void *opaque, int version_id)
+{
+    union slirp_sockaddr *ssa = (union slirp_sockaddr *)opaque;
+    return ssa->ss.ss_family == AF_INET;
+}
+
+static int slirp_socket_pre_load(void *opaque)
+{
+    struct socket *so = opaque;
+    if (tcp_attach(so) < 0) {
+        return -ENOMEM;
+    }
+    /* Older versions don't load these fields */
+    so->so_ffamily = AF_INET;
+    so->so_lfamily = AF_INET;
+    return 0;
+}
+
+#ifndef _WIN32
+#define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_UINT32_TEST(f, s, t)
+#else
+/* Win uses u_long rather than uint32_t - but it's still 32bits long */
+#define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_SINGLE_TEST(f, s, t, 0, \
+                                       slirp_vmstate_info_uint32, u_long)
+#endif
+
+/* The OS provided ss_family field isn't that portable; it's size
+ * and type varies (16/8 bit, signed, unsigned)
+ * and the values it contains aren't fully portable.
+ */
+typedef struct SS_FamilyTmpStruct {
+    union slirp_sockaddr    *parent;
+    uint16_t                 portable_family;
+} SS_FamilyTmpStruct;
+
+#define SS_FAMILY_MIG_IPV4   2  /* Linux, BSD, Win... */
+#define SS_FAMILY_MIG_IPV6  10  /* Linux */
+#define SS_FAMILY_MIG_OTHER 0xffff
+
+static int ss_family_pre_save(void *opaque)
+{
+    SS_FamilyTmpStruct *tss = opaque;
+
+    tss->portable_family = SS_FAMILY_MIG_OTHER;
+
+    if (tss->parent->ss.ss_family == AF_INET) {
+        tss->portable_family = SS_FAMILY_MIG_IPV4;
+    } else if (tss->parent->ss.ss_family == AF_INET6) {
+        tss->portable_family = SS_FAMILY_MIG_IPV6;
+    }
+
+    return 0;
+}
+
+static int ss_family_post_load(void *opaque, int version_id)
+{
+    SS_FamilyTmpStruct *tss = opaque;
+
+    switch (tss->portable_family) {
+    case SS_FAMILY_MIG_IPV4:
+        tss->parent->ss.ss_family = AF_INET;
+        break;
+    case SS_FAMILY_MIG_IPV6:
+    case 23: /* compatibility: AF_INET6 from mingw */
+    case 28: /* compatibility: AF_INET6 from FreeBSD sys/socket.h */
+        tss->parent->ss.ss_family = AF_INET6;
+        break;
+    default:
+        g_critical("invalid ss_family type %x", tss->portable_family);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_slirp_ss_family = {
+    .name = "slirp-socket-addr/ss_family",
+    .pre_save  = ss_family_pre_save,
+    .post_load = ss_family_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT16(portable_family, SS_FamilyTmpStruct),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_slirp_socket_addr = {
+    .name = "slirp-socket-addr",
+    .version_id = 4,
+    .fields = (VMStateField[]) {
+        VMSTATE_WITH_TMP(union slirp_sockaddr, SS_FamilyTmpStruct,
+                            vmstate_slirp_ss_family),
+        VMSTATE_SIN4_ADDR(sin.sin_addr.s_addr, union slirp_sockaddr,
+                            slirp_family_inet),
+        VMSTATE_UINT16_TEST(sin.sin_port, union slirp_sockaddr,
+                            slirp_family_inet),
+
+#if 0
+        /* Untested: Needs checking by someone with IPv6 test */
+        VMSTATE_BUFFER_TEST(sin6.sin6_addr, union slirp_sockaddr,
+                            slirp_family_inet6),
+        VMSTATE_UINT16_TEST(sin6.sin6_port, union slirp_sockaddr,
+                            slirp_family_inet6),
+        VMSTATE_UINT32_TEST(sin6.sin6_flowinfo, union slirp_sockaddr,
+                            slirp_family_inet6),
+        VMSTATE_UINT32_TEST(sin6.sin6_scope_id, union slirp_sockaddr,
+                            slirp_family_inet6),
+#endif
+
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_slirp_socket = {
+    .name = "slirp-socket",
+    .version_id = 4,
+    .pre_load = slirp_socket_pre_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(so_urgc, struct socket),
+        /* Pre-v4 versions */
+        VMSTATE_SIN4_ADDR(so_faddr.s_addr, struct socket,
+                            slirp_older_than_v4),
+        VMSTATE_SIN4_ADDR(so_laddr.s_addr, struct socket,
+                            slirp_older_than_v4),
+        VMSTATE_UINT16_TEST(so_fport, struct socket, slirp_older_than_v4),
+        VMSTATE_UINT16_TEST(so_lport, struct socket, slirp_older_than_v4),
+        /* v4 and newer */
+        VMSTATE_STRUCT(fhost, struct socket, 4, vmstate_slirp_socket_addr,
+                       union slirp_sockaddr),
+        VMSTATE_STRUCT(lhost, struct socket, 4, vmstate_slirp_socket_addr,
+                       union slirp_sockaddr),
+
+        VMSTATE_UINT8(so_iptos, struct socket),
+        VMSTATE_UINT8(so_emu, struct socket),
+        VMSTATE_UINT8(so_type, struct socket),
+        VMSTATE_INT32(so_state, struct socket),
+        VMSTATE_STRUCT(so_rcv, struct socket, 0, vmstate_slirp_sbuf,
+                       struct sbuf),
+        VMSTATE_STRUCT(so_snd, struct socket, 0, vmstate_slirp_sbuf,
+                       struct sbuf),
+        VMSTATE_STRUCT_POINTER(so_tcpcb, struct socket, vmstate_slirp_tcp,
+                       struct tcpcb),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_slirp_bootp_client = {
+    .name = "slirp_bootpclient",
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT16(allocated, BOOTPClient),
+        VMSTATE_BUFFER(macaddr, BOOTPClient),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_slirp = {
+    .name = "slirp",
+    .version_id = 4,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT16_V(ip_id, Slirp, 2),
+        VMSTATE_STRUCT_ARRAY(bootp_clients, Slirp, NB_BOOTP_CLIENTS, 3,
+                             vmstate_slirp_bootp_client, BOOTPClient),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void slirp_state_save(Slirp *slirp, SlirpWriteCb write_cb, void *opaque)
+{
+    struct gfwd_list *ex_ptr;
+    SlirpOStream f = {
+        .write_cb = write_cb,
+        .opaque = opaque,
+    };
+
+    for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
+        if (ex_ptr->write_cb) {
+            struct socket *so;
+            so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr,
+                                       ntohs(ex_ptr->ex_fport));
+            if (!so) {
+                continue;
+            }
+
+            slirp_ostream_write_u8(&f, 42);
+            slirp_vmstate_save_state(&f, &vmstate_slirp_socket, so);
+        }
+    slirp_ostream_write_u8(&f, 0);
+
+    slirp_vmstate_save_state(&f, &vmstate_slirp, slirp);
+}
+
+
+int slirp_state_load(Slirp *slirp, int version_id,
+                     SlirpReadCb read_cb, void *opaque)
+{
+    struct gfwd_list *ex_ptr;
+    SlirpIStream f = {
+        .read_cb = read_cb,
+        .opaque = opaque,
+    };
+
+    while (slirp_istream_read_u8(&f)) {
+        int ret;
+        struct socket *so = socreate(slirp);
+
+        ret = slirp_vmstate_load_state(&f, &vmstate_slirp_socket, so, version_id);
+        if (ret < 0) {
+            return ret;
+        }
+
+        if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) !=
+            slirp->vnetwork_addr.s_addr) {
+            return -EINVAL;
+        }
+        for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+            if (ex_ptr->write_cb &&
+                so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
+                so->so_fport == ex_ptr->ex_fport) {
+                break;
+            }
+        }
+        if (!ex_ptr) {
+            return -EINVAL;
+        }
+    }
+
+    return slirp_vmstate_load_state(&f, &vmstate_slirp, slirp, version_id);
+}
+
+int slirp_state_version(void)
+{
+    return 4;
+}
diff --git a/slirp/src/state.h b/slirp/src/state.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/slirp/src/stream.c b/slirp/src/stream.c
new file mode 100644 (file)
index 0000000..d114dde
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * libslirp io streams
+ *
+ * Copyright (c) 2018 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "stream.h"
+#include <glib.h>
+
+bool slirp_istream_read(SlirpIStream *f, void *buf, size_t size)
+{
+    return f->read_cb(buf, size, f->opaque) == size;
+}
+
+bool slirp_ostream_write(SlirpOStream *f, const void *buf, size_t size)
+{
+    return f->write_cb(buf, size, f->opaque) == size;
+}
+
+uint8_t slirp_istream_read_u8(SlirpIStream *f)
+{
+    uint8_t b;
+
+    if (slirp_istream_read(f, &b, sizeof(b))) {
+        return b;
+    }
+
+    return 0;
+}
+
+bool slirp_ostream_write_u8(SlirpOStream *f, uint8_t b)
+{
+    return slirp_ostream_write(f, &b, sizeof(b));
+}
+
+uint16_t slirp_istream_read_u16(SlirpIStream *f)
+{
+    uint16_t b;
+
+    if (slirp_istream_read(f, &b, sizeof(b))) {
+        return GUINT16_FROM_BE(b);
+    }
+
+    return 0;
+}
+
+bool slirp_ostream_write_u16(SlirpOStream *f, uint16_t b)
+{
+    b =  GUINT16_TO_BE(b);
+    return slirp_ostream_write(f, &b, sizeof(b));
+}
+
+uint32_t slirp_istream_read_u32(SlirpIStream *f)
+{
+    uint32_t b;
+
+    if (slirp_istream_read(f, &b, sizeof(b))) {
+        return GUINT32_FROM_BE(b);
+    }
+
+    return 0;
+}
+
+bool slirp_ostream_write_u32(SlirpOStream *f, uint32_t b)
+{
+    b = GUINT32_TO_BE(b);
+    return slirp_ostream_write(f, &b, sizeof(b));
+}
+
+int16_t slirp_istream_read_i16(SlirpIStream *f)
+{
+    int16_t b;
+
+    if (slirp_istream_read(f, &b, sizeof(b))) {
+        return GINT16_FROM_BE(b);
+    }
+
+    return 0;
+}
+
+bool slirp_ostream_write_i16(SlirpOStream *f, int16_t b)
+{
+    b = GINT16_TO_BE(b);
+    return slirp_ostream_write(f, &b, sizeof(b));
+}
+
+int32_t slirp_istream_read_i32(SlirpIStream *f)
+{
+    int32_t b;
+
+    if (slirp_istream_read(f, &b, sizeof(b))) {
+        return GINT32_FROM_BE(b);
+    }
+
+    return 0;
+}
+
+bool slirp_ostream_write_i32(SlirpOStream *f, int32_t b)
+{
+    b = GINT32_TO_BE(b);
+    return slirp_ostream_write(f, &b, sizeof(b));
+}
diff --git a/slirp/src/stream.h b/slirp/src/stream.h
new file mode 100644 (file)
index 0000000..985334c
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef STREAM_H_
+#define STREAM_H_
+
+#include "libslirp.h"
+
+typedef struct SlirpIStream {
+    SlirpReadCb read_cb;
+    void *opaque;
+} SlirpIStream;
+
+typedef struct SlirpOStream {
+    SlirpWriteCb write_cb;
+    void *opaque;
+} SlirpOStream;
+
+bool slirp_istream_read(SlirpIStream *f, void *buf, size_t size);
+bool slirp_ostream_write(SlirpOStream *f, const void *buf, size_t size);
+
+uint8_t slirp_istream_read_u8(SlirpIStream *f);
+bool slirp_ostream_write_u8(SlirpOStream *f, uint8_t b);
+
+uint16_t slirp_istream_read_u16(SlirpIStream *f);
+bool slirp_ostream_write_u16(SlirpOStream *f, uint16_t b);
+
+uint32_t slirp_istream_read_u32(SlirpIStream *f);
+bool slirp_ostream_write_u32(SlirpOStream *f, uint32_t b);
+
+int16_t slirp_istream_read_i16(SlirpIStream *f);
+bool slirp_ostream_write_i16(SlirpOStream *f, int16_t b);
+
+int32_t slirp_istream_read_i32(SlirpIStream *f);
+bool slirp_ostream_write_i32(SlirpOStream *f, int32_t b);
+
+#endif /* STREAM_H_ */
diff --git a/slirp/src/tcp.h b/slirp/src/tcp.h
new file mode 100644 (file)
index 0000000..47aaea6
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1982, 1986, 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. 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.
+ *
+ *     @(#)tcp.h       8.1 (Berkeley) 6/10/93
+ * tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp
+ */
+
+#ifndef TCP_H
+#define TCP_H
+
+#include <glib.h>
+
+typedef        uint32_t tcp_seq;
+
+#define      PR_SLOWHZ       2               /* 2 slow timeouts per second (approx) */
+#define      PR_FASTHZ       5               /* 5 fast timeouts per second (not important) */
+
+#define TCP_SNDSPACE 8192
+#define TCP_RCVSPACE 8192
+
+/*
+ * TCP header.
+ * Per RFC 793, September, 1981.
+ */
+#define tcphdr slirp_tcphdr
+struct tcphdr {
+       uint16_t th_sport;              /* source port */
+       uint16_t th_dport;              /* destination port */
+       tcp_seq th_seq;                 /* sequence number */
+       tcp_seq th_ack;                 /* acknowledgement number */
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+       uint8_t th_off:4,               /* data offset */
+               th_x2:4;                /* (unused) */
+#else
+       uint8_t th_x2:4,                /* (unused) */
+               th_off:4;               /* data offset */
+#endif
+       uint8_t th_flags;
+       uint16_t th_win;                /* window */
+       uint16_t th_sum;                /* checksum */
+       uint16_t th_urp;                /* urgent pointer */
+};
+
+#include "tcp_var.h"
+
+#ifndef TH_FIN
+#define        TH_FIN  0x01
+#define        TH_SYN  0x02
+#define        TH_RST  0x04
+#define        TH_PUSH 0x08
+#define        TH_ACK  0x10
+#define        TH_URG  0x20
+#endif
+
+#ifndef TCPOPT_EOL
+#define        TCPOPT_EOL              0
+#define        TCPOPT_NOP              1
+#define        TCPOPT_MAXSEG           2
+#define TCPOPT_WINDOW          3
+#define TCPOPT_SACK_PERMITTED  4               /* Experimental */
+#define TCPOPT_SACK            5               /* Experimental */
+#define TCPOPT_TIMESTAMP       8
+
+#define TCPOPT_TSTAMP_HDR      \
+    (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP)
+#endif
+
+#ifndef TCPOLEN_MAXSEG
+#define    TCPOLEN_MAXSEG              4
+#define    TCPOLEN_WINDOW              3
+#define    TCPOLEN_SACK_PERMITTED      2
+#define    TCPOLEN_TIMESTAMP           10
+#define    TCPOLEN_TSTAMP_APPA         (TCPOLEN_TIMESTAMP+2) /* appendix A */
+#endif
+
+/*
+ * Default maximum segment size for TCP.
+ * With an IP MSS of 576, this is 536,
+ * but 512 is probably more convenient.
+ * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)).
+ *
+ * We make this 1460 because we only care about Ethernet in the qemu context.
+ */
+#undef TCP_MSS
+#define        TCP_MSS 1460
+#undef TCP6_MSS
+#define TCP6_MSS 1440
+
+#undef TCP_MAXWIN
+#define        TCP_MAXWIN      65535   /* largest value for (unscaled) window */
+
+#undef TCP_MAX_WINSHIFT
+#define TCP_MAX_WINSHIFT       14      /* maximum window shift */
+
+/*
+ * User-settable options (used with setsockopt).
+ *
+ * We don't use the system headers on unix because we have conflicting
+ * local structures. We can't avoid the system definitions on Windows,
+ * so we undefine them.
+ */
+#undef TCP_NODELAY
+#define        TCP_NODELAY     0x01    /* don't delay send to coalesce packets */
+#undef TCP_MAXSEG
+
+/*
+ * TCP FSM state definitions.
+ * Per RFC793, September, 1981.
+ */
+
+#define TCP_NSTATES     11
+
+#define TCPS_CLOSED             0       /* closed */
+#define TCPS_LISTEN             1       /* listening for connection */
+#define TCPS_SYN_SENT           2       /* active, have sent syn */
+#define TCPS_SYN_RECEIVED       3       /* have send and received syn */
+/* states < TCPS_ESTABLISHED are those where connections not established */
+#define TCPS_ESTABLISHED        4       /* established */
+#define TCPS_CLOSE_WAIT         5       /* rcvd fin, waiting for close */
+/* states > TCPS_CLOSE_WAIT are those where user has closed */
+#define TCPS_FIN_WAIT_1         6       /* have closed, sent fin */
+#define TCPS_CLOSING            7       /* closed xchd FIN; await FIN ACK */
+#define TCPS_LAST_ACK           8       /* had fin and close; await FIN ACK */
+/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */
+#define TCPS_FIN_WAIT_2         9       /* have closed, fin is acked */
+#define TCPS_TIME_WAIT          10      /* in 2*msl quiet wait after close */
+
+#define TCPS_HAVERCVDSYN(s)     ((s) >= TCPS_SYN_RECEIVED)
+#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED)
+#define TCPS_HAVERCVDFIN(s)     ((s) >= TCPS_TIME_WAIT)
+
+/*
+ * TCP sequence numbers are 32 bit integers operated
+ * on with modular arithmetic.  These macros can be
+ * used to compare such integers.
+ */
+#define SEQ_LT(a,b)     ((int)((a)-(b)) < 0)
+#define SEQ_LEQ(a,b)    ((int)((a)-(b)) <= 0)
+#define SEQ_GT(a,b)     ((int)((a)-(b)) > 0)
+#define SEQ_GEQ(a,b)    ((int)((a)-(b)) >= 0)
+
+/*
+ * Macros to initialize tcp sequence numbers for
+ * send and receive from initial send and receive
+ * sequence numbers.
+ */
+#define tcp_rcvseqinit(tp) \
+     (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1
+
+#define tcp_sendseqinit(tp) \
+    (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss
+
+#define TCP_ISSINCR     (125*1024)      /* increment for tcp_iss each second */
+
+#endif
diff --git a/slirp/src/tcp_input.c b/slirp/src/tcp_input.c
new file mode 100644 (file)
index 0000000..b10477f
--- /dev/null
@@ -0,0 +1,1556 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994
+ *     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. 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.
+ *
+ *     @(#)tcp_input.c 8.5 (Berkeley) 4/10/94
+ * tcp_input.c,v 1.10 1994/10/13 18:36:32 wollman Exp
+ */
+
+/*
+ * Changes and additions relating to SLiRP
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include "slirp.h"
+#include "ip_icmp.h"
+
+#define        TCPREXMTTHRESH 3
+
+#define TCP_PAWS_IDLE  (24 * 24 * 60 * 60 * PR_SLOWHZ)
+
+/* for modulo comparisons of timestamps */
+#define TSTMP_LT(a,b)  ((int)((a)-(b)) < 0)
+#define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0)
+
+/*
+ * Insert segment ti into reassembly queue of tcp with
+ * control block tp.  Return TH_FIN if reassembly now includes
+ * a segment with FIN.  The macro form does the common case inline
+ * (segment is the next to be received on an established connection,
+ * and the queue is empty), avoiding linkage into and removal
+ * from the queue and repetition of various conversions.
+ * Set DELACK for segments received in order, but ack immediately
+ * when segments are out of order (so fast retransmit can work).
+ */
+#define        TCP_REASS(tp, ti, m, so, flags) { \
+       if ((ti)->ti_seq == (tp)->rcv_nxt && \
+        tcpfrag_list_empty(tp) && \
+           (tp)->t_state == TCPS_ESTABLISHED) { \
+               tp->t_flags |= TF_DELACK; \
+               (tp)->rcv_nxt += (ti)->ti_len; \
+               flags = (ti)->ti_flags & TH_FIN; \
+               if (so->so_emu) { \
+                       if (tcp_emu((so),(m))) sbappend(so, (m)); \
+               } else \
+                       sbappend((so), (m)); \
+       } else { \
+               (flags) = tcp_reass((tp), (ti), (m)); \
+               tp->t_flags |= TF_ACKNOW; \
+       } \
+}
+
+static void tcp_dooptions(struct tcpcb *tp, uint8_t *cp, int cnt,
+                          struct tcpiphdr *ti);
+static void tcp_xmit_timer(register struct tcpcb *tp, int rtt);
+
+static int
+tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti,
+          struct mbuf *m)
+{
+       register struct tcpiphdr *q;
+       struct socket *so = tp->t_socket;
+       int flags;
+
+       /*
+        * Call with ti==NULL after become established to
+        * force pre-ESTABLISHED data up to user socket.
+        */
+        if (ti == NULL)
+               goto present;
+
+       /*
+        * Find a segment which begins after this one does.
+        */
+       for (q = tcpfrag_list_first(tp); !tcpfrag_list_end(q, tp);
+            q = tcpiphdr_next(q))
+               if (SEQ_GT(q->ti_seq, ti->ti_seq))
+                       break;
+
+       /*
+        * If there is a preceding segment, it may provide some of
+        * our data already.  If so, drop the data from the incoming
+        * segment.  If it provides all of our data, drop us.
+        */
+       if (!tcpfrag_list_end(tcpiphdr_prev(q), tp)) {
+               register int i;
+               q = tcpiphdr_prev(q);
+               /* conversion to int (in i) handles seq wraparound */
+               i = q->ti_seq + q->ti_len - ti->ti_seq;
+               if (i > 0) {
+                       if (i >= ti->ti_len) {
+                               m_free(m);
+                               /*
+                                * Try to present any queued data
+                                * at the left window edge to the user.
+                                * This is needed after the 3-WHS
+                                * completes.
+                                */
+                               goto present;   /* ??? */
+                       }
+                       m_adj(m, i);
+                       ti->ti_len -= i;
+                       ti->ti_seq += i;
+               }
+               q = tcpiphdr_next(q);
+       }
+       ti->ti_mbuf = m;
+
+       /*
+        * While we overlap succeeding segments trim them or,
+        * if they are completely covered, dequeue them.
+        */
+       while (!tcpfrag_list_end(q, tp)) {
+               register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq;
+               if (i <= 0)
+                       break;
+               if (i < q->ti_len) {
+                       q->ti_seq += i;
+                       q->ti_len -= i;
+                       m_adj(q->ti_mbuf, i);
+                       break;
+               }
+               q = tcpiphdr_next(q);
+               m = tcpiphdr_prev(q)->ti_mbuf;
+               remque(tcpiphdr2qlink(tcpiphdr_prev(q)));
+               m_free(m);
+       }
+
+       /*
+        * Stick new segment in its place.
+        */
+       insque(tcpiphdr2qlink(ti), tcpiphdr2qlink(tcpiphdr_prev(q)));
+
+present:
+       /*
+        * Present data to user, advancing rcv_nxt through
+        * completed sequence space.
+        */
+       if (!TCPS_HAVEESTABLISHED(tp->t_state))
+               return (0);
+       ti = tcpfrag_list_first(tp);
+       if (tcpfrag_list_end(ti, tp) || ti->ti_seq != tp->rcv_nxt)
+               return (0);
+       if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len)
+               return (0);
+       do {
+               tp->rcv_nxt += ti->ti_len;
+               flags = ti->ti_flags & TH_FIN;
+               remque(tcpiphdr2qlink(ti));
+               m = ti->ti_mbuf;
+               ti = tcpiphdr_next(ti);
+               if (so->so_state & SS_FCANTSENDMORE)
+                       m_free(m);
+               else {
+                       if (so->so_emu) {
+                               if (tcp_emu(so,m)) sbappend(so, m);
+                       } else
+                               sbappend(so, m);
+               }
+       } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt);
+       return (flags);
+}
+
+/*
+ * TCP input routine, follows pages 65-76 of the
+ * protocol specification dated September, 1981 very closely.
+ */
+void
+tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
+{
+       struct ip save_ip, *ip;
+       struct ip6 save_ip6, *ip6;
+       register struct tcpiphdr *ti;
+       char *optp = NULL;
+       int optlen = 0;
+       int len, tlen, off;
+        register struct tcpcb *tp = NULL;
+       register int tiflags;
+        struct socket *so = NULL;
+       int todrop, acked, ourfinisacked, needoutput = 0;
+       int iss = 0;
+       uint32_t tiwin;
+       int ret;
+       struct sockaddr_storage lhost, fhost;
+       struct sockaddr_in *lhost4, *fhost4;
+       struct sockaddr_in6 *lhost6, *fhost6;
+    struct gfwd_list *ex_ptr;
+    Slirp *slirp;
+
+       DEBUG_CALL("tcp_input");
+       DEBUG_ARG("m = %p  iphlen = %2d  inso = %p",
+              m, iphlen, inso);
+
+       /*
+        * If called with m == 0, then we're continuing the connect
+        */
+       if (m == NULL) {
+               so = inso;
+               slirp = so->slirp;
+
+               /* Re-set a few variables */
+               tp = sototcpcb(so);
+               m = so->so_m;
+                so->so_m = NULL;
+               ti = so->so_ti;
+               tiwin = ti->ti_win;
+               tiflags = ti->ti_flags;
+
+               goto cont_conn;
+       }
+       slirp = m->slirp;
+
+       ip = mtod(m, struct ip *);
+       ip6 = mtod(m, struct ip6 *);
+
+       switch (af) {
+       case AF_INET:
+           if (iphlen > sizeof(struct ip)) {
+               ip_stripoptions(m, (struct mbuf *)0);
+               iphlen = sizeof(struct ip);
+           }
+           /* XXX Check if too short */
+
+
+           /*
+            * Save a copy of the IP header in case we want restore it
+            * for sending an ICMP error message in response.
+            */
+           save_ip = *ip;
+           save_ip.ip_len += iphlen;
+
+           /*
+            * Get IP and TCP header together in first mbuf.
+            * Note: IP leaves IP header in first mbuf.
+            */
+           m->m_data -= sizeof(struct tcpiphdr) - sizeof(struct ip)
+                                                - sizeof(struct tcphdr);
+           m->m_len += sizeof(struct tcpiphdr) - sizeof(struct ip)
+                                               - sizeof(struct tcphdr);
+           ti = mtod(m, struct tcpiphdr *);
+
+           /*
+            * Checksum extended TCP header and data.
+            */
+           tlen = ip->ip_len;
+           tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
+           memset(&ti->ih_mbuf, 0 , sizeof(struct mbuf_ptr));
+           memset(&ti->ti, 0, sizeof(ti->ti));
+           ti->ti_x0 = 0;
+           ti->ti_src = save_ip.ip_src;
+           ti->ti_dst = save_ip.ip_dst;
+           ti->ti_pr = save_ip.ip_p;
+           ti->ti_len = htons((uint16_t)tlen);
+           break;
+
+       case AF_INET6:
+           /*
+            * Save a copy of the IP header in case we want restore it
+            * for sending an ICMP error message in response.
+            */
+           save_ip6 = *ip6;
+           /*
+            * Get IP and TCP header together in first mbuf.
+            * Note: IP leaves IP header in first mbuf.
+            */
+           m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip6)
+                                                + sizeof(struct tcphdr));
+           m->m_len  += sizeof(struct tcpiphdr) - (sizeof(struct ip6)
+                                                + sizeof(struct tcphdr));
+           ti = mtod(m, struct tcpiphdr *);
+
+           tlen = ip6->ip_pl;
+           tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
+           memset(&ti->ih_mbuf, 0 , sizeof(struct mbuf_ptr));
+           memset(&ti->ti, 0, sizeof(ti->ti));
+           ti->ti_x0 = 0;
+           ti->ti_src6 = save_ip6.ip_src;
+           ti->ti_dst6 = save_ip6.ip_dst;
+           ti->ti_nh6 = save_ip6.ip_nh;
+           ti->ti_len = htons((uint16_t)tlen);
+           break;
+
+       default:
+           g_assert_not_reached();
+       }
+
+       len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
+       if (cksum(m, len)) {
+           goto drop;
+       }
+
+       /*
+        * Check that TCP offset makes sense,
+        * pull out TCP options and adjust length.              XXX
+        */
+       off = ti->ti_off << 2;
+       if (off < sizeof (struct tcphdr) || off > tlen) {
+         goto drop;
+       }
+       tlen -= off;
+       ti->ti_len = tlen;
+       if (off > sizeof (struct tcphdr)) {
+         optlen = off - sizeof (struct tcphdr);
+         optp = mtod(m, char *) + sizeof (struct tcpiphdr);
+       }
+       tiflags = ti->ti_flags;
+
+       /*
+        * Convert TCP protocol specific fields to host format.
+        */
+       NTOHL(ti->ti_seq);
+       NTOHL(ti->ti_ack);
+       NTOHS(ti->ti_win);
+       NTOHS(ti->ti_urp);
+
+       /*
+        * Drop TCP, IP headers and TCP options.
+        */
+       m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+       m->m_len  -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+
+       /*
+        * Locate pcb for segment.
+        */
+findso:
+       lhost.ss_family = af;
+       fhost.ss_family = af;
+       switch (af) {
+       case AF_INET:
+           lhost4 = (struct sockaddr_in *) &lhost;
+           lhost4->sin_addr = ti->ti_src;
+           lhost4->sin_port = ti->ti_sport;
+           fhost4 = (struct sockaddr_in *) &fhost;
+           fhost4->sin_addr = ti->ti_dst;
+           fhost4->sin_port = ti->ti_dport;
+           break;
+       case AF_INET6:
+           lhost6 = (struct sockaddr_in6 *) &lhost;
+           lhost6->sin6_addr = ti->ti_src6;
+           lhost6->sin6_port = ti->ti_sport;
+           fhost6 = (struct sockaddr_in6 *) &fhost;
+           fhost6->sin6_addr = ti->ti_dst6;
+           fhost6->sin6_port = ti->ti_dport;
+           break;
+       default:
+           g_assert_not_reached();
+       }
+
+       so = solookup(&slirp->tcp_last_so, &slirp->tcb, &lhost, &fhost);
+
+       /*
+        * If the state is CLOSED (i.e., TCB does not exist) then
+        * all data in the incoming segment is discarded.
+        * If the TCB exists but is in CLOSED state, it is embryonic,
+        * but should either do a listen or a connect soon.
+        *
+        * state == CLOSED means we've done socreate() but haven't
+        * attached it to a protocol yet...
+        *
+        * XXX If a TCB does not exist, and the TH_SYN flag is
+        * the only flag set, then create a session, mark it
+        * as if it was LISTENING, and continue...
+        */
+        if (so == NULL) {
+          /* TODO: IPv6 */
+          if (slirp->restricted) {
+            /* Any hostfwds will have an existing socket, so we only get here
+             * for non-hostfwd connections. These should be dropped, unless it
+             * happens to be a guestfwd.
+             */
+            for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+                if (ex_ptr->ex_fport == ti->ti_dport &&
+                    ti->ti_dst.s_addr == ex_ptr->ex_addr.s_addr) {
+                    break;
+                }
+            }
+            if (!ex_ptr) {
+                goto dropwithreset;
+            }
+          }
+
+         if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN)
+           goto dropwithreset;
+
+          so = socreate(slirp);
+         if (tcp_attach(so) < 0) {
+            g_free(so); /* Not sofree (if it failed, it's not insqued) */
+            goto dropwithreset;
+         }
+
+         sbreserve(&so->so_snd, TCP_SNDSPACE);
+         sbreserve(&so->so_rcv, TCP_RCVSPACE);
+
+         so->lhost.ss = lhost;
+         so->fhost.ss = fhost;
+
+         so->so_iptos = tcp_tos(so);
+         if (so->so_iptos == 0) {
+             switch (af) {
+             case AF_INET:
+                 so->so_iptos = ((struct ip *)ti)->ip_tos;
+                 break;
+             case AF_INET6:
+                 break;
+             default:
+                 g_assert_not_reached();
+             }
+         }
+
+         tp = sototcpcb(so);
+         tp->t_state = TCPS_LISTEN;
+       }
+
+        /*
+         * If this is a still-connecting socket, this probably
+         * a retransmit of the SYN.  Whether it's a retransmit SYN
+        * or something else, we nuke it.
+         */
+        if (so->so_state & SS_ISFCONNECTING)
+                goto drop;
+
+       tp = sototcpcb(so);
+
+       /* XXX Should never fail */
+        if (tp == NULL)
+               goto dropwithreset;
+       if (tp->t_state == TCPS_CLOSED)
+               goto drop;
+
+       tiwin = ti->ti_win;
+
+       /*
+        * Segment received on connection.
+        * Reset idle time and keep-alive timer.
+        */
+       tp->t_idle = 0;
+       if (slirp_do_keepalive)
+          tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
+       else
+          tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
+
+       /*
+        * Process options if not in LISTEN state,
+        * else do it below (after getting remote address).
+        */
+       if (optp && tp->t_state != TCPS_LISTEN)
+               tcp_dooptions(tp, (uint8_t *)optp, optlen, ti);
+
+       /*
+        * Header prediction: check for the two common cases
+        * of a uni-directional data xfer.  If the packet has
+        * no control flags, is in-sequence, the window didn't
+        * change and we're not retransmitting, it's a
+        * candidate.  If the length is zero and the ack moved
+        * forward, we're the sender side of the xfer.  Just
+        * free the data acked & wake any higher level process
+        * that was blocked waiting for space.  If the length
+        * is non-zero and the ack didn't move, we're the
+        * receiver side.  If we're getting packets in-order
+        * (the reassembly queue is empty), add the data to
+        * the socket buffer and note that we need a delayed ack.
+        *
+        * XXX Some of these tests are not needed
+        * eg: the tiwin == tp->snd_wnd prevents many more
+        * predictions.. with no *real* advantage..
+        */
+       if (tp->t_state == TCPS_ESTABLISHED &&
+           (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&
+           ti->ti_seq == tp->rcv_nxt &&
+           tiwin && tiwin == tp->snd_wnd &&
+           tp->snd_nxt == tp->snd_max) {
+               if (ti->ti_len == 0) {
+                       if (SEQ_GT(ti->ti_ack, tp->snd_una) &&
+                           SEQ_LEQ(ti->ti_ack, tp->snd_max) &&
+                           tp->snd_cwnd >= tp->snd_wnd) {
+                               /*
+                                * this is a pure ack for outstanding data.
+                                */
+                               if (tp->t_rtt &&
+                                   SEQ_GT(ti->ti_ack, tp->t_rtseq))
+                                       tcp_xmit_timer(tp, tp->t_rtt);
+                               acked = ti->ti_ack - tp->snd_una;
+                               sodrop(so, acked);
+                               tp->snd_una = ti->ti_ack;
+                               m_free(m);
+
+                               /*
+                                * If all outstanding data are acked, stop
+                                * retransmit timer, otherwise restart timer
+                                * using current (possibly backed-off) value.
+                                * If process is waiting for space,
+                                * wakeup/selwakeup/signal.  If data
+                                * are ready to send, let tcp_output
+                                * decide between more output or persist.
+                                */
+                               if (tp->snd_una == tp->snd_max)
+                                       tp->t_timer[TCPT_REXMT] = 0;
+                               else if (tp->t_timer[TCPT_PERSIST] == 0)
+                                       tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+
+                               /*
+                                * This is called because sowwakeup might have
+                                * put data into so_snd.  Since we don't so sowwakeup,
+                                * we don't need this.. XXX???
+                                */
+                               if (so->so_snd.sb_cc)
+                                       (void) tcp_output(tp);
+
+                               return;
+                       }
+               } else if (ti->ti_ack == tp->snd_una &&
+                   tcpfrag_list_empty(tp) &&
+                   ti->ti_len <= sbspace(&so->so_rcv)) {
+                       /*
+                        * this is a pure, in-sequence data packet
+                        * with nothing on the reassembly queue and
+                        * we have enough buffer space to take it.
+                        */
+                       tp->rcv_nxt += ti->ti_len;
+                       /*
+                        * Add data to socket buffer.
+                        */
+                       if (so->so_emu) {
+                               if (tcp_emu(so,m)) sbappend(so, m);
+                       } else
+                               sbappend(so, m);
+
+                       /*
+                        * If this is a short packet, then ACK now - with Nagel
+                        *      congestion avoidance sender won't send more until
+                        *      he gets an ACK.
+                        *
+                        * It is better to not delay acks at all to maximize
+                        * TCP throughput.  See RFC 2581.
+                        */
+                       tp->t_flags |= TF_ACKNOW;
+                       tcp_output(tp);
+                       return;
+               }
+       } /* header prediction */
+       /*
+        * Calculate amount of space in receive window,
+        * and then do TCP input processing.
+        * Receive window is amount of space in rcv queue,
+        * but not less than advertised window.
+        */
+       { int win;
+          win = sbspace(&so->so_rcv);
+         if (win < 0)
+           win = 0;
+          tp->rcv_wnd = MAX(win, (int)(tp->rcv_adv - tp->rcv_nxt));
+       }
+
+       switch (tp->t_state) {
+
+       /*
+        * If the state is LISTEN then ignore segment if it contains an RST.
+        * If the segment contains an ACK then it is bad and send a RST.
+        * If it does not contain a SYN then it is not interesting; drop it.
+        * Don't bother responding if the destination was a broadcast.
+        * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial
+        * tp->iss, and send a segment:
+        *     <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>
+        * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss.
+        * Fill in remote peer address fields if not previously specified.
+        * Enter SYN_RECEIVED state, and process any other fields of this
+        * segment in this state.
+        */
+       case TCPS_LISTEN: {
+
+         if (tiflags & TH_RST)
+           goto drop;
+         if (tiflags & TH_ACK)
+           goto dropwithreset;
+         if ((tiflags & TH_SYN) == 0)
+           goto drop;
+
+         /*
+          * This has way too many gotos...
+          * But a bit of spaghetti code never hurt anybody :)
+          */
+
+         /*
+          * If this is destined for the control address, then flag to
+          * tcp_ctl once connected, otherwise connect
+          */
+          /* TODO: IPv6 */
+         if (af == AF_INET &&
+                (so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+                slirp->vnetwork_addr.s_addr) {
+           if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr &&
+               so->so_faddr.s_addr != slirp->vnameserver_addr.s_addr) {
+               /* May be an add exec */
+               for (ex_ptr = slirp->guestfwd_list; ex_ptr;
+                    ex_ptr = ex_ptr->ex_next) {
+                 if(ex_ptr->ex_fport == so->so_fport &&
+                    so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
+                   so->so_state |= SS_CTL;
+                   break;
+                 }
+               }
+               if (so->so_state & SS_CTL) {
+                   goto cont_input;
+               }
+           }
+           /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */
+         }
+
+         if (so->so_emu & EMU_NOCONNECT) {
+           so->so_emu &= ~EMU_NOCONNECT;
+           goto cont_input;
+         }
+
+         if ((tcp_fconnect(so, so->so_ffamily) == -1) &&
+              (errno != EAGAIN) &&
+              (errno != EINPROGRESS) && (errno != EWOULDBLOCK)
+          ) {
+           uint8_t code;
+           DEBUG_MISC(" tcp fconnect errno = %d-%s", errno, strerror(errno));
+           if(errno == ECONNREFUSED) {
+             /* ACK the SYN, send RST to refuse the connection */
+             tcp_respond(tp, ti, m, ti->ti_seq + 1, (tcp_seq) 0,
+                         TH_RST | TH_ACK, af);
+           } else {
+             switch (af) {
+             case AF_INET:
+               code = ICMP_UNREACH_NET;
+               if (errno == EHOSTUNREACH) {
+                 code = ICMP_UNREACH_HOST;
+               }
+               break;
+             case AF_INET6:
+               code = ICMP6_UNREACH_NO_ROUTE;
+               if (errno == EHOSTUNREACH) {
+                 code = ICMP6_UNREACH_ADDRESS;
+               }
+               break;
+             default:
+               g_assert_not_reached();
+             }
+             HTONL(ti->ti_seq);             /* restore tcp header */
+             HTONL(ti->ti_ack);
+             HTONS(ti->ti_win);
+             HTONS(ti->ti_urp);
+             m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+             m->m_len  += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+             switch (af) {
+             case AF_INET:
+               m->m_data += sizeof(struct tcpiphdr) - sizeof(struct ip)
+                                                    - sizeof(struct tcphdr);
+               m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct ip)
+                                                    - sizeof(struct tcphdr);
+               *ip = save_ip;
+               icmp_send_error(m, ICMP_UNREACH, code, 0, strerror(errno));
+               break;
+             case AF_INET6:
+               m->m_data += sizeof(struct tcpiphdr) - (sizeof(struct ip6)
+                                                    + sizeof(struct tcphdr));
+               m->m_len  -= sizeof(struct tcpiphdr) - (sizeof(struct ip6)
+                                                    + sizeof(struct tcphdr));
+               *ip6 = save_ip6;
+               icmp6_send_error(m, ICMP6_UNREACH, code);
+               break;
+             default:
+               g_assert_not_reached();
+             }
+           }
+            tcp_close(tp);
+           m_free(m);
+         } else {
+           /*
+            * Haven't connected yet, save the current mbuf
+            * and ti, and return
+            * XXX Some OS's don't tell us whether the connect()
+            * succeeded or not.  So we must time it out.
+            */
+           so->so_m = m;
+           so->so_ti = ti;
+           tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
+           tp->t_state = TCPS_SYN_RECEIVED;
+           /*
+            * Initialize receive sequence numbers now so that we can send a
+            * valid RST if the remote end rejects our connection.
+            */
+           tp->irs = ti->ti_seq;
+           tcp_rcvseqinit(tp);
+           tcp_template(tp);
+         }
+         return;
+
+       cont_conn:
+         /* m==NULL
+          * Check if the connect succeeded
+          */
+         if (so->so_state & SS_NOFDREF) {
+           tp = tcp_close(tp);
+           goto dropwithreset;
+         }
+       cont_input:
+         tcp_template(tp);
+
+         if (optp)
+           tcp_dooptions(tp, (uint8_t *)optp, optlen, ti);
+
+         if (iss)
+           tp->iss = iss;
+         else
+           tp->iss = slirp->tcp_iss;
+         slirp->tcp_iss += TCP_ISSINCR/2;
+         tp->irs = ti->ti_seq;
+         tcp_sendseqinit(tp);
+         tcp_rcvseqinit(tp);
+         tp->t_flags |= TF_ACKNOW;
+         tp->t_state = TCPS_SYN_RECEIVED;
+         tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
+         goto trimthenstep6;
+       } /* case TCPS_LISTEN */
+
+       /*
+        * If the state is SYN_SENT:
+        *      if seg contains an ACK, but not for our SYN, drop the input.
+        *      if seg contains a RST, then drop the connection.
+        *      if seg does not contain SYN, then drop it.
+        * Otherwise this is an acceptable SYN segment
+        *      initialize tp->rcv_nxt and tp->irs
+        *      if seg contains ack then advance tp->snd_una
+        *      if SYN has been acked change to ESTABLISHED else SYN_RCVD state
+        *      arrange for segment to be acked (eventually)
+        *      continue processing rest of data/controls, beginning with URG
+        */
+       case TCPS_SYN_SENT:
+               if ((tiflags & TH_ACK) &&
+                   (SEQ_LEQ(ti->ti_ack, tp->iss) ||
+                    SEQ_GT(ti->ti_ack, tp->snd_max)))
+                       goto dropwithreset;
+
+               if (tiflags & TH_RST) {
+                        if (tiflags & TH_ACK) {
+                                tcp_drop(tp, 0); /* XXX Check t_softerror! */
+                        }
+                       goto drop;
+               }
+
+               if ((tiflags & TH_SYN) == 0)
+                       goto drop;
+               if (tiflags & TH_ACK) {
+                       tp->snd_una = ti->ti_ack;
+                       if (SEQ_LT(tp->snd_nxt, tp->snd_una))
+                               tp->snd_nxt = tp->snd_una;
+               }
+
+               tp->t_timer[TCPT_REXMT] = 0;
+               tp->irs = ti->ti_seq;
+               tcp_rcvseqinit(tp);
+               tp->t_flags |= TF_ACKNOW;
+               if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) {
+                       soisfconnected(so);
+                       tp->t_state = TCPS_ESTABLISHED;
+
+                       (void) tcp_reass(tp, (struct tcpiphdr *)0,
+                               (struct mbuf *)0);
+                       /*
+                        * if we didn't have to retransmit the SYN,
+                        * use its rtt as our initial srtt & rtt var.
+                        */
+                       if (tp->t_rtt)
+                               tcp_xmit_timer(tp, tp->t_rtt);
+               } else
+                       tp->t_state = TCPS_SYN_RECEIVED;
+
+trimthenstep6:
+               /*
+                * Advance ti->ti_seq to correspond to first data byte.
+                * If data, trim to stay within window,
+                * dropping FIN if necessary.
+                */
+               ti->ti_seq++;
+               if (ti->ti_len > tp->rcv_wnd) {
+                       todrop = ti->ti_len - tp->rcv_wnd;
+                       m_adj(m, -todrop);
+                       ti->ti_len = tp->rcv_wnd;
+                       tiflags &= ~TH_FIN;
+               }
+               tp->snd_wl1 = ti->ti_seq - 1;
+               tp->rcv_up = ti->ti_seq;
+               goto step6;
+       } /* switch tp->t_state */
+       /*
+        * States other than LISTEN or SYN_SENT.
+        * Check that at least some bytes of segment are within
+        * receive window.  If segment begins before rcv_nxt,
+        * drop leading data (and SYN); if nothing left, just ack.
+        */
+       todrop = tp->rcv_nxt - ti->ti_seq;
+       if (todrop > 0) {
+               if (tiflags & TH_SYN) {
+                       tiflags &= ~TH_SYN;
+                       ti->ti_seq++;
+                       if (ti->ti_urp > 1)
+                               ti->ti_urp--;
+                       else
+                               tiflags &= ~TH_URG;
+                       todrop--;
+               }
+               /*
+                * Following if statement from Stevens, vol. 2, p. 960.
+                */
+               if (todrop > ti->ti_len
+                   || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) {
+                       /*
+                        * Any valid FIN must be to the left of the window.
+                        * At this point the FIN must be a duplicate or out
+                        * of sequence; drop it.
+                        */
+                       tiflags &= ~TH_FIN;
+
+                       /*
+                        * Send an ACK to resynchronize and drop any data.
+                        * But keep on processing for RST or ACK.
+                        */
+                       tp->t_flags |= TF_ACKNOW;
+                       todrop = ti->ti_len;
+               }
+               m_adj(m, todrop);
+               ti->ti_seq += todrop;
+               ti->ti_len -= todrop;
+               if (ti->ti_urp > todrop)
+                       ti->ti_urp -= todrop;
+               else {
+                       tiflags &= ~TH_URG;
+                       ti->ti_urp = 0;
+               }
+       }
+       /*
+        * If new data are received on a connection after the
+        * user processes are gone, then RST the other end.
+        */
+       if ((so->so_state & SS_NOFDREF) &&
+           tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) {
+               tp = tcp_close(tp);
+               goto dropwithreset;
+       }
+
+       /*
+        * If segment ends after window, drop trailing data
+        * (and PUSH and FIN); if nothing left, just ACK.
+        */
+       todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd);
+       if (todrop > 0) {
+               if (todrop >= ti->ti_len) {
+                       /*
+                        * If a new connection request is received
+                        * while in TIME_WAIT, drop the old connection
+                        * and start over if the sequence numbers
+                        * are above the previous ones.
+                        */
+                       if (tiflags & TH_SYN &&
+                           tp->t_state == TCPS_TIME_WAIT &&
+                           SEQ_GT(ti->ti_seq, tp->rcv_nxt)) {
+                               iss = tp->rcv_nxt + TCP_ISSINCR;
+                               tp = tcp_close(tp);
+                               goto findso;
+                       }
+                       /*
+                        * If window is closed can only take segments at
+                        * window edge, and have to drop data and PUSH from
+                        * incoming segments.  Continue processing, but
+                        * remember to ack.  Otherwise, drop segment
+                        * and ack.
+                        */
+                       if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) {
+                               tp->t_flags |= TF_ACKNOW;
+                       } else {
+                               goto dropafterack;
+                       }
+               }
+               m_adj(m, -todrop);
+               ti->ti_len -= todrop;
+               tiflags &= ~(TH_PUSH|TH_FIN);
+       }
+
+       /*
+        * If the RST bit is set examine the state:
+        *    SYN_RECEIVED STATE:
+        *      If passive open, return to LISTEN state.
+        *      If active open, inform user that connection was refused.
+        *    ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES:
+        *      Inform user that connection was reset, and close tcb.
+        *    CLOSING, LAST_ACK, TIME_WAIT STATES
+        *      Close the tcb.
+        */
+       if (tiflags&TH_RST) switch (tp->t_state) {
+
+       case TCPS_SYN_RECEIVED:
+       case TCPS_ESTABLISHED:
+       case TCPS_FIN_WAIT_1:
+       case TCPS_FIN_WAIT_2:
+       case TCPS_CLOSE_WAIT:
+               tp->t_state = TCPS_CLOSED;
+                tcp_close(tp);
+               goto drop;
+
+       case TCPS_CLOSING:
+       case TCPS_LAST_ACK:
+       case TCPS_TIME_WAIT:
+                tcp_close(tp);
+               goto drop;
+       }
+
+       /*
+        * If a SYN is in the window, then this is an
+        * error and we send an RST and drop the connection.
+        */
+       if (tiflags & TH_SYN) {
+               tp = tcp_drop(tp,0);
+               goto dropwithreset;
+       }
+
+       /*
+        * If the ACK bit is off we drop the segment and return.
+        */
+       if ((tiflags & TH_ACK) == 0) goto drop;
+
+       /*
+        * Ack processing.
+        */
+       switch (tp->t_state) {
+       /*
+        * In SYN_RECEIVED state if the ack ACKs our SYN then enter
+        * ESTABLISHED state and continue processing, otherwise
+        * send an RST.  una<=ack<=max
+        */
+       case TCPS_SYN_RECEIVED:
+
+               if (SEQ_GT(tp->snd_una, ti->ti_ack) ||
+                   SEQ_GT(ti->ti_ack, tp->snd_max))
+                       goto dropwithreset;
+               tp->t_state = TCPS_ESTABLISHED;
+               /*
+                * The sent SYN is ack'ed with our sequence number +1
+                * The first data byte already in the buffer will get
+                * lost if no correction is made.  This is only needed for
+                * SS_CTL since the buffer is empty otherwise.
+                * tp->snd_una++; or:
+                */
+               tp->snd_una=ti->ti_ack;
+               if (so->so_state & SS_CTL) {
+                 /* So tcp_ctl reports the right state */
+                 ret = tcp_ctl(so);
+                 if (ret == 1) {
+                   soisfconnected(so);
+                   so->so_state &= ~SS_CTL;   /* success XXX */
+                 } else if (ret == 2) {
+                   so->so_state &= SS_PERSISTENT_MASK;
+                   so->so_state |= SS_NOFDREF; /* CTL_CMD */
+                 } else {
+                   needoutput = 1;
+                   tp->t_state = TCPS_FIN_WAIT_1;
+                 }
+               } else {
+                 soisfconnected(so);
+               }
+
+               (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);
+               tp->snd_wl1 = ti->ti_seq - 1;
+               /* Avoid ack processing; snd_una==ti_ack  =>  dup ack */
+               goto synrx_to_est;
+               /* fall into ... */
+
+       /*
+        * In ESTABLISHED state: drop duplicate ACKs; ACK out of range
+        * ACKs.  If the ack is in the range
+        *      tp->snd_una < ti->ti_ack <= tp->snd_max
+        * then advance tp->snd_una to ti->ti_ack and drop
+        * data from the retransmission queue.  If this ACK reflects
+        * more up to date window information we update our window information.
+        */
+       case TCPS_ESTABLISHED:
+       case TCPS_FIN_WAIT_1:
+       case TCPS_FIN_WAIT_2:
+       case TCPS_CLOSE_WAIT:
+       case TCPS_CLOSING:
+       case TCPS_LAST_ACK:
+       case TCPS_TIME_WAIT:
+
+               if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
+                       if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {
+                         DEBUG_MISC(" dup ack  m = %p  so = %p", m, so);
+                               /*
+                                * If we have outstanding data (other than
+                                * a window probe), this is a completely
+                                * duplicate ack (ie, window info didn't
+                                * change), the ack is the biggest we've
+                                * seen and we've seen exactly our rexmt
+                                * threshold of them, assume a packet
+                                * has been dropped and retransmit it.
+                                * Kludge snd_nxt & the congestion
+                                * window so we send only this one
+                                * packet.
+                                *
+                                * We know we're losing at the current
+                                * window size so do congestion avoidance
+                                * (set ssthresh to half the current window
+                                * and pull our congestion window back to
+                                * the new ssthresh).
+                                *
+                                * Dup acks mean that packets have left the
+                                * network (they're now cached at the receiver)
+                                * so bump cwnd by the amount in the receiver
+                                * to keep a constant cwnd packets in the
+                                * network.
+                                */
+                               if (tp->t_timer[TCPT_REXMT] == 0 ||
+                                   ti->ti_ack != tp->snd_una)
+                                       tp->t_dupacks = 0;
+                               else if (++tp->t_dupacks == TCPREXMTTHRESH) {
+                                       tcp_seq onxt = tp->snd_nxt;
+                                       unsigned win =
+                                                MIN(tp->snd_wnd, tp->snd_cwnd) /
+                                                2 / tp->t_maxseg;
+
+                                       if (win < 2)
+                                               win = 2;
+                                       tp->snd_ssthresh = win * tp->t_maxseg;
+                                       tp->t_timer[TCPT_REXMT] = 0;
+                                       tp->t_rtt = 0;
+                                       tp->snd_nxt = ti->ti_ack;
+                                       tp->snd_cwnd = tp->t_maxseg;
+                                       (void) tcp_output(tp);
+                                       tp->snd_cwnd = tp->snd_ssthresh +
+                                              tp->t_maxseg * tp->t_dupacks;
+                                       if (SEQ_GT(onxt, tp->snd_nxt))
+                                               tp->snd_nxt = onxt;
+                                       goto drop;
+                               } else if (tp->t_dupacks > TCPREXMTTHRESH) {
+                                       tp->snd_cwnd += tp->t_maxseg;
+                                       (void) tcp_output(tp);
+                                       goto drop;
+                               }
+                       } else
+                               tp->t_dupacks = 0;
+                       break;
+               }
+       synrx_to_est:
+               /*
+                * If the congestion window was inflated to account
+                * for the other side's cached packets, retract it.
+                */
+               if (tp->t_dupacks > TCPREXMTTHRESH &&
+                   tp->snd_cwnd > tp->snd_ssthresh)
+                       tp->snd_cwnd = tp->snd_ssthresh;
+               tp->t_dupacks = 0;
+               if (SEQ_GT(ti->ti_ack, tp->snd_max)) {
+                       goto dropafterack;
+               }
+               acked = ti->ti_ack - tp->snd_una;
+
+               /*
+                * If transmit timer is running and timed sequence
+                * number was acked, update smoothed round trip time.
+                * Since we now have an rtt measurement, cancel the
+                * timer backoff (cf., Phil Karn's retransmit alg.).
+                * Recompute the initial retransmit timer.
+                */
+               if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq))
+                       tcp_xmit_timer(tp,tp->t_rtt);
+
+               /*
+                * If all outstanding data is acked, stop retransmit
+                * timer and remember to restart (more output or persist).
+                * If there is more data to be acked, restart retransmit
+                * timer, using current (possibly backed-off) value.
+                */
+               if (ti->ti_ack == tp->snd_max) {
+                       tp->t_timer[TCPT_REXMT] = 0;
+                       needoutput = 1;
+               } else if (tp->t_timer[TCPT_PERSIST] == 0)
+                       tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+               /*
+                * When new data is acked, open the congestion window.
+                * If the window gives us less than ssthresh packets
+                * in flight, open exponentially (maxseg per packet).
+                * Otherwise open linearly: maxseg per window
+                * (maxseg^2 / cwnd per packet).
+                */
+               {
+                 register unsigned cw = tp->snd_cwnd;
+                 register unsigned incr = tp->t_maxseg;
+
+                 if (cw > tp->snd_ssthresh)
+                   incr = incr * incr / cw;
+                  tp->snd_cwnd = MIN(cw + incr, TCP_MAXWIN << tp->snd_scale);
+               }
+               if (acked > so->so_snd.sb_cc) {
+                       tp->snd_wnd -= so->so_snd.sb_cc;
+                       sodrop(so, (int)so->so_snd.sb_cc);
+                       ourfinisacked = 1;
+               } else {
+                       sodrop(so, acked);
+                       tp->snd_wnd -= acked;
+                       ourfinisacked = 0;
+               }
+               tp->snd_una = ti->ti_ack;
+               if (SEQ_LT(tp->snd_nxt, tp->snd_una))
+                       tp->snd_nxt = tp->snd_una;
+
+               switch (tp->t_state) {
+
+               /*
+                * In FIN_WAIT_1 STATE in addition to the processing
+                * for the ESTABLISHED state if our FIN is now acknowledged
+                * then enter FIN_WAIT_2.
+                */
+               case TCPS_FIN_WAIT_1:
+                       if (ourfinisacked) {
+                               /*
+                                * If we can't receive any more
+                                * data, then closing user can proceed.
+                                * Starting the timer is contrary to the
+                                * specification, but if we don't get a FIN
+                                * we'll hang forever.
+                                */
+                               if (so->so_state & SS_FCANTRCVMORE) {
+                                       tp->t_timer[TCPT_2MSL] = TCP_MAXIDLE;
+                               }
+                               tp->t_state = TCPS_FIN_WAIT_2;
+                       }
+                       break;
+
+               /*
+                * In CLOSING STATE in addition to the processing for
+                * the ESTABLISHED state if the ACK acknowledges our FIN
+                * then enter the TIME-WAIT state, otherwise ignore
+                * the segment.
+                */
+               case TCPS_CLOSING:
+                       if (ourfinisacked) {
+                               tp->t_state = TCPS_TIME_WAIT;
+                               tcp_canceltimers(tp);
+                               tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+                       }
+                       break;
+
+               /*
+                * In LAST_ACK, we may still be waiting for data to drain
+                * and/or to be acked, as well as for the ack of our FIN.
+                * If our FIN is now acknowledged, delete the TCB,
+                * enter the closed state and return.
+                */
+               case TCPS_LAST_ACK:
+                       if (ourfinisacked) {
+                                tcp_close(tp);
+                               goto drop;
+                       }
+                       break;
+
+               /*
+                * In TIME_WAIT state the only thing that should arrive
+                * is a retransmission of the remote FIN.  Acknowledge
+                * it and restart the finack timer.
+                */
+               case TCPS_TIME_WAIT:
+                       tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+                       goto dropafterack;
+               }
+       } /* switch(tp->t_state) */
+
+step6:
+       /*
+        * Update window information.
+        * Don't look at window if no ACK: TAC's send garbage on first SYN.
+        */
+       if ((tiflags & TH_ACK) &&
+           (SEQ_LT(tp->snd_wl1, ti->ti_seq) ||
+           (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||
+           (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) {
+               tp->snd_wnd = tiwin;
+               tp->snd_wl1 = ti->ti_seq;
+               tp->snd_wl2 = ti->ti_ack;
+               if (tp->snd_wnd > tp->max_sndwnd)
+                       tp->max_sndwnd = tp->snd_wnd;
+               needoutput = 1;
+       }
+
+       /*
+        * Process segments with URG.
+        */
+       if ((tiflags & TH_URG) && ti->ti_urp &&
+           TCPS_HAVERCVDFIN(tp->t_state) == 0) {
+               /*
+                * This is a kludge, but if we receive and accept
+                * random urgent pointers, we'll crash in
+                * soreceive.  It's hard to imagine someone
+                * actually wanting to send this much urgent data.
+                */
+               if (ti->ti_urp + so->so_rcv.sb_cc > so->so_rcv.sb_datalen) {
+                       ti->ti_urp = 0;
+                       tiflags &= ~TH_URG;
+                       goto dodata;
+               }
+               /*
+                * If this segment advances the known urgent pointer,
+                * then mark the data stream.  This should not happen
+                * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since
+                * a FIN has been received from the remote side.
+                * In these states we ignore the URG.
+                *
+                * According to RFC961 (Assigned Protocols),
+                * the urgent pointer points to the last octet
+                * of urgent data.  We continue, however,
+                * to consider it to indicate the first octet
+                * of data past the urgent section as the original
+                * spec states (in one of two places).
+                */
+               if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) {
+                       tp->rcv_up = ti->ti_seq + ti->ti_urp;
+                       so->so_urgc =  so->so_rcv.sb_cc +
+                               (tp->rcv_up - tp->rcv_nxt); /* -1; */
+                       tp->rcv_up = ti->ti_seq + ti->ti_urp;
+
+               }
+       } else
+               /*
+                * If no out of band data is expected,
+                * pull receive urgent pointer along
+                * with the receive window.
+                */
+               if (SEQ_GT(tp->rcv_nxt, tp->rcv_up))
+                       tp->rcv_up = tp->rcv_nxt;
+dodata:
+
+       /*
+        * If this is a small packet, then ACK now - with Nagel
+        *      congestion avoidance sender won't send more until
+        *      he gets an ACK.
+        */
+       if (ti->ti_len && (unsigned)ti->ti_len <= 5 &&
+           ((struct tcpiphdr_2 *)ti)->first_char == (char)27) {
+               tp->t_flags |= TF_ACKNOW;
+       }
+
+       /*
+        * Process the segment text, merging it into the TCP sequencing queue,
+        * and arranging for acknowledgment of receipt if necessary.
+        * This process logically involves adjusting tp->rcv_wnd as data
+        * is presented to the user (this happens in tcp_usrreq.c,
+        * case PRU_RCVD).  If a FIN has already been received on this
+        * connection then we just ignore the text.
+        */
+       if ((ti->ti_len || (tiflags&TH_FIN)) &&
+           TCPS_HAVERCVDFIN(tp->t_state) == 0) {
+               TCP_REASS(tp, ti, m, so, tiflags);
+       } else {
+               m_free(m);
+               tiflags &= ~TH_FIN;
+       }
+
+       /*
+        * If FIN is received ACK the FIN and let the user know
+        * that the connection is closing.
+        */
+       if (tiflags & TH_FIN) {
+               if (TCPS_HAVERCVDFIN(tp->t_state) == 0) {
+                       /*
+                        * If we receive a FIN we can't send more data,
+                        * set it SS_FDRAIN
+                         * Shutdown the socket if there is no rx data in the
+                        * buffer.
+                        * soread() is called on completion of shutdown() and
+                        * will got to TCPS_LAST_ACK, and use tcp_output()
+                        * to send the FIN.
+                        */
+                       sofwdrain(so);
+
+                       tp->t_flags |= TF_ACKNOW;
+                       tp->rcv_nxt++;
+               }
+               switch (tp->t_state) {
+
+               /*
+                * In SYN_RECEIVED and ESTABLISHED STATES
+                * enter the CLOSE_WAIT state.
+                */
+               case TCPS_SYN_RECEIVED:
+               case TCPS_ESTABLISHED:
+                 if(so->so_emu == EMU_CTL)        /* no shutdown on socket */
+                   tp->t_state = TCPS_LAST_ACK;
+                 else
+                   tp->t_state = TCPS_CLOSE_WAIT;
+                 break;
+
+               /*
+                * If still in FIN_WAIT_1 STATE FIN has not been acked so
+                * enter the CLOSING state.
+                */
+               case TCPS_FIN_WAIT_1:
+                       tp->t_state = TCPS_CLOSING;
+                       break;
+
+               /*
+                * In FIN_WAIT_2 state enter the TIME_WAIT state,
+                * starting the time-wait timer, turning off the other
+                * standard timers.
+                */
+               case TCPS_FIN_WAIT_2:
+                       tp->t_state = TCPS_TIME_WAIT;
+                       tcp_canceltimers(tp);
+                       tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+                       break;
+
+               /*
+                * In TIME_WAIT state restart the 2 MSL time_wait timer.
+                */
+               case TCPS_TIME_WAIT:
+                       tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+                       break;
+               }
+       }
+
+       /*
+        * Return any desired output.
+        */
+       if (needoutput || (tp->t_flags & TF_ACKNOW)) {
+               (void) tcp_output(tp);
+       }
+       return;
+
+dropafterack:
+       /*
+        * Generate an ACK dropping incoming segment if it occupies
+        * sequence space, where the ACK reflects our state.
+        */
+       if (tiflags & TH_RST)
+               goto drop;
+       m_free(m);
+       tp->t_flags |= TF_ACKNOW;
+       (void) tcp_output(tp);
+       return;
+
+dropwithreset:
+       /* reuses m if m!=NULL, m_free() unnecessary */
+       if (tiflags & TH_ACK)
+               tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST, af);
+       else {
+               if (tiflags & TH_SYN) ti->ti_len++;
+               tcp_respond(tp, ti, m, ti->ti_seq + ti->ti_len, (tcp_seq) 0,
+                   TH_RST | TH_ACK, af);
+       }
+
+       return;
+
+drop:
+       /*
+        * Drop space held by incoming segment and return.
+        */
+       m_free(m);
+}
+
+static void
+tcp_dooptions(struct tcpcb *tp, uint8_t *cp, int cnt, struct tcpiphdr *ti)
+{
+       uint16_t mss;
+       int opt, optlen;
+
+       DEBUG_CALL("tcp_dooptions");
+       DEBUG_ARG("tp = %p  cnt=%i", tp, cnt);
+
+       for (; cnt > 0; cnt -= optlen, cp += optlen) {
+               opt = cp[0];
+               if (opt == TCPOPT_EOL)
+                       break;
+               if (opt == TCPOPT_NOP)
+                       optlen = 1;
+               else {
+                       optlen = cp[1];
+                       if (optlen <= 0)
+                               break;
+               }
+               switch (opt) {
+
+               default:
+                       continue;
+
+               case TCPOPT_MAXSEG:
+                       if (optlen != TCPOLEN_MAXSEG)
+                               continue;
+                       if (!(ti->ti_flags & TH_SYN))
+                               continue;
+                       memcpy((char *) &mss, (char *) cp + 2, sizeof(mss));
+                       NTOHS(mss);
+                       (void) tcp_mss(tp, mss);        /* sets t_maxseg */
+                       break;
+               }
+       }
+}
+
+/*
+ * Collect new round-trip time estimate
+ * and update averages and current timeout.
+ */
+
+static void
+tcp_xmit_timer(register struct tcpcb *tp, int rtt)
+{
+       register short delta;
+
+       DEBUG_CALL("tcp_xmit_timer");
+       DEBUG_ARG("tp = %p", tp);
+       DEBUG_ARG("rtt = %d", rtt);
+
+       if (tp->t_srtt != 0) {
+               /*
+                * srtt is stored as fixed point with 3 bits after the
+                * binary point (i.e., scaled by 8).  The following magic
+                * is equivalent to the smoothing algorithm in rfc793 with
+                * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed
+                * point).  Adjust rtt to origin 0.
+                */
+               delta = rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT);
+               if ((tp->t_srtt += delta) <= 0)
+                       tp->t_srtt = 1;
+               /*
+                * We accumulate a smoothed rtt variance (actually, a
+                * smoothed mean difference), then set the retransmit
+                * timer to smoothed rtt + 4 times the smoothed variance.
+                * rttvar is stored as fixed point with 2 bits after the
+                * binary point (scaled by 4).  The following is
+                * equivalent to rfc793 smoothing with an alpha of .75
+                * (rttvar = rttvar*3/4 + |delta| / 4).  This replaces
+                * rfc793's wired-in beta.
+                */
+               if (delta < 0)
+                       delta = -delta;
+               delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT);
+               if ((tp->t_rttvar += delta) <= 0)
+                       tp->t_rttvar = 1;
+       } else {
+               /*
+                * No rtt measurement yet - use the unsmoothed rtt.
+                * Set the variance to half the rtt (so our first
+                * retransmit happens at 3*rtt).
+                */
+               tp->t_srtt = rtt << TCP_RTT_SHIFT;
+               tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1);
+       }
+       tp->t_rtt = 0;
+       tp->t_rxtshift = 0;
+
+       /*
+        * the retransmit should happen at rtt + 4 * rttvar.
+        * Because of the way we do the smoothing, srtt and rttvar
+        * will each average +1/2 tick of bias.  When we compute
+        * the retransmit timer, we want 1/2 tick of rounding and
+        * 1 extra tick because of +-1/2 tick uncertainty in the
+        * firing of the timer.  The bias will give us exactly the
+        * 1.5 tick we need.  But, because the bias is
+        * statistical, we have to test that we don't drop below
+        * the minimum feasible timer (which is 2 ticks).
+        */
+       TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp),
+           (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */
+
+       /*
+        * We received an ack for a packet that wasn't retransmitted;
+        * it is probably safe to discard any error indications we've
+        * received recently.  This isn't quite right, but close enough
+        * for now (a route might have failed after we sent a segment,
+        * and the return path might not be symmetrical).
+        */
+       tp->t_softerror = 0;
+}
+
+/*
+ * Determine a reasonable value for maxseg size.
+ * If the route is known, check route for mtu.
+ * If none, use an mss that can be handled on the outgoing
+ * interface without forcing IP to fragment; if bigger than
+ * an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES
+ * to utilize large mbufs.  If no route is found, route has no mtu,
+ * or the destination isn't local, use a default, hopefully conservative
+ * size (usually 512 or the default IP max size, but no more than the mtu
+ * of the interface), as we can't discover anything about intervening
+ * gateways or networks.  We also initialize the congestion/slow start
+ * window to be a single segment if the destination isn't local.
+ * While looking at the routing entry, we also initialize other path-dependent
+ * parameters from pre-set or cached values in the routing entry.
+ */
+
+int
+tcp_mss(struct tcpcb *tp, unsigned offer)
+{
+       struct socket *so = tp->t_socket;
+       int mss;
+
+       DEBUG_CALL("tcp_mss");
+       DEBUG_ARG("tp = %p", tp);
+       DEBUG_ARG("offer = %d", offer);
+
+       switch (so->so_ffamily) {
+       case AF_INET:
+            mss = MIN(IF_MTU, IF_MRU) - sizeof(struct tcphdr)
+                                     - sizeof(struct ip);
+           break;
+       case AF_INET6:
+            mss = MIN(IF_MTU, IF_MRU) - sizeof(struct tcphdr)
+                                     - sizeof(struct ip6);
+           break;
+       default:
+           g_assert_not_reached();
+       }
+
+       if (offer)
+            mss = MIN(mss, offer);
+        mss = MAX(mss, 32);
+       if (mss < tp->t_maxseg || offer != 0)
+          tp->t_maxseg = mss;
+
+       tp->snd_cwnd = mss;
+
+       sbreserve(&so->so_snd, TCP_SNDSPACE + ((TCP_SNDSPACE % mss) ?
+                                               (mss - (TCP_SNDSPACE % mss)) :
+                                               0));
+       sbreserve(&so->so_rcv, TCP_RCVSPACE + ((TCP_RCVSPACE % mss) ?
+                                               (mss - (TCP_RCVSPACE % mss)) :
+                                               0));
+
+       DEBUG_MISC(" returning mss = %d", mss);
+
+       return mss;
+}
diff --git a/slirp/src/tcp_output.c b/slirp/src/tcp_output.c
new file mode 100644 (file)
index 0000000..e9674df
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 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. 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.
+ *
+ *     @(#)tcp_output.c        8.3 (Berkeley) 12/30/93
+ * tcp_output.c,v 1.3 1994/09/15 10:36:55 davidg Exp
+ */
+
+/*
+ * Changes and additions relating to SLiRP
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include "slirp.h"
+
+static const uint8_t  tcp_outflags[TCP_NSTATES] = {
+       TH_RST|TH_ACK, 0,      TH_SYN,        TH_SYN|TH_ACK,
+       TH_ACK,        TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK,
+       TH_FIN|TH_ACK, TH_ACK, TH_ACK,
+};
+
+
+#undef MAX_TCPOPTLEN
+#define MAX_TCPOPTLEN  32      /* max # bytes that go in options */
+
+/*
+ * Tcp output routine: figure out what should be sent and send it.
+ */
+int
+tcp_output(struct tcpcb *tp)
+{
+       register struct socket *so = tp->t_socket;
+       register long len, win;
+       int off, flags, error;
+       register struct mbuf *m;
+       register struct tcpiphdr *ti, tcpiph_save;
+       struct ip *ip;
+       struct ip6 *ip6;
+       uint8_t opt[MAX_TCPOPTLEN];
+       unsigned optlen, hdrlen;
+       int idle, sendalot;
+
+       DEBUG_CALL("tcp_output");
+       DEBUG_ARG("tp = %p", tp);
+
+       /*
+        * Determine length of data that should be transmitted,
+        * and flags that will be used.
+        * If there is some data or critical controls (SYN, RST)
+        * to send, then transmit; otherwise, investigate further.
+        */
+       idle = (tp->snd_max == tp->snd_una);
+       if (idle && tp->t_idle >= tp->t_rxtcur)
+               /*
+                * We have been idle for "a while" and no acks are
+                * expected to clock out any data we send --
+                * slow start to get ack "clock" running again.
+                */
+               tp->snd_cwnd = tp->t_maxseg;
+again:
+       sendalot = 0;
+       off = tp->snd_nxt - tp->snd_una;
+        win = MIN(tp->snd_wnd, tp->snd_cwnd);
+
+       flags = tcp_outflags[tp->t_state];
+
+       DEBUG_MISC(" --- tcp_output flags = 0x%x", flags);
+
+       /*
+        * If in persist timeout with window of 0, send 1 byte.
+        * Otherwise, if window is small but nonzero
+        * and timer expired, we will send what we can
+        * and go to transmit state.
+        */
+       if (tp->t_force) {
+               if (win == 0) {
+                       /*
+                        * If we still have some data to send, then
+                        * clear the FIN bit.  Usually this would
+                        * happen below when it realizes that we
+                        * aren't sending all the data.  However,
+                        * if we have exactly 1 byte of unset data,
+                        * then it won't clear the FIN bit below,
+                        * and if we are in persist state, we wind
+                        * up sending the packet without recording
+                        * that we sent the FIN bit.
+                        *
+                        * We can't just blindly clear the FIN bit,
+                        * because if we don't have any more data
+                        * to send then the probe will be the FIN
+                        * itself.
+                        */
+                       if (off < so->so_snd.sb_cc)
+                               flags &= ~TH_FIN;
+                       win = 1;
+               } else {
+                       tp->t_timer[TCPT_PERSIST] = 0;
+                       tp->t_rxtshift = 0;
+               }
+       }
+
+        len = MIN(so->so_snd.sb_cc, win) - off;
+
+       if (len < 0) {
+               /*
+                * If FIN has been sent but not acked,
+                * but we haven't been called to retransmit,
+                * len will be -1.  Otherwise, window shrank
+                * after we sent into it.  If window shrank to 0,
+                * cancel pending retransmit and pull snd_nxt
+                * back to (closed) window.  We will enter persist
+                * state below.  If the window didn't close completely,
+                * just wait for an ACK.
+                */
+               len = 0;
+               if (win == 0) {
+                       tp->t_timer[TCPT_REXMT] = 0;
+                       tp->snd_nxt = tp->snd_una;
+               }
+       }
+
+       if (len > tp->t_maxseg) {
+               len = tp->t_maxseg;
+               sendalot = 1;
+       }
+       if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
+               flags &= ~TH_FIN;
+
+       win = sbspace(&so->so_rcv);
+
+       /*
+        * Sender silly window avoidance.  If connection is idle
+        * and can send all data, a maximum segment,
+        * at least a maximum default-size segment do it,
+        * or are forced, do it; otherwise don't bother.
+        * If peer's buffer is tiny, then send
+        * when window is at least half open.
+        * If retransmitting (possibly after persist timer forced us
+        * to send into a small window), then must resend.
+        */
+       if (len) {
+               if (len == tp->t_maxseg)
+                       goto send;
+               if ((1 || idle || tp->t_flags & TF_NODELAY) &&
+                   len + off >= so->so_snd.sb_cc)
+                       goto send;
+               if (tp->t_force)
+                       goto send;
+               if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0)
+                       goto send;
+               if (SEQ_LT(tp->snd_nxt, tp->snd_max))
+                       goto send;
+       }
+
+       /*
+        * Compare available window to amount of window
+        * known to peer (as advertised window less
+        * next expected input).  If the difference is at least two
+        * max size segments, or at least 50% of the maximum possible
+        * window, then want to send a window update to peer.
+        */
+       if (win > 0) {
+               /*
+                * "adv" is the amount we can increase the window,
+                * taking into account that we are limited by
+                * TCP_MAXWIN << tp->rcv_scale.
+                */
+                long adv = MIN(win, (long)TCP_MAXWIN << tp->rcv_scale) -
+                       (tp->rcv_adv - tp->rcv_nxt);
+
+               if (adv >= (long) (2 * tp->t_maxseg))
+                       goto send;
+               if (2 * adv >= (long) so->so_rcv.sb_datalen)
+                       goto send;
+       }
+
+       /*
+        * Send if we owe peer an ACK.
+        */
+       if (tp->t_flags & TF_ACKNOW)
+               goto send;
+       if (flags & (TH_SYN|TH_RST))
+               goto send;
+       if (SEQ_GT(tp->snd_up, tp->snd_una))
+               goto send;
+       /*
+        * If our state indicates that FIN should be sent
+        * and we have not yet done so, or we're retransmitting the FIN,
+        * then we need to send.
+        */
+       if (flags & TH_FIN &&
+           ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una))
+               goto send;
+
+       /*
+        * TCP window updates are not reliable, rather a polling protocol
+        * using ``persist'' packets is used to insure receipt of window
+        * updates.  The three ``states'' for the output side are:
+        *      idle                    not doing retransmits or persists
+        *      persisting              to move a small or zero window
+        *      (re)transmitting        and thereby not persisting
+        *
+        * tp->t_timer[TCPT_PERSIST]
+        *      is set when we are in persist state.
+        * tp->t_force
+        *      is set when we are called to send a persist packet.
+        * tp->t_timer[TCPT_REXMT]
+        *      is set when we are retransmitting
+        * The output side is idle when both timers are zero.
+        *
+        * If send window is too small, there is data to transmit, and no
+        * retransmit or persist is pending, then go to persist state.
+        * If nothing happens soon, send when timer expires:
+        * if window is nonzero, transmit what we can,
+        * otherwise force out a byte.
+        */
+       if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 &&
+           tp->t_timer[TCPT_PERSIST] == 0) {
+               tp->t_rxtshift = 0;
+               tcp_setpersist(tp);
+       }
+
+       /*
+        * No reason to send a segment, just return.
+        */
+       return (0);
+
+send:
+       /*
+        * Before ESTABLISHED, force sending of initial options
+        * unless TCP set not to do any options.
+        * NOTE: we assume that the IP/TCP header plus TCP options
+        * always fit in a single mbuf, leaving room for a maximum
+        * link header, i.e.
+        *      max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN
+        */
+       optlen = 0;
+       hdrlen = sizeof (struct tcpiphdr);
+       if (flags & TH_SYN) {
+               tp->snd_nxt = tp->iss;
+               if ((tp->t_flags & TF_NOOPT) == 0) {
+                       uint16_t mss;
+
+                       opt[0] = TCPOPT_MAXSEG;
+                       opt[1] = 4;
+                       mss = htons((uint16_t) tcp_mss(tp, 0));
+                       memcpy((char *)(opt + 2), (char *)&mss, sizeof(mss));
+                       optlen = 4;
+               }
+       }
+
+       hdrlen += optlen;
+
+       /*
+        * Adjust data length if insertion of options will
+        * bump the packet length beyond the t_maxseg length.
+        */
+        if (len > tp->t_maxseg - optlen) {
+               len = tp->t_maxseg - optlen;
+               sendalot = 1;
+        }
+
+       /*
+        * Grab a header mbuf, attaching a copy of data to
+        * be transmitted, and initialize the header from
+        * the template for sends on this connection.
+        */
+       if (len) {
+               m = m_get(so->slirp);
+               if (m == NULL) {
+                       error = 1;
+                       goto out;
+               }
+               m->m_data += IF_MAXLINKHDR;
+               m->m_len = hdrlen;
+
+               sbcopy(&so->so_snd, off, (int) len, mtod(m, char *) + hdrlen);
+               m->m_len += len;
+
+               /*
+                * If we're sending everything we've got, set PUSH.
+                * (This will keep happy those implementations which only
+                * give data to the user when a buffer fills or
+                * a PUSH comes in.)
+                */
+               if (off + len == so->so_snd.sb_cc)
+                       flags |= TH_PUSH;
+       } else {
+               m = m_get(so->slirp);
+               if (m == NULL) {
+                       error = 1;
+                       goto out;
+               }
+               m->m_data += IF_MAXLINKHDR;
+               m->m_len = hdrlen;
+       }
+
+       ti = mtod(m, struct tcpiphdr *);
+
+       memcpy((char *)ti, &tp->t_template, sizeof (struct tcpiphdr));
+
+       /*
+        * Fill in fields, remembering maximum advertised
+        * window for use in delaying messages about window sizes.
+        * If resending a FIN, be sure not to use a new sequence number.
+        */
+       if (flags & TH_FIN && tp->t_flags & TF_SENTFIN &&
+           tp->snd_nxt == tp->snd_max)
+               tp->snd_nxt--;
+       /*
+        * If we are doing retransmissions, then snd_nxt will
+        * not reflect the first unsent octet.  For ACK only
+        * packets, we do not want the sequence number of the
+        * retransmitted packet, we want the sequence number
+        * of the next unsent octet.  So, if there is no data
+        * (and no SYN or FIN), use snd_max instead of snd_nxt
+        * when filling in ti_seq.  But if we are in persist
+        * state, snd_max might reflect one byte beyond the
+        * right edge of the window, so use snd_nxt in that
+        * case, since we know we aren't doing a retransmission.
+        * (retransmit and persist are mutually exclusive...)
+        */
+       if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST])
+               ti->ti_seq = htonl(tp->snd_nxt);
+       else
+               ti->ti_seq = htonl(tp->snd_max);
+       ti->ti_ack = htonl(tp->rcv_nxt);
+       if (optlen) {
+               memcpy((char *)(ti + 1), (char *)opt, optlen);
+               ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2;
+       }
+       ti->ti_flags = flags;
+       /*
+        * Calculate receive window.  Don't shrink window,
+        * but avoid silly window syndrome.
+        */
+       if (win < (long)(so->so_rcv.sb_datalen / 4) && win < (long)tp->t_maxseg)
+               win = 0;
+       if (win > (long)TCP_MAXWIN << tp->rcv_scale)
+               win = (long)TCP_MAXWIN << tp->rcv_scale;
+       if (win < (long)(tp->rcv_adv - tp->rcv_nxt))
+               win = (long)(tp->rcv_adv - tp->rcv_nxt);
+       ti->ti_win = htons((uint16_t) (win>>tp->rcv_scale));
+
+       if (SEQ_GT(tp->snd_up, tp->snd_una)) {
+               ti->ti_urp = htons((uint16_t)(tp->snd_up - ntohl(ti->ti_seq)));
+               ti->ti_flags |= TH_URG;
+       } else
+               /*
+                * If no urgent pointer to send, then we pull
+                * the urgent pointer to the left edge of the send window
+                * so that it doesn't drift into the send window on sequence
+                * number wraparound.
+                */
+               tp->snd_up = tp->snd_una;               /* drag it along */
+
+       /*
+        * Put TCP length in extended header, and then
+        * checksum extended header and data.
+        */
+       if (len + optlen)
+               ti->ti_len = htons((uint16_t)(sizeof (struct tcphdr) +
+                   optlen + len));
+       ti->ti_sum = cksum(m, (int)(hdrlen + len));
+
+       /*
+        * In transmit state, time the transmission and arrange for
+        * the retransmit.  In persist state, just set snd_max.
+        */
+       if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) {
+               tcp_seq startseq = tp->snd_nxt;
+
+               /*
+                * Advance snd_nxt over sequence space of this segment.
+                */
+               if (flags & (TH_SYN|TH_FIN)) {
+                       if (flags & TH_SYN)
+                               tp->snd_nxt++;
+                       if (flags & TH_FIN) {
+                               tp->snd_nxt++;
+                               tp->t_flags |= TF_SENTFIN;
+                       }
+               }
+               tp->snd_nxt += len;
+               if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
+                       tp->snd_max = tp->snd_nxt;
+                       /*
+                        * Time this transmission if not a retransmission and
+                        * not currently timing anything.
+                        */
+                       if (tp->t_rtt == 0) {
+                               tp->t_rtt = 1;
+                               tp->t_rtseq = startseq;
+                       }
+               }
+
+               /*
+                * Set retransmit timer if not currently set,
+                * and not doing an ack or a keep-alive probe.
+                * Initial value for retransmit timer is smoothed
+                * round-trip time + 2 * round-trip time variance.
+                * Initialize shift counter which is used for backoff
+                * of retransmit time.
+                */
+               if (tp->t_timer[TCPT_REXMT] == 0 &&
+                   tp->snd_nxt != tp->snd_una) {
+                       tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+                       if (tp->t_timer[TCPT_PERSIST]) {
+                               tp->t_timer[TCPT_PERSIST] = 0;
+                               tp->t_rxtshift = 0;
+                       }
+               }
+       } else
+               if (SEQ_GT(tp->snd_nxt + len, tp->snd_max))
+                       tp->snd_max = tp->snd_nxt + len;
+
+       /*
+        * Fill in IP length and desired time to live and
+        * send to IP level.  There should be a better way
+        * to handle ttl and tos; we could keep them in
+        * the template, but need a way to checksum without them.
+        */
+       m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */
+       tcpiph_save = *mtod(m, struct tcpiphdr *);
+
+       switch (so->so_ffamily) {
+       case AF_INET:
+           m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+                                                - sizeof(struct ip);
+           m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+                                                - sizeof(struct ip);
+           ip = mtod(m, struct ip *);
+
+           ip->ip_len = m->m_len;
+           ip->ip_dst = tcpiph_save.ti_dst;
+           ip->ip_src = tcpiph_save.ti_src;
+           ip->ip_p = tcpiph_save.ti_pr;
+
+           ip->ip_ttl = IPDEFTTL;
+           ip->ip_tos = so->so_iptos;
+           error = ip_output(so, m);
+           break;
+
+       case AF_INET6:
+           m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+                                                - sizeof(struct ip6);
+           m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+                                                - sizeof(struct ip6);
+           ip6 = mtod(m, struct ip6 *);
+
+           ip6->ip_pl = tcpiph_save.ti_len;
+           ip6->ip_dst = tcpiph_save.ti_dst6;
+           ip6->ip_src = tcpiph_save.ti_src6;
+           ip6->ip_nh = tcpiph_save.ti_nh6;
+
+           error = ip6_output(so, m, 0);
+           break;
+
+       default:
+           g_assert_not_reached();
+       }
+
+       if (error) {
+out:
+               return (error);
+       }
+
+       /*
+        * Data sent (as far as we can tell).
+        * If this advertises a larger window than any other segment,
+        * then remember the size of the advertised window.
+        * Any pending ACK has now been sent.
+        */
+       if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))
+               tp->rcv_adv = tp->rcv_nxt + win;
+       tp->last_ack_sent = tp->rcv_nxt;
+       tp->t_flags &= ~(TF_ACKNOW|TF_DELACK);
+       if (sendalot)
+               goto again;
+
+       return (0);
+}
+
+void
+tcp_setpersist(struct tcpcb *tp)
+{
+    int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1;
+
+       /*
+        * Start/restart persistence timer.
+        */
+       TCPT_RANGESET(tp->t_timer[TCPT_PERSIST],
+           t * tcp_backoff[tp->t_rxtshift],
+           TCPTV_PERSMIN, TCPTV_PERSMAX);
+       if (tp->t_rxtshift < TCP_MAXRXTSHIFT)
+               tp->t_rxtshift++;
+}
diff --git a/slirp/src/tcp_subr.c b/slirp/src/tcp_subr.c
new file mode 100644 (file)
index 0000000..1db59ca
--- /dev/null
@@ -0,0 +1,989 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 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. 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.
+ *
+ *     @(#)tcp_subr.c  8.1 (Berkeley) 6/10/93
+ * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp
+ */
+
+/*
+ * Changes and additions relating to SLiRP
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include "slirp.h"
+
+/* patchable/settable parameters for tcp */
+/* Don't do rfc1323 performance enhancements */
+#define TCP_DO_RFC1323 0
+
+/*
+ * Tcp initialization
+ */
+void
+tcp_init(Slirp *slirp)
+{
+    slirp->tcp_iss = 1;                /* wrong */
+    slirp->tcb.so_next = slirp->tcb.so_prev = &slirp->tcb;
+    slirp->tcp_last_so = &slirp->tcb;
+}
+
+void tcp_cleanup(Slirp *slirp)
+{
+    while (slirp->tcb.so_next != &slirp->tcb) {
+        tcp_close(sototcpcb(slirp->tcb.so_next));
+    }
+}
+
+/*
+ * Create template to be used to send tcp packets on a connection.
+ * Call after host entry created, fills
+ * in a skeletal tcp/ip header, minimizing the amount of work
+ * necessary when the connection is used.
+ */
+void
+tcp_template(struct tcpcb *tp)
+{
+       struct socket *so = tp->t_socket;
+       register struct tcpiphdr *n = &tp->t_template;
+
+       n->ti_mbuf = NULL;
+       memset(&n->ti, 0, sizeof(n->ti));
+       n->ti_x0 = 0;
+       switch (so->so_ffamily) {
+       case AF_INET:
+           n->ti_pr = IPPROTO_TCP;
+           n->ti_len = htons(sizeof(struct tcphdr));
+           n->ti_src = so->so_faddr;
+           n->ti_dst = so->so_laddr;
+           n->ti_sport = so->so_fport;
+           n->ti_dport = so->so_lport;
+           break;
+
+       case AF_INET6:
+           n->ti_nh6 = IPPROTO_TCP;
+           n->ti_len = htons(sizeof(struct tcphdr));
+           n->ti_src6 = so->so_faddr6;
+           n->ti_dst6 = so->so_laddr6;
+           n->ti_sport = so->so_fport6;
+           n->ti_dport = so->so_lport6;
+           break;
+
+       default:
+           g_assert_not_reached();
+       }
+
+       n->ti_seq = 0;
+       n->ti_ack = 0;
+       n->ti_x2 = 0;
+       n->ti_off = 5;
+       n->ti_flags = 0;
+       n->ti_win = 0;
+       n->ti_sum = 0;
+       n->ti_urp = 0;
+}
+
+/*
+ * Send a single message to the TCP at address specified by
+ * the given TCP/IP header.  If m == 0, then we make a copy
+ * of the tcpiphdr at ti and send directly to the addressed host.
+ * This is used to force keep alive messages out using the TCP
+ * template for a connection tp->t_template.  If flags are given
+ * then we send a message back to the TCP which originated the
+ * segment ti, and discard the mbuf containing it and any other
+ * attached mbufs.
+ *
+ * In any case the ack and sequence number of the transmitted
+ * segment are as specified by the parameters.
+ */
+void
+tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
+            tcp_seq ack, tcp_seq seq, int flags, unsigned short af)
+{
+       register int tlen;
+       int win = 0;
+
+       DEBUG_CALL("tcp_respond");
+       DEBUG_ARG("tp = %p", tp);
+       DEBUG_ARG("ti = %p", ti);
+       DEBUG_ARG("m = %p", m);
+       DEBUG_ARG("ack = %u", ack);
+       DEBUG_ARG("seq = %u", seq);
+       DEBUG_ARG("flags = %x", flags);
+
+       if (tp)
+               win = sbspace(&tp->t_socket->so_rcv);
+        if (m == NULL) {
+               if (!tp || (m = m_get(tp->t_socket->slirp)) == NULL)
+                       return;
+               tlen = 0;
+               m->m_data += IF_MAXLINKHDR;
+               *mtod(m, struct tcpiphdr *) = *ti;
+               ti = mtod(m, struct tcpiphdr *);
+               switch (af) {
+               case AF_INET:
+                   ti->ti.ti_i4.ih_x1 = 0;
+                   break;
+               case AF_INET6:
+                   ti->ti.ti_i6.ih_x1 = 0;
+                   break;
+               default:
+                   g_assert_not_reached();
+               }
+               flags = TH_ACK;
+       } else {
+               /*
+                * ti points into m so the next line is just making
+                * the mbuf point to ti
+                */
+               m->m_data = (char *)ti;
+
+               m->m_len = sizeof (struct tcpiphdr);
+               tlen = 0;
+#define xchg(a,b,type) { type t; t=a; a=b; b=t; }
+               switch (af) {
+               case AF_INET:
+                   xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32_t);
+                   xchg(ti->ti_dport, ti->ti_sport, uint16_t);
+                   break;
+               case AF_INET6:
+                   xchg(ti->ti_dst6, ti->ti_src6, struct in6_addr);
+                   xchg(ti->ti_dport, ti->ti_sport, uint16_t);
+                   break;
+               default:
+                   g_assert_not_reached();
+               }
+#undef xchg
+       }
+       ti->ti_len = htons((uint16_t)(sizeof (struct tcphdr) + tlen));
+       tlen += sizeof (struct tcpiphdr);
+       m->m_len = tlen;
+
+       ti->ti_mbuf = NULL;
+       ti->ti_x0 = 0;
+       ti->ti_seq = htonl(seq);
+       ti->ti_ack = htonl(ack);
+       ti->ti_x2 = 0;
+       ti->ti_off = sizeof (struct tcphdr) >> 2;
+       ti->ti_flags = flags;
+       if (tp)
+               ti->ti_win = htons((uint16_t) (win >> tp->rcv_scale));
+       else
+               ti->ti_win = htons((uint16_t)win);
+       ti->ti_urp = 0;
+       ti->ti_sum = 0;
+       ti->ti_sum = cksum(m, tlen);
+
+       struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
+       struct ip *ip;
+       struct ip6 *ip6;
+
+       switch (af) {
+       case AF_INET:
+           m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+                                                - sizeof(struct ip);
+           m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+                                                - sizeof(struct ip);
+           ip = mtod(m, struct ip *);
+           ip->ip_len = m->m_len;
+           ip->ip_dst = tcpiph_save.ti_dst;
+           ip->ip_src = tcpiph_save.ti_src;
+           ip->ip_p = tcpiph_save.ti_pr;
+
+           if (flags & TH_RST) {
+               ip->ip_ttl = MAXTTL;
+           } else {
+               ip->ip_ttl = IPDEFTTL;
+           }
+
+           ip_output(NULL, m);
+           break;
+
+       case AF_INET6:
+           m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+                                                - sizeof(struct ip6);
+           m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+                                                - sizeof(struct ip6);
+           ip6 = mtod(m, struct ip6 *);
+           ip6->ip_pl = tcpiph_save.ti_len;
+           ip6->ip_dst = tcpiph_save.ti_dst6;
+           ip6->ip_src = tcpiph_save.ti_src6;
+           ip6->ip_nh = tcpiph_save.ti_nh6;
+
+           ip6_output(NULL, m, 0);
+           break;
+
+       default:
+           g_assert_not_reached();
+       }
+}
+
+/*
+ * Create a new TCP control block, making an
+ * empty reassembly queue and hooking it to the argument
+ * protocol control block.
+ */
+struct tcpcb *
+tcp_newtcpcb(struct socket *so)
+{
+       register struct tcpcb *tp;
+
+       tp = (struct tcpcb *)malloc(sizeof(*tp));
+       if (tp == NULL)
+               return ((struct tcpcb *)0);
+
+       memset((char *) tp, 0, sizeof(struct tcpcb));
+       tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp;
+       tp->t_maxseg = (so->so_ffamily == AF_INET) ? TCP_MSS : TCP6_MSS;
+
+       tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
+       tp->t_socket = so;
+
+       /*
+        * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
+        * rtt estimate.  Set rttvar so that srtt + 2 * rttvar gives
+        * reasonable initial retransmit time.
+        */
+       tp->t_srtt = TCPTV_SRTTBASE;
+       tp->t_rttvar = TCPTV_SRTTDFLT << 2;
+       tp->t_rttmin = TCPTV_MIN;
+
+       TCPT_RANGESET(tp->t_rxtcur,
+           ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
+           TCPTV_MIN, TCPTV_REXMTMAX);
+
+       tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
+       tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
+       tp->t_state = TCPS_CLOSED;
+
+       so->so_tcpcb = tp;
+
+       return (tp);
+}
+
+/*
+ * Drop a TCP connection, reporting
+ * the specified error.  If connection is synchronized,
+ * then send a RST to peer.
+ */
+struct tcpcb *tcp_drop(struct tcpcb *tp, int err)
+{
+       DEBUG_CALL("tcp_drop");
+       DEBUG_ARG("tp = %p", tp);
+       DEBUG_ARG("errno = %d", errno);
+
+       if (TCPS_HAVERCVDSYN(tp->t_state)) {
+               tp->t_state = TCPS_CLOSED;
+               (void) tcp_output(tp);
+       }
+       return (tcp_close(tp));
+}
+
+/*
+ * Close a TCP control block:
+ *     discard all space held by the tcp
+ *     discard internet protocol block
+ *     wake up any sleepers
+ */
+struct tcpcb *
+tcp_close(struct tcpcb *tp)
+{
+       register struct tcpiphdr *t;
+       struct socket *so = tp->t_socket;
+       Slirp *slirp = so->slirp;
+       register struct mbuf *m;
+
+       DEBUG_CALL("tcp_close");
+       DEBUG_ARG("tp = %p", tp);
+
+       /* free the reassembly queue, if any */
+       t = tcpfrag_list_first(tp);
+       while (!tcpfrag_list_end(t, tp)) {
+               t = tcpiphdr_next(t);
+               m = tcpiphdr_prev(t)->ti_mbuf;
+               remque(tcpiphdr2qlink(tcpiphdr_prev(t)));
+               m_free(m);
+       }
+       free(tp);
+        so->so_tcpcb = NULL;
+       /* clobber input socket cache if we're closing the cached connection */
+       if (so == slirp->tcp_last_so)
+               slirp->tcp_last_so = &slirp->tcb;
+       so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
+       closesocket(so->s);
+       sbfree(&so->so_rcv);
+       sbfree(&so->so_snd);
+       sofree(so);
+       return ((struct tcpcb *)0);
+}
+
+/*
+ * TCP protocol interface to socket abstraction.
+ */
+
+/*
+ * User issued close, and wish to trail through shutdown states:
+ * if never received SYN, just forget it.  If got a SYN from peer,
+ * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
+ * If already got a FIN from peer, then almost done; go to LAST_ACK
+ * state.  In all other cases, have already sent FIN to peer (e.g.
+ * after PRU_SHUTDOWN), and just have to play tedious game waiting
+ * for peer to send FIN or not respond to keep-alives, etc.
+ * We can let the user exit from the close as soon as the FIN is acked.
+ */
+void
+tcp_sockclosed(struct tcpcb *tp)
+{
+
+       DEBUG_CALL("tcp_sockclosed");
+       DEBUG_ARG("tp = %p", tp);
+
+       if (!tp) {
+               return;
+       }
+
+       switch (tp->t_state) {
+
+       case TCPS_CLOSED:
+       case TCPS_LISTEN:
+       case TCPS_SYN_SENT:
+               tp->t_state = TCPS_CLOSED;
+               tp = tcp_close(tp);
+               break;
+
+       case TCPS_SYN_RECEIVED:
+       case TCPS_ESTABLISHED:
+               tp->t_state = TCPS_FIN_WAIT_1;
+               break;
+
+       case TCPS_CLOSE_WAIT:
+               tp->t_state = TCPS_LAST_ACK;
+               break;
+       }
+       tcp_output(tp);
+}
+
+/*
+ * Connect to a host on the Internet
+ * Called by tcp_input
+ * Only do a connect, the tcp fields will be set in tcp_input
+ * return 0 if there's a result of the connect,
+ * else return -1 means we're still connecting
+ * The return value is almost always -1 since the socket is
+ * nonblocking.  Connect returns after the SYN is sent, and does
+ * not wait for ACK+SYN.
+ */
+int tcp_fconnect(struct socket *so, unsigned short af)
+{
+  int ret=0;
+
+  DEBUG_CALL("tcp_fconnect");
+  DEBUG_ARG("so = %p", so);
+
+  ret = so->s = slirp_socket(af, SOCK_STREAM, 0);
+  if (ret >= 0) {
+    int opt, s=so->s;
+    struct sockaddr_storage addr;
+
+    slirp_set_nonblock(s);
+    so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
+    slirp_socket_set_fast_reuse(s);
+    opt = 1;
+    setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
+    opt = 1;
+    setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
+
+    addr = so->fhost.ss;
+    DEBUG_CALL(" connect()ing");
+    sotranslate_out(so, &addr);
+
+    /* We don't care what port we get */
+    ret = connect(s, (struct sockaddr *)&addr, sockaddr_size(&addr));
+
+    /*
+     * If it's not in progress, it failed, so we just return 0,
+     * without clearing SS_NOFDREF
+     */
+    soisfconnecting(so);
+  }
+
+  return(ret);
+}
+
+/*
+ * Accept the socket and connect to the local-host
+ *
+ * We have a problem. The correct thing to do would be
+ * to first connect to the local-host, and only if the
+ * connection is accepted, then do an accept() here.
+ * But, a) we need to know who's trying to connect
+ * to the socket to be able to SYN the local-host, and
+ * b) we are already connected to the foreign host by
+ * the time it gets to accept(), so... We simply accept
+ * here and SYN the local-host.
+ */
+void tcp_connect(struct socket *inso)
+{
+    Slirp *slirp = inso->slirp;
+    struct socket *so;
+    struct sockaddr_storage addr;
+    socklen_t addrlen = sizeof(struct sockaddr_storage);
+    struct tcpcb *tp;
+    int s, opt;
+
+    DEBUG_CALL("tcp_connect");
+    DEBUG_ARG("inso = %p", inso);
+
+    /*
+     * If it's an SS_ACCEPTONCE socket, no need to socreate()
+     * another socket, just use the accept() socket.
+     */
+    if (inso->so_state & SS_FACCEPTONCE) {
+        /* FACCEPTONCE already have a tcpcb */
+        so = inso;
+    } else {
+        so = socreate(slirp);
+        if (tcp_attach(so) < 0) {
+            g_free(so); /* NOT sofree */
+            return;
+        }
+        so->lhost = inso->lhost;
+        so->so_ffamily = inso->so_ffamily;
+    }
+
+    tcp_mss(sototcpcb(so), 0);
+
+    s = accept(inso->s, (struct sockaddr *)&addr, &addrlen);
+    if (s < 0) {
+        tcp_close(sototcpcb(so)); /* This will sofree() as well */
+        return;
+    }
+    slirp_set_nonblock(s);
+    so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
+    slirp_socket_set_fast_reuse(s);
+    opt = 1;
+    setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
+    slirp_socket_set_nodelay(s);
+
+    so->fhost.ss = addr;
+    sotranslate_accept(so);
+
+    /* Close the accept() socket, set right state */
+    if (inso->so_state & SS_FACCEPTONCE) {
+        /* If we only accept once, close the accept() socket */
+        so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
+        closesocket(so->s);
+
+        /* Don't select it yet, even though we have an FD */
+        /* if it's not FACCEPTONCE, it's already NOFDREF */
+        so->so_state = SS_NOFDREF;
+    }
+    so->s = s;
+    so->so_state |= SS_INCOMING;
+
+    so->so_iptos = tcp_tos(so);
+    tp = sototcpcb(so);
+
+    tcp_template(tp);
+
+    tp->t_state = TCPS_SYN_SENT;
+    tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
+    tp->iss = slirp->tcp_iss;
+    slirp->tcp_iss += TCP_ISSINCR/2;
+    tcp_sendseqinit(tp);
+    tcp_output(tp);
+}
+
+/*
+ * Attach a TCPCB to a socket.
+ */
+int
+tcp_attach(struct socket *so)
+{
+       if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL)
+          return -1;
+
+       insque(so, &so->slirp->tcb);
+
+       return 0;
+}
+
+/*
+ * Set the socket's type of service field
+ */
+static const struct tos_t tcptos[] = {
+         {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */
+         {21, 21, IPTOS_LOWDELAY,  EMU_FTP},   /* ftp control */
+         {0, 23, IPTOS_LOWDELAY, 0},   /* telnet */
+         {0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */
+         {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT},   /* rlogin */
+         {0, 544, IPTOS_LOWDELAY, EMU_KSH},            /* kshell */
+         {0, 543, IPTOS_LOWDELAY, 0},  /* klogin */
+         {0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */
+         {0, 6668, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC undernet */
+         {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */
+         {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */
+         {0, 0, 0, 0}
+};
+
+static struct emu_t *tcpemu = NULL;
+
+/*
+ * Return TOS according to the above table
+ */
+uint8_t
+tcp_tos(struct socket *so)
+{
+       int i = 0;
+       struct emu_t *emup;
+
+       while(tcptos[i].tos) {
+               if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) ||
+                   (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) {
+                       so->so_emu = tcptos[i].emu;
+                       return tcptos[i].tos;
+               }
+               i++;
+       }
+
+       /* Nope, lets see if there's a user-added one */
+       for (emup = tcpemu; emup; emup = emup->next) {
+               if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) ||
+                   (emup->lport && (ntohs(so->so_lport) == emup->lport))) {
+                       so->so_emu = emup->emu;
+                       return emup->tos;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Emulate programs that try and connect to us
+ * This includes ftp (the data connection is
+ * initiated by the server) and IRC (DCC CHAT and
+ * DCC SEND) for now
+ *
+ * NOTE: It's possible to crash SLiRP by sending it
+ * unstandard strings to emulate... if this is a problem,
+ * more checks are needed here
+ *
+ * XXX Assumes the whole command came in one packet
+ *
+ * XXX Some ftp clients will have their TOS set to
+ * LOWDELAY and so Nagel will kick in.  Because of this,
+ * we'll get the first letter, followed by the rest, so
+ * we simply scan for ORT instead of PORT...
+ * DCC doesn't have this problem because there's other stuff
+ * in the packet before the DCC command.
+ *
+ * Return 1 if the mbuf m is still valid and should be
+ * sbappend()ed
+ *
+ * NOTE: if you return 0 you MUST m_free() the mbuf!
+ */
+int
+tcp_emu(struct socket *so, struct mbuf *m)
+{
+       Slirp *slirp = so->slirp;
+       unsigned n1, n2, n3, n4, n5, n6;
+        char buff[257];
+       uint32_t laddr;
+       unsigned lport;
+       char *bptr;
+
+       DEBUG_CALL("tcp_emu");
+       DEBUG_ARG("so = %p", so);
+       DEBUG_ARG("m = %p", m);
+
+       switch(so->so_emu) {
+               int x, i;
+
+        /* TODO: IPv6 */
+        case EMU_IDENT:
+               /*
+                * Identification protocol as per rfc-1413
+                */
+
+               {
+                       struct socket *tmpso;
+                       struct sockaddr_in addr;
+                       socklen_t addrlen = sizeof(struct sockaddr_in);
+                       struct sbuf *so_rcv = &so->so_rcv;
+
+                       if (m->m_len > so_rcv->sb_datalen
+                                       - (so_rcv->sb_wptr - so_rcv->sb_data)) {
+                           return 1;
+                       }
+
+                       memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
+                       so_rcv->sb_wptr += m->m_len;
+                       so_rcv->sb_rptr += m->m_len;
+                       m->m_data[m->m_len] = 0; /* NULL terminate */
+                       if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) {
+                               if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) {
+                                       HTONS(n1);
+                                       HTONS(n2);
+                                       /* n2 is the one on our host */
+                                       for (tmpso = slirp->tcb.so_next;
+                                            tmpso != &slirp->tcb;
+                                            tmpso = tmpso->so_next) {
+                                               if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr &&
+                                                   tmpso->so_lport == n2 &&
+                                                   tmpso->so_faddr.s_addr == so->so_faddr.s_addr &&
+                                                   tmpso->so_fport == n1) {
+                                                       if (getsockname(tmpso->s,
+                                                               (struct sockaddr *)&addr, &addrlen) == 0)
+                                                          n2 = addr.sin_port;
+                                                       break;
+                                               }
+                                       }
+                                       NTOHS(n1);
+                                       NTOHS(n2);
+                                       so_rcv->sb_cc = snprintf(so_rcv->sb_data,
+                                                                so_rcv->sb_datalen,
+                                                                "%d,%d\r\n", n1, n2);
+                                       so_rcv->sb_rptr = so_rcv->sb_data;
+                                       so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc;
+                               }
+                       }
+                       m_free(m);
+                       return 0;
+               }
+
+        case EMU_FTP: /* ftp */
+                *(m->m_data+m->m_len) = 0; /* NUL terminate for strstr */
+               if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) {
+                       /*
+                        * Need to emulate the PORT command
+                        */
+                       x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]",
+                                  &n1, &n2, &n3, &n4, &n5, &n6, buff);
+                       if (x < 6)
+                          return 1;
+
+                       laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
+                       lport = htons((n5 << 8) | (n6));
+
+                       if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr,
+                                            lport, SS_FACCEPTONCE)) == NULL) {
+                          return 1;
+                       }
+                       n6 = ntohs(so->so_fport);
+
+                       n5 = (n6 >> 8) & 0xff;
+                       n6 &= 0xff;
+
+                       laddr = ntohl(so->so_faddr.s_addr);
+
+                       n1 = ((laddr >> 24) & 0xff);
+                       n2 = ((laddr >> 16) & 0xff);
+                       n3 = ((laddr >> 8)  & 0xff);
+                       n4 =  (laddr & 0xff);
+
+                       m->m_len = bptr - m->m_data; /* Adjust length */
+                        m->m_len += snprintf(bptr, m->m_size - m->m_len,
+                                             "ORT %d,%d,%d,%d,%d,%d\r\n%s",
+                                             n1, n2, n3, n4, n5, n6, x==7?buff:"");
+                       return 1;
+               } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
+                       /*
+                        * Need to emulate the PASV response
+                        */
+                       x = sscanf(bptr, "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]",
+                                  &n1, &n2, &n3, &n4, &n5, &n6, buff);
+                       if (x < 6)
+                          return 1;
+
+                       laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
+                       lport = htons((n5 << 8) | (n6));
+
+                       if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr,
+                                            lport, SS_FACCEPTONCE)) == NULL) {
+                          return 1;
+                       }
+                       n6 = ntohs(so->so_fport);
+
+                       n5 = (n6 >> 8) & 0xff;
+                       n6 &= 0xff;
+
+                       laddr = ntohl(so->so_faddr.s_addr);
+
+                       n1 = ((laddr >> 24) & 0xff);
+                       n2 = ((laddr >> 16) & 0xff);
+                       n3 = ((laddr >> 8)  & 0xff);
+                       n4 =  (laddr & 0xff);
+
+                       m->m_len = bptr - m->m_data; /* Adjust length */
+                       m->m_len += snprintf(bptr, m->m_size - m->m_len,
+                                             "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
+                                             n1, n2, n3, n4, n5, n6, x==7?buff:"");
+
+                       return 1;
+               }
+
+               return 1;
+
+        case EMU_KSH:
+               /*
+                * The kshell (Kerberos rsh) and shell services both pass
+                * a local port port number to carry signals to the server
+                * and stderr to the client.  It is passed at the beginning
+                * of the connection as a NUL-terminated decimal ASCII string.
+                */
+               so->so_emu = 0;
+               for (lport = 0, i = 0; i < m->m_len-1; ++i) {
+                       if (m->m_data[i] < '0' || m->m_data[i] > '9')
+                               return 1;       /* invalid number */
+                       lport *= 10;
+                       lport += m->m_data[i] - '0';
+               }
+               if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
+                   (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr,
+                                    htons(lport), SS_FACCEPTONCE)) != NULL)
+                    m->m_len = snprintf(m->m_data, m->m_size, "%d",
+                                        ntohs(so->so_fport)) + 1;
+               return 1;
+
+        case EMU_IRC:
+               /*
+                * Need to emulate DCC CHAT, DCC SEND and DCC MOVE
+                */
+               *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */
+               if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL)
+                        return 1;
+
+               /* The %256s is for the broken mIRC */
+               if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
+                       if ((so = tcp_listen(slirp, INADDR_ANY, 0,
+                                            htonl(laddr), htons(lport),
+                                            SS_FACCEPTONCE)) == NULL) {
+                               return 1;
+                       }
+                       m->m_len = bptr - m->m_data; /* Adjust length */
+                        m->m_len += snprintf(bptr, m->m_size,
+                                             "DCC CHAT chat %lu %u%c\n",
+                                             (unsigned long)ntohl(so->so_faddr.s_addr),
+                                             ntohs(so->so_fport), 1);
+               } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
+                       if ((so = tcp_listen(slirp, INADDR_ANY, 0,
+                                            htonl(laddr), htons(lport),
+                                            SS_FACCEPTONCE)) == NULL) {
+                               return 1;
+                       }
+                       m->m_len = bptr - m->m_data; /* Adjust length */
+                        m->m_len += snprintf(bptr, m->m_size,
+                                             "DCC SEND %s %lu %u %u%c\n", buff,
+                                             (unsigned long)ntohl(so->so_faddr.s_addr),
+                                             ntohs(so->so_fport), n1, 1);
+               } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
+                       if ((so = tcp_listen(slirp, INADDR_ANY, 0,
+                                            htonl(laddr), htons(lport),
+                                            SS_FACCEPTONCE)) == NULL) {
+                               return 1;
+                       }
+                       m->m_len = bptr - m->m_data; /* Adjust length */
+                        m->m_len += snprintf(bptr, m->m_size,
+                                             "DCC MOVE %s %lu %u %u%c\n", buff,
+                                             (unsigned long)ntohl(so->so_faddr.s_addr),
+                                             ntohs(so->so_fport), n1, 1);
+               }
+               return 1;
+
+        case EMU_REALAUDIO:
+                /*
+                * RealAudio emulation - JP. We must try to parse the incoming
+                * data and try to find the two characters that contain the
+                * port number. Then we redirect an udp port and replace the
+                * number with the real port we got.
+                *
+                * The 1.0 beta versions of the player are not supported
+                * any more.
+                *
+                * A typical packet for player version 1.0 (release version):
+                *
+                * 0000:50 4E 41 00 05
+                * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 ........g.l.c..P
+                * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH
+                * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v
+                * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB
+                *
+                * Now the port number 0x1BD7 is found at offset 0x04 of the
+                * Now the port number 0x1BD7 is found at offset 0x04 of the
+                * second packet. This time we received five bytes first and
+                * then the rest. You never know how many bytes you get.
+                *
+                * A typical packet for player version 2.0 (beta):
+                *
+                * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA.............
+                * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .gux.c..Win2.0.0
+                * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/
+                * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas
+                * 0040:65 2E 72 61 79 53 00 00 06 36 42                e.rayS...6B
+                *
+                * Port number 0x1BC1 is found at offset 0x0d.
+                *
+                * This is just a horrible switch statement. Variable ra tells
+                * us where we're going.
+                */
+
+               bptr = m->m_data;
+               while (bptr < m->m_data + m->m_len) {
+                       uint16_t p;
+                       static int ra = 0;
+                       char ra_tbl[4];
+
+                       ra_tbl[0] = 0x50;
+                       ra_tbl[1] = 0x4e;
+                       ra_tbl[2] = 0x41;
+                       ra_tbl[3] = 0;
+
+                       switch (ra) {
+                        case 0:
+                        case 2:
+                        case 3:
+                               if (*bptr++ != ra_tbl[ra]) {
+                                       ra = 0;
+                                       continue;
+                               }
+                               break;
+
+                        case 1:
+                               /*
+                                * We may get 0x50 several times, ignore them
+                                */
+                               if (*bptr == 0x50) {
+                                       ra = 1;
+                                       bptr++;
+                                       continue;
+                               } else if (*bptr++ != ra_tbl[ra]) {
+                                       ra = 0;
+                                       continue;
+                               }
+                               break;
+
+                        case 4:
+                               /*
+                                * skip version number
+                                */
+                               bptr++;
+                               break;
+
+                        case 5:
+                               /*
+                                * The difference between versions 1.0 and
+                                * 2.0 is here. For future versions of
+                                * the player this may need to be modified.
+                                */
+                               if (*(bptr + 1) == 0x02)
+                                  bptr += 8;
+                               else
+                                  bptr += 4;
+                               break;
+
+                        case 6:
+                               /* This is the field containing the port
+                                * number that RA-player is listening to.
+                                */
+                               lport = (((uint8_t*)bptr)[0] << 8)
+                               + ((uint8_t *)bptr)[1];
+                               if (lport < 6970)
+                                  lport += 256;   /* don't know why */
+                               if (lport < 6970 || lport > 7170)
+                                  return 1;       /* failed */
+
+                               /* try to get udp port between 6970 - 7170 */
+                               for (p = 6970; p < 7071; p++) {
+                                       if (udp_listen(slirp, INADDR_ANY,
+                                                      htons(p),
+                                                      so->so_laddr.s_addr,
+                                                      htons(lport),
+                                                      SS_FACCEPTONCE)) {
+                                               break;
+                                       }
+                               }
+                               if (p == 7071)
+                                  p = 0;
+                               *(uint8_t *)bptr++ = (p >> 8) & 0xff;
+                                *(uint8_t *)bptr = p & 0xff;
+                               ra = 0;
+                               return 1;   /* port redirected, we're done */
+                               break;
+
+                        default:
+                               ra = 0;
+                       }
+                       ra++;
+               }
+               return 1;
+
+        default:
+               /* Ooops, not emulated, won't call tcp_emu again */
+               so->so_emu = 0;
+               return 1;
+       }
+}
+
+/*
+ * Do misc. config of SLiRP while its running.
+ * Return 0 if this connections is to be closed, 1 otherwise,
+ * return 2 if this is a command-line connection
+ */
+int tcp_ctl(struct socket *so)
+{
+    Slirp *slirp = so->slirp;
+    struct sbuf *sb = &so->so_snd;
+    struct gfwd_list *ex_ptr;
+
+    DEBUG_CALL("tcp_ctl");
+    DEBUG_ARG("so = %p", so);
+
+    /* TODO: IPv6 */
+    if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
+        /* Check if it's pty_exec */
+        for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+            if (ex_ptr->ex_fport == so->so_fport &&
+                so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
+                if (ex_ptr->write_cb) {
+                    so->s = -1;
+                    so->guestfwd = ex_ptr;
+                    return 1;
+                }
+                DEBUG_MISC(" executing %s", ex_ptr->ex_exec);
+                return fork_exec(so, ex_ptr->ex_exec);
+            }
+        }
+    }
+    sb->sb_cc =
+        snprintf(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data),
+                 "Error: No application configured.\r\n");
+    sb->sb_wptr += sb->sb_cc;
+    return 0;
+}
diff --git a/slirp/src/tcp_timer.c b/slirp/src/tcp_timer.c
new file mode 100644 (file)
index 0000000..7be5457
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 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. 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.
+ *
+ *     @(#)tcp_timer.c 8.1 (Berkeley) 6/10/93
+ * tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp
+ */
+
+#include "slirp.h"
+
+static struct tcpcb *tcp_timers(register struct tcpcb *tp, int timer);
+
+/*
+ * Fast timeout routine for processing delayed acks
+ */
+void
+tcp_fasttimo(Slirp *slirp)
+{
+       register struct socket *so;
+       register struct tcpcb *tp;
+
+       DEBUG_CALL("tcp_fasttimo");
+
+       so = slirp->tcb.so_next;
+       if (so)
+       for (; so != &slirp->tcb; so = so->so_next)
+               if ((tp = (struct tcpcb *)so->so_tcpcb) &&
+                   (tp->t_flags & TF_DELACK)) {
+                       tp->t_flags &= ~TF_DELACK;
+                       tp->t_flags |= TF_ACKNOW;
+                       (void) tcp_output(tp);
+               }
+}
+
+/*
+ * Tcp protocol timeout routine called every 500 ms.
+ * Updates the timers in all active tcb's and
+ * causes finite state machine actions if timers expire.
+ */
+void
+tcp_slowtimo(Slirp *slirp)
+{
+       register struct socket *ip, *ipnxt;
+       register struct tcpcb *tp;
+       register int i;
+
+       DEBUG_CALL("tcp_slowtimo");
+
+       /*
+        * Search through tcb's and update active timers.
+        */
+       ip = slirp->tcb.so_next;
+        if (ip == NULL) {
+            return;
+        }
+       for (; ip != &slirp->tcb; ip = ipnxt) {
+               ipnxt = ip->so_next;
+               tp = sototcpcb(ip);
+                if (tp == NULL) {
+                        continue;
+                }
+               for (i = 0; i < TCPT_NTIMERS; i++) {
+                       if (tp->t_timer[i] && --tp->t_timer[i] == 0) {
+                               tcp_timers(tp,i);
+                               if (ipnxt->so_prev != ip)
+                                       goto tpgone;
+                       }
+               }
+               tp->t_idle++;
+               if (tp->t_rtt)
+                  tp->t_rtt++;
+tpgone:
+               ;
+       }
+       slirp->tcp_iss += TCP_ISSINCR/PR_SLOWHZ;        /* increment iss */
+       slirp->tcp_now++;                               /* for timestamps */
+}
+
+/*
+ * Cancel all timers for TCP tp.
+ */
+void
+tcp_canceltimers(struct tcpcb *tp)
+{
+       register int i;
+
+       for (i = 0; i < TCPT_NTIMERS; i++)
+               tp->t_timer[i] = 0;
+}
+
+const int tcp_backoff[TCP_MAXRXTSHIFT + 1] =
+   { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
+
+/*
+ * TCP timer processing.
+ */
+static struct tcpcb *
+tcp_timers(register struct tcpcb *tp, int timer)
+{
+       register int rexmt;
+
+       DEBUG_CALL("tcp_timers");
+
+       switch (timer) {
+
+       /*
+        * 2 MSL timeout in shutdown went off.  If we're closed but
+        * still waiting for peer to close and connection has been idle
+        * too long, or if 2MSL time is up from TIME_WAIT, delete connection
+        * control block.  Otherwise, check again in a bit.
+        */
+       case TCPT_2MSL:
+               if (tp->t_state != TCPS_TIME_WAIT &&
+                   tp->t_idle <= TCP_MAXIDLE)
+                       tp->t_timer[TCPT_2MSL] = TCPTV_KEEPINTVL;
+               else
+                       tp = tcp_close(tp);
+               break;
+
+       /*
+        * Retransmission timer went off.  Message has not
+        * been acked within retransmit interval.  Back off
+        * to a longer retransmit interval and retransmit one segment.
+        */
+       case TCPT_REXMT:
+
+               /*
+                * XXXXX If a packet has timed out, then remove all the queued
+                * packets for that session.
+                */
+
+               if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
+                       /*
+                        * This is a hack to suit our terminal server here at the uni of canberra
+                        * since they have trouble with zeroes... It usually lets them through
+                        * unharmed, but under some conditions, it'll eat the zeros.  If we
+                        * keep retransmitting it, it'll keep eating the zeroes, so we keep
+                        * retransmitting, and eventually the connection dies...
+                        * (this only happens on incoming data)
+                        *
+                        * So, if we were gonna drop the connection from too many retransmits,
+                        * don't... instead halve the t_maxseg, which might break up the NULLs and
+                        * let them through
+                        *
+                        * *sigh*
+                        */
+
+                       tp->t_maxseg >>= 1;
+                       if (tp->t_maxseg < 32) {
+                               /*
+                                * We tried our best, now the connection must die!
+                                */
+                               tp->t_rxtshift = TCP_MAXRXTSHIFT;
+                               tp = tcp_drop(tp, tp->t_softerror);
+                               /* tp->t_softerror : ETIMEDOUT); */ /* XXX */
+                               return (tp); /* XXX */
+                       }
+
+                       /*
+                        * Set rxtshift to 6, which is still at the maximum
+                        * backoff time
+                        */
+                       tp->t_rxtshift = 6;
+               }
+               rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
+               TCPT_RANGESET(tp->t_rxtcur, rexmt,
+                   (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */
+               tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+               /*
+                * If losing, let the lower level know and try for
+                * a better route.  Also, if we backed off this far,
+                * our srtt estimate is probably bogus.  Clobber it
+                * so we'll take the next rtt measurement as our srtt;
+                * move the current srtt into rttvar to keep the current
+                * retransmit times until then.
+                */
+               if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
+                       tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
+                       tp->t_srtt = 0;
+               }
+               tp->snd_nxt = tp->snd_una;
+               /*
+                * If timing a segment in this window, stop the timer.
+                */
+               tp->t_rtt = 0;
+               /*
+                * Close the congestion window down to one segment
+                * (we'll open it by one segment for each ack we get).
+                * Since we probably have a window's worth of unacked
+                * data accumulated, this "slow start" keeps us from
+                * dumping all that data as back-to-back packets (which
+                * might overwhelm an intermediate gateway).
+                *
+                * There are two phases to the opening: Initially we
+                * open by one mss on each ack.  This makes the window
+                * size increase exponentially with time.  If the
+                * window is larger than the path can handle, this
+                * exponential growth results in dropped packet(s)
+                * almost immediately.  To get more time between
+                * drops but still "push" the network to take advantage
+                * of improving conditions, we switch from exponential
+                * to linear window opening at some threshold size.
+                * For a threshold, we use half the current window
+                * size, truncated to a multiple of the mss.
+                *
+                * (the minimum cwnd that will give us exponential
+                * growth is 2 mss.  We don't allow the threshold
+                * to go below this.)
+                */
+               {
+                unsigned win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
+               if (win < 2)
+                       win = 2;
+               tp->snd_cwnd = tp->t_maxseg;
+               tp->snd_ssthresh = win * tp->t_maxseg;
+               tp->t_dupacks = 0;
+               }
+               (void) tcp_output(tp);
+               break;
+
+       /*
+        * Persistence timer into zero window.
+        * Force a byte to be output, if possible.
+        */
+       case TCPT_PERSIST:
+               tcp_setpersist(tp);
+               tp->t_force = 1;
+               (void) tcp_output(tp);
+               tp->t_force = 0;
+               break;
+
+       /*
+        * Keep-alive timer went off; send something
+        * or drop connection if idle for too long.
+        */
+       case TCPT_KEEP:
+               if (tp->t_state < TCPS_ESTABLISHED)
+                       goto dropit;
+
+               if (slirp_do_keepalive && tp->t_state <= TCPS_CLOSE_WAIT) {
+                       if (tp->t_idle >= TCPTV_KEEP_IDLE + TCP_MAXIDLE)
+                               goto dropit;
+                       /*
+                        * Send a packet designed to force a response
+                        * if the peer is up and reachable:
+                        * either an ACK if the connection is still alive,
+                        * or an RST if the peer has closed the connection
+                        * due to timeout or reboot.
+                        * Using sequence number tp->snd_una-1
+                        * causes the transmitted zero-length segment
+                        * to lie outside the receive window;
+                        * by the protocol spec, this requires the
+                        * correspondent TCP to respond.
+                        */
+                       tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
+                           tp->rcv_nxt, tp->snd_una - 1, 0,
+                           tp->t_socket->so_ffamily);
+                       tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
+               } else
+                       tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
+               break;
+
+       dropit:
+               tp = tcp_drop(tp, 0);
+               break;
+       }
+
+       return (tp);
+}
diff --git a/slirp/src/tcp_timer.h b/slirp/src/tcp_timer.h
new file mode 100644 (file)
index 0000000..b25b391
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1982, 1986, 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. 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.
+ *
+ *     @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93
+ * tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp
+ */
+
+#ifndef TCP_TIMER_H
+#define TCP_TIMER_H
+
+/*
+ * Definitions of the TCP timers.  These timers are counted
+ * down PR_SLOWHZ times a second.
+ */
+#define        TCPT_NTIMERS    4
+
+#define        TCPT_REXMT      0               /* retransmit */
+#define        TCPT_PERSIST    1               /* retransmit persistence */
+#define        TCPT_KEEP       2               /* keep alive */
+#define        TCPT_2MSL       3               /* 2*msl quiet time timer */
+
+/*
+ * The TCPT_REXMT timer is used to force retransmissions.
+ * The TCP has the TCPT_REXMT timer set whenever segments
+ * have been sent for which ACKs are expected but not yet
+ * received.  If an ACK is received which advances tp->snd_una,
+ * then the retransmit timer is cleared (if there are no more
+ * outstanding segments) or reset to the base value (if there
+ * are more ACKs expected).  Whenever the retransmit timer goes off,
+ * we retransmit one unacknowledged segment, and do a backoff
+ * on the retransmit timer.
+ *
+ * The TCPT_PERSIST timer is used to keep window size information
+ * flowing even if the window goes shut.  If all previous transmissions
+ * have been acknowledged (so that there are no retransmissions in progress),
+ * and the window is too small to bother sending anything, then we start
+ * the TCPT_PERSIST timer.  When it expires, if the window is nonzero,
+ * we go to transmit state.  Otherwise, at intervals send a single byte
+ * into the peer's window to force him to update our window information.
+ * We do this at most as often as TCPT_PERSMIN time intervals,
+ * but no more frequently than the current estimate of round-trip
+ * packet time.  The TCPT_PERSIST timer is cleared whenever we receive
+ * a window update from the peer.
+ *
+ * The TCPT_KEEP timer is used to keep connections alive.  If an
+ * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time,
+ * but not yet established, then we drop the connection.  Once the connection
+ * is established, if the connection is idle for TCPTV_KEEP_IDLE time
+ * (and keepalives have been enabled on the socket), we begin to probe
+ * the connection.  We force the peer to send us a segment by sending:
+ *     <SEQ=SND.UNA-1><ACK=RCV.NXT><CTL=ACK>
+ * This segment is (deliberately) outside the window, and should elicit
+ * an ack segment in response from the peer.  If, despite the TCPT_KEEP
+ * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE
+ * amount of time probing, then we drop the connection.
+ */
+
+/*
+ * Time constants.
+ */
+#define TCPTV_MSL       ( 5*PR_SLOWHZ)          /* max seg lifetime (hah!) */
+
+#define        TCPTV_SRTTBASE  0                       /* base roundtrip time;
+                                                  if 0, no idea yet */
+#define        TCPTV_SRTTDFLT  (  3*PR_SLOWHZ)         /* assumed RTT if no info */
+
+#define        TCPTV_PERSMIN   (  5*PR_SLOWHZ)         /* retransmit persistence */
+#define        TCPTV_PERSMAX   ( 60*PR_SLOWHZ)         /* maximum persist interval */
+
+#define        TCPTV_KEEP_INIT ( 75*PR_SLOWHZ)         /* initial connect keep alive */
+#define        TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ)      /* dflt time before probing */
+#define        TCPTV_KEEPINTVL ( 75*PR_SLOWHZ)         /* default probe interval */
+#define        TCPTV_KEEPCNT   8                       /* max probes before drop */
+
+#define        TCPTV_MIN       (  1*PR_SLOWHZ)         /* minimum allowable value */
+#define TCPTV_REXMTMAX  ( 12*PR_SLOWHZ)                /* max allowable REXMT value */
+
+#define        TCP_LINGERTIME  120                     /* linger at most 2 minutes */
+
+#define TCP_MAXRXTSHIFT 12                      /* maximum retransmits */
+
+
+/*
+ * Force a time value to be in a certain range.
+ */
+#define        TCPT_RANGESET(tv, value, tvmin, tvmax) { \
+       (tv) = (value); \
+       if ((tv) < (tvmin)) \
+               (tv) = (tvmin); \
+       else if ((tv) > (tvmax)) \
+               (tv) = (tvmax); \
+}
+
+extern const int tcp_backoff[];
+
+struct tcpcb;
+
+void tcp_fasttimo(Slirp *);
+void tcp_slowtimo(Slirp *);
+void tcp_canceltimers(struct tcpcb *);
+
+#endif
diff --git a/slirp/src/tcp_var.h b/slirp/src/tcp_var.h
new file mode 100644 (file)
index 0000000..27ef1a5
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 1982, 1986, 1993, 1994
+ *     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. 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.
+ *
+ *     @(#)tcp_var.h   8.3 (Berkeley) 4/10/94
+ * tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp
+ */
+
+#ifndef TCP_VAR_H
+#define TCP_VAR_H
+
+#include "tcpip.h"
+#include "tcp_timer.h"
+
+/*
+ * Tcp control block, one per tcp; fields:
+ */
+struct tcpcb {
+       struct tcpiphdr *seg_next;      /* sequencing queue */
+       struct tcpiphdr *seg_prev;
+       short   t_state;                /* state of this connection */
+       short   t_timer[TCPT_NTIMERS];  /* tcp timers */
+       short   t_rxtshift;             /* log(2) of rexmt exp. backoff */
+       short   t_rxtcur;               /* current retransmit value */
+       short   t_dupacks;              /* consecutive dup acks recd */
+       uint16_t        t_maxseg;               /* maximum segment size */
+       uint8_t t_force;                /* 1 if forcing out a byte */
+       uint16_t        t_flags;
+#define        TF_ACKNOW       0x0001          /* ack peer immediately */
+#define        TF_DELACK       0x0002          /* ack, but try to delay it */
+#define        TF_NODELAY      0x0004          /* don't delay packets to coalesce */
+#define        TF_NOOPT        0x0008          /* don't use tcp options */
+#define        TF_SENTFIN      0x0010          /* have sent FIN */
+#define        TF_REQ_SCALE    0x0020          /* have/will request window scaling */
+#define        TF_RCVD_SCALE   0x0040          /* other side has requested scaling */
+#define        TF_REQ_TSTMP    0x0080          /* have/will request timestamps */
+#define        TF_RCVD_TSTMP   0x0100          /* a timestamp was received in SYN */
+#define        TF_SACK_PERMIT  0x0200          /* other side said I could SACK */
+
+       struct  tcpiphdr t_template;    /* static skeletal packet for xmit */
+
+       struct  socket *t_socket;               /* back pointer to socket */
+/*
+ * The following fields are used as in the protocol specification.
+ * See RFC783, Dec. 1981, page 21.
+ */
+/* send sequence variables */
+       tcp_seq snd_una;                /* send unacknowledged */
+       tcp_seq snd_nxt;                /* send next */
+       tcp_seq snd_up;                 /* send urgent pointer */
+       tcp_seq snd_wl1;                /* window update seg seq number */
+       tcp_seq snd_wl2;                /* window update seg ack number */
+       tcp_seq iss;                    /* initial send sequence number */
+       uint32_t snd_wnd;               /* send window */
+/* receive sequence variables */
+       uint32_t rcv_wnd;               /* receive window */
+       tcp_seq rcv_nxt;                /* receive next */
+       tcp_seq rcv_up;                 /* receive urgent pointer */
+       tcp_seq irs;                    /* initial receive sequence number */
+/*
+ * Additional variables for this implementation.
+ */
+/* receive variables */
+       tcp_seq rcv_adv;                /* advertised window */
+/* retransmit variables */
+       tcp_seq snd_max;                /* highest sequence number sent;
+                                        * used to recognize retransmits
+                                        */
+/* congestion control (for slow start, source quench, retransmit after loss) */
+       uint32_t snd_cwnd;              /* congestion-controlled window */
+       uint32_t snd_ssthresh;          /* snd_cwnd size threshold for
+                                        * for slow start exponential to
+                                        * linear switch
+                                        */
+/*
+ * transmit timing stuff.  See below for scale of srtt and rttvar.
+ * "Variance" is actually smoothed difference.
+ */
+       short   t_idle;                 /* inactivity time */
+       short   t_rtt;                  /* round trip time */
+       tcp_seq t_rtseq;                /* sequence number being timed */
+       short   t_srtt;                 /* smoothed round-trip time */
+       short   t_rttvar;               /* variance in round-trip time */
+       uint16_t        t_rttmin;               /* minimum rtt allowed */
+       uint32_t max_sndwnd;            /* largest window peer has offered */
+
+/* out-of-band data */
+       uint8_t t_oobflags;             /* have some */
+       uint8_t t_iobc;                 /* input character */
+#define        TCPOOB_HAVEDATA 0x01
+#define        TCPOOB_HADDATA  0x02
+       short   t_softerror;            /* possible error not yet reported */
+
+/* RFC 1323 variables */
+       uint8_t snd_scale;              /* window scaling for send window */
+       uint8_t rcv_scale;              /* window scaling for recv window */
+       uint8_t request_r_scale;        /* pending window scaling */
+       uint8_t requested_s_scale;
+       uint32_t        ts_recent;              /* timestamp echo data */
+       uint32_t        ts_recent_age;          /* when last updated */
+       tcp_seq last_ack_sent;
+
+};
+
+#define        sototcpcb(so)   ((so)->so_tcpcb)
+
+/*
+ * The smoothed round-trip time and estimated variance
+ * are stored as fixed point numbers scaled by the values below.
+ * For convenience, these scales are also used in smoothing the average
+ * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed).
+ * With these scales, srtt has 3 bits to the right of the binary point,
+ * and thus an "ALPHA" of 0.875.  rttvar has 2 bits to the right of the
+ * binary point, and is smoothed with an ALPHA of 0.75.
+ */
+#define        TCP_RTT_SCALE           8       /* multiplier for srtt; 3 bits frac. */
+#define        TCP_RTT_SHIFT           3       /* shift for srtt; 3 bits frac. */
+#define        TCP_RTTVAR_SCALE        4       /* multiplier for rttvar; 2 bits */
+#define        TCP_RTTVAR_SHIFT        2       /* multiplier for rttvar; 2 bits */
+
+/*
+ * The initial retransmission should happen at rtt + 4 * rttvar.
+ * Because of the way we do the smoothing, srtt and rttvar
+ * will each average +1/2 tick of bias.  When we compute
+ * the retransmit timer, we want 1/2 tick of rounding and
+ * 1 extra tick because of +-1/2 tick uncertainty in the
+ * firing of the timer.  The bias will give us exactly the
+ * 1.5 tick we need.  But, because the bias is
+ * statistical, we have to test that we don't drop below
+ * the minimum feasible timer (which is 2 ticks).
+ * This macro assumes that the value of TCP_RTTVAR_SCALE
+ * is the same as the multiplier for rttvar.
+ */
+#define        TCP_REXMTVAL(tp) \
+       (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar)
+
+#endif
diff --git a/slirp/src/tcpip.h b/slirp/src/tcpip.h
new file mode 100644 (file)
index 0000000..07dbf2c
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1982, 1986, 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. 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.
+ *
+ *     @(#)tcpip.h     8.1 (Berkeley) 6/10/93
+ * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp
+ */
+
+#ifndef TCPIP_H
+#define TCPIP_H
+
+/*
+ * Tcp+ip header, after ip options removed.
+ */
+struct tcpiphdr {
+    struct mbuf_ptr ih_mbuf;   /* backpointer to mbuf */
+    union {
+        struct {
+            struct  in_addr ih_src; /* source internet address */
+            struct  in_addr ih_dst; /* destination internet address */
+            uint8_t ih_x1;          /* (unused) */
+            uint8_t ih_pr;          /* protocol */
+        } ti_i4;
+        struct {
+            struct  in6_addr ih_src;
+            struct  in6_addr ih_dst;
+            uint8_t ih_x1;
+            uint8_t ih_nh;
+        } ti_i6;
+    } ti;
+    uint16_t    ti_x0;
+    uint16_t    ti_len;             /* protocol length */
+    struct      tcphdr ti_t;        /* tcp header */
+};
+#define        ti_mbuf         ih_mbuf.mptr
+#define        ti_pr           ti.ti_i4.ih_pr
+#define        ti_src          ti.ti_i4.ih_src
+#define        ti_dst          ti.ti_i4.ih_dst
+#define        ti_src6         ti.ti_i6.ih_src
+#define        ti_dst6         ti.ti_i6.ih_dst
+#define        ti_nh6          ti.ti_i6.ih_nh
+#define        ti_sport        ti_t.th_sport
+#define        ti_dport        ti_t.th_dport
+#define        ti_seq          ti_t.th_seq
+#define        ti_ack          ti_t.th_ack
+#define        ti_x2           ti_t.th_x2
+#define        ti_off          ti_t.th_off
+#define        ti_flags        ti_t.th_flags
+#define        ti_win          ti_t.th_win
+#define        ti_sum          ti_t.th_sum
+#define        ti_urp          ti_t.th_urp
+
+#define tcpiphdr2qlink(T) ((struct qlink*)(((char*)(T)) - sizeof(struct qlink)))
+#define qlink2tcpiphdr(Q) ((struct tcpiphdr*)(((char*)(Q)) + sizeof(struct qlink)))
+#define tcpiphdr_next(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->next)
+#define tcpiphdr_prev(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->prev)
+#define tcpfrag_list_first(T) qlink2tcpiphdr((T)->seg_next)
+#define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink*)(T))
+#define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr*)(T))
+
+/* This is the difference between the size of a tcpiphdr structure, and the
+ * size of actual ip+tcp headers, rounded up since we need to align data.  */
+#define TCPIPHDR_DELTA\
+    (MAX(0,\
+         (sizeof(struct tcpiphdr)\
+          - sizeof(struct ip) - sizeof(struct tcphdr) + 3) & ~3))
+
+/*
+ * Just a clean way to get to the first byte
+ * of the packet
+ */
+struct tcpiphdr_2 {
+       struct tcpiphdr dummy;
+       char first_char;
+};
+
+#endif
diff --git a/slirp/src/tftp.c b/slirp/src/tftp.c
new file mode 100644 (file)
index 0000000..2d8f978
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * tftp.c - a simple, read-only tftp server for qemu
+ *
+ * Copyright (c) 2004 Magnus Damm <damm@opensource.se>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "slirp.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+static inline int tftp_session_in_use(struct tftp_session *spt)
+{
+    return (spt->slirp != NULL);
+}
+
+static inline void tftp_session_update(struct tftp_session *spt)
+{
+    spt->timestamp = curtime;
+}
+
+static void tftp_session_terminate(struct tftp_session *spt)
+{
+    if (spt->fd >= 0) {
+        close(spt->fd);
+        spt->fd = -1;
+    }
+    g_free(spt->filename);
+    spt->slirp = NULL;
+}
+
+static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage *srcsas,
+                                 struct tftp_t *tp)
+{
+  struct tftp_session *spt;
+  int k;
+
+  for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
+    spt = &slirp->tftp_sessions[k];
+
+    if (!tftp_session_in_use(spt))
+        goto found;
+
+    /* sessions time out after 5 inactive seconds */
+    if ((int)(curtime - spt->timestamp) > 5000) {
+        tftp_session_terminate(spt);
+        goto found;
+    }
+  }
+
+  return -1;
+
+ found:
+  memset(spt, 0, sizeof(*spt));
+  memcpy(&spt->client_addr, srcsas, sockaddr_size(srcsas));
+  spt->fd = -1;
+  spt->block_size = 512;
+  spt->client_port = tp->udp.uh_sport;
+  spt->slirp = slirp;
+
+  tftp_session_update(spt);
+
+  return k;
+}
+
+static int tftp_session_find(Slirp *slirp, struct sockaddr_storage *srcsas,
+                             struct tftp_t *tp)
+{
+  struct tftp_session *spt;
+  int k;
+
+  for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
+    spt = &slirp->tftp_sessions[k];
+
+    if (tftp_session_in_use(spt)) {
+      if (sockaddr_equal(&spt->client_addr, srcsas)) {
+       if (spt->client_port == tp->udp.uh_sport) {
+         return k;
+       }
+      }
+    }
+  }
+
+  return -1;
+}
+
+static int tftp_read_data(struct tftp_session *spt, uint32_t block_nr,
+                          uint8_t *buf, int len)
+{
+    int bytes_read = 0;
+
+    if (spt->fd < 0) {
+        spt->fd = open(spt->filename, O_RDONLY | O_BINARY);
+    }
+
+    if (spt->fd < 0) {
+        return -1;
+    }
+
+    if (len) {
+        lseek(spt->fd, block_nr * spt->block_size, SEEK_SET);
+
+        bytes_read = read(spt->fd, buf, len);
+    }
+
+    return bytes_read;
+}
+
+static struct tftp_t *tftp_prep_mbuf_data(struct tftp_session *spt,
+                                          struct mbuf *m)
+{
+    struct tftp_t *tp;
+
+    memset(m->m_data, 0, m->m_size);
+
+    m->m_data += IF_MAXLINKHDR;
+    if (spt->client_addr.ss_family == AF_INET6) {
+        m->m_data += sizeof(struct ip6);
+    } else {
+        m->m_data += sizeof(struct ip);
+    }
+    tp = (void *)m->m_data;
+    m->m_data += sizeof(struct udphdr);
+
+    return tp;
+}
+
+static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m,
+                            struct tftp_t *recv_tp)
+{
+    if (spt->client_addr.ss_family == AF_INET6) {
+        struct sockaddr_in6 sa6, da6;
+
+        sa6.sin6_addr = spt->slirp->vhost_addr6;
+        sa6.sin6_port = recv_tp->udp.uh_dport;
+        da6.sin6_addr = ((struct sockaddr_in6 *)&spt->client_addr)->sin6_addr;
+        da6.sin6_port = spt->client_port;
+
+        udp6_output(NULL, m, &sa6, &da6);
+    } else {
+        struct sockaddr_in sa4, da4;
+
+        sa4.sin_addr = spt->slirp->vhost_addr;
+        sa4.sin_port = recv_tp->udp.uh_dport;
+        da4.sin_addr = ((struct sockaddr_in *)&spt->client_addr)->sin_addr;
+        da4.sin_port = spt->client_port;
+
+        udp_output(NULL, m, &sa4, &da4, IPTOS_LOWDELAY);
+    }
+}
+
+static int tftp_send_oack(struct tftp_session *spt,
+                          const char *keys[], uint32_t values[], int nb,
+                          struct tftp_t *recv_tp)
+{
+    struct mbuf *m;
+    struct tftp_t *tp;
+    int i, n = 0;
+
+    m = m_get(spt->slirp);
+
+    if (!m)
+        return -1;
+
+    tp = tftp_prep_mbuf_data(spt, m);
+
+    tp->tp_op = htons(TFTP_OACK);
+    for (i = 0; i < nb; i++) {
+        n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
+                      keys[i]) + 1;
+        n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
+                      values[i]) + 1;
+    }
+
+    m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + n
+               - sizeof(struct udphdr);
+    tftp_udp_output(spt, m, recv_tp);
+
+    return 0;
+}
+
+static void tftp_send_error(struct tftp_session *spt,
+                            uint16_t errorcode, const char *msg,
+                            struct tftp_t *recv_tp)
+{
+  struct mbuf *m;
+  struct tftp_t *tp;
+
+  DEBUG_TFTP("tftp error msg: %s", msg);
+
+  m = m_get(spt->slirp);
+
+  if (!m) {
+    goto out;
+  }
+
+  tp = tftp_prep_mbuf_data(spt, m);
+
+  tp->tp_op = htons(TFTP_ERROR);
+  tp->x.tp_error.tp_error_code = htons(errorcode);
+  slirp_pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg);
+
+  m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + 3 + strlen(msg)
+             - sizeof(struct udphdr);
+  tftp_udp_output(spt, m, recv_tp);
+
+out:
+  tftp_session_terminate(spt);
+}
+
+static void tftp_send_next_block(struct tftp_session *spt,
+                                 struct tftp_t *recv_tp)
+{
+  struct mbuf *m;
+  struct tftp_t *tp;
+  int nobytes;
+
+  m = m_get(spt->slirp);
+
+  if (!m) {
+    return;
+  }
+
+  tp = tftp_prep_mbuf_data(spt, m);
+
+  tp->tp_op = htons(TFTP_DATA);
+  tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff);
+
+  nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf,
+                           spt->block_size);
+
+  if (nobytes < 0) {
+    m_free(m);
+
+    /* send "file not found" error back */
+
+    tftp_send_error(spt, 1, "File not found", tp);
+
+    return;
+  }
+
+  m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX - nobytes)
+             - sizeof(struct udphdr);
+  tftp_udp_output(spt, m, recv_tp);
+
+  if (nobytes == spt->block_size) {
+    tftp_session_update(spt);
+  }
+  else {
+    tftp_session_terminate(spt);
+  }
+
+  spt->block_nr++;
+}
+
+static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
+                            struct tftp_t *tp, int pktlen)
+{
+  struct tftp_session *spt;
+  int s, k;
+  size_t prefix_len;
+  char *req_fname;
+  const char *option_name[2];
+  uint32_t option_value[2];
+  int nb_options = 0;
+
+  /* check if a session already exists and if so terminate it */
+  s = tftp_session_find(slirp, srcsas, tp);
+  if (s >= 0) {
+    tftp_session_terminate(&slirp->tftp_sessions[s]);
+  }
+
+  s = tftp_session_allocate(slirp, srcsas, tp);
+
+  if (s < 0) {
+    return;
+  }
+
+  spt = &slirp->tftp_sessions[s];
+
+  /* unspecified prefix means service disabled */
+  if (!slirp->tftp_prefix) {
+      tftp_send_error(spt, 2, "Access violation", tp);
+      return;
+  }
+
+  /* skip header fields */
+  k = 0;
+  pktlen -= offsetof(struct tftp_t, x.tp_buf);
+
+  /* prepend tftp_prefix */
+  prefix_len = strlen(slirp->tftp_prefix);
+  spt->filename = g_malloc(prefix_len + TFTP_FILENAME_MAX + 2);
+  memcpy(spt->filename, slirp->tftp_prefix, prefix_len);
+  spt->filename[prefix_len] = '/';
+
+  /* get name */
+  req_fname = spt->filename + prefix_len + 1;
+
+  while (1) {
+    if (k >= TFTP_FILENAME_MAX || k >= pktlen) {
+      tftp_send_error(spt, 2, "Access violation", tp);
+      return;
+    }
+    req_fname[k] = tp->x.tp_buf[k];
+    if (req_fname[k++] == '\0') {
+      break;
+    }
+  }
+
+  DEBUG_TFTP("tftp rrq file: %s", req_fname);
+
+  /* check mode */
+  if ((pktlen - k) < 6) {
+    tftp_send_error(spt, 2, "Access violation", tp);
+    return;
+  }
+
+  if (strcasecmp(&tp->x.tp_buf[k], "octet") != 0) {
+      tftp_send_error(spt, 4, "Unsupported transfer mode", tp);
+      return;
+  }
+
+  k += 6; /* skipping octet */
+
+  /* do sanity checks on the filename */
+  if (!strncmp(req_fname, "../", 3) ||
+      req_fname[strlen(req_fname) - 1] == '/' ||
+      strstr(req_fname, "/../")) {
+      tftp_send_error(spt, 2, "Access violation", tp);
+      return;
+  }
+
+  /* check if the file exists */
+  if (tftp_read_data(spt, 0, NULL, 0) < 0) {
+      tftp_send_error(spt, 1, "File not found", tp);
+      return;
+  }
+
+  if (tp->x.tp_buf[pktlen - 1] != 0) {
+      tftp_send_error(spt, 2, "Access violation", tp);
+      return;
+  }
+
+  while (k < pktlen && nb_options < G_N_ELEMENTS(option_name)) {
+      const char *key, *value;
+
+      key = &tp->x.tp_buf[k];
+      k += strlen(key) + 1;
+
+      if (k >= pktlen) {
+         tftp_send_error(spt, 2, "Access violation", tp);
+         return;
+      }
+
+      value = &tp->x.tp_buf[k];
+      k += strlen(value) + 1;
+
+      if (strcasecmp(key, "tsize") == 0) {
+         int tsize = atoi(value);
+         struct stat stat_p;
+
+         if (tsize == 0) {
+             if (stat(spt->filename, &stat_p) == 0)
+                 tsize = stat_p.st_size;
+             else {
+                 tftp_send_error(spt, 1, "File not found", tp);
+                 return;
+             }
+         }
+
+          option_name[nb_options] = "tsize";
+          option_value[nb_options] = tsize;
+          nb_options++;
+      } else if (strcasecmp(key, "blksize") == 0) {
+          int blksize = atoi(value);
+
+          /* Accept blksize up to our maximum size */
+          if (blksize > 0) {
+              spt->block_size = MIN(blksize, TFTP_BLOCKSIZE_MAX);
+              option_name[nb_options] = "blksize";
+              option_value[nb_options] = spt->block_size;
+              nb_options++;
+          }
+      }
+  }
+
+  if (nb_options > 0) {
+      assert(nb_options <= G_N_ELEMENTS(option_name));
+      tftp_send_oack(spt, option_name, option_value, nb_options, tp);
+      return;
+  }
+
+  spt->block_nr = 0;
+  tftp_send_next_block(spt, tp);
+}
+
+static void tftp_handle_ack(Slirp *slirp, struct sockaddr_storage *srcsas,
+                            struct tftp_t *tp, int pktlen)
+{
+  int s;
+
+  s = tftp_session_find(slirp, srcsas, tp);
+
+  if (s < 0) {
+    return;
+  }
+
+  tftp_send_next_block(&slirp->tftp_sessions[s], tp);
+}
+
+static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas,
+                              struct tftp_t *tp, int pktlen)
+{
+  int s;
+
+  s = tftp_session_find(slirp, srcsas, tp);
+
+  if (s < 0) {
+    return;
+  }
+
+  tftp_session_terminate(&slirp->tftp_sessions[s]);
+}
+
+void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m)
+{
+  struct tftp_t *tp = (struct tftp_t *)m->m_data;
+
+  switch(ntohs(tp->tp_op)) {
+  case TFTP_RRQ:
+    tftp_handle_rrq(m->slirp, srcsas, tp, m->m_len);
+    break;
+
+  case TFTP_ACK:
+    tftp_handle_ack(m->slirp, srcsas, tp, m->m_len);
+    break;
+
+  case TFTP_ERROR:
+    tftp_handle_error(m->slirp, srcsas, tp, m->m_len);
+    break;
+  }
+}
diff --git a/slirp/src/tftp.h b/slirp/src/tftp.h
new file mode 100644 (file)
index 0000000..a4c4a64
--- /dev/null
@@ -0,0 +1,51 @@
+/* tftp defines */
+
+#ifndef SLIRP_TFTP_H
+#define SLIRP_TFTP_H
+
+#define TFTP_SESSIONS_MAX 20
+
+#define TFTP_SERVER    69
+
+#define TFTP_RRQ    1
+#define TFTP_WRQ    2
+#define TFTP_DATA   3
+#define TFTP_ACK    4
+#define TFTP_ERROR  5
+#define TFTP_OACK   6
+
+#define TFTP_FILENAME_MAX 512
+#define TFTP_BLOCKSIZE_MAX 1428
+
+struct tftp_t {
+  struct udphdr udp;
+  uint16_t tp_op;
+  union {
+    struct {
+      uint16_t tp_block_nr;
+      uint8_t tp_buf[TFTP_BLOCKSIZE_MAX];
+    } tp_data;
+    struct {
+      uint16_t tp_error_code;
+      uint8_t tp_msg[TFTP_BLOCKSIZE_MAX];
+    } tp_error;
+    char tp_buf[TFTP_BLOCKSIZE_MAX + 2];
+  } x;
+} __attribute__((packed));
+
+struct tftp_session {
+    Slirp *slirp;
+    char *filename;
+    int fd;
+    uint16_t block_size;
+
+    struct sockaddr_storage client_addr;
+    uint16_t client_port;
+    uint32_t block_nr;
+
+    int timestamp;
+};
+
+void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m);
+
+#endif
diff --git a/slirp/src/udp.c b/slirp/src/udp.c
new file mode 100644 (file)
index 0000000..fa9f4a0
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 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. 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.
+ *
+ *     @(#)udp_usrreq.c        8.4 (Berkeley) 1/21/94
+ * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp
+ */
+
+/*
+ * Changes and additions relating to SLiRP
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include "slirp.h"
+#include "ip_icmp.h"
+
+static uint8_t udp_tos(struct socket *so);
+
+void
+udp_init(Slirp *slirp)
+{
+    slirp->udb.so_next = slirp->udb.so_prev = &slirp->udb;
+    slirp->udp_last_so = &slirp->udb;
+}
+
+void udp_cleanup(Slirp *slirp)
+{
+    while (slirp->udb.so_next != &slirp->udb) {
+        udp_detach(slirp->udb.so_next);
+    }
+}
+
+/* m->m_data  points at ip packet header
+ * m->m_len   length ip packet
+ * ip->ip_len length data (IPDU)
+ */
+void
+udp_input(register struct mbuf *m, int iphlen)
+{
+       Slirp *slirp = m->slirp;
+       register struct ip *ip;
+       register struct udphdr *uh;
+       int len;
+       struct ip save_ip;
+       struct socket *so;
+       struct sockaddr_storage lhost;
+       struct sockaddr_in *lhost4;
+
+       DEBUG_CALL("udp_input");
+       DEBUG_ARG("m = %p", m);
+       DEBUG_ARG("iphlen = %d", iphlen);
+
+       /*
+        * Strip IP options, if any; should skip this,
+        * make available to user, and use on returned packets,
+        * but we don't yet have a way to check the checksum
+        * with options still present.
+        */
+       if(iphlen > sizeof(struct ip)) {
+               ip_stripoptions(m, (struct mbuf *)0);
+               iphlen = sizeof(struct ip);
+       }
+
+       /*
+        * Get IP and UDP header together in first mbuf.
+        */
+       ip = mtod(m, struct ip *);
+       uh = (struct udphdr *)((char *)ip + iphlen);
+
+       /*
+        * Make mbuf data length reflect UDP length.
+        * If not enough data to reflect UDP length, drop.
+        */
+       len = ntohs((uint16_t)uh->uh_ulen);
+
+       if (ip->ip_len != len) {
+               if (len > ip->ip_len) {
+                       goto bad;
+               }
+               m_adj(m, len - ip->ip_len);
+               ip->ip_len = len;
+       }
+
+       /*
+        * Save a copy of the IP header in case we want restore it
+        * for sending an ICMP error message in response.
+        */
+       save_ip = *ip;
+       save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */
+
+       /*
+        * Checksum extended UDP header and data.
+        */
+       if (uh->uh_sum) {
+      memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
+         ((struct ipovly *)ip)->ih_x1 = 0;
+         ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
+         if(cksum(m, len + sizeof(struct ip))) {
+           goto bad;
+         }
+       }
+
+       lhost.ss_family = AF_INET;
+       lhost4 = (struct sockaddr_in *) &lhost;
+       lhost4->sin_addr = ip->ip_src;
+       lhost4->sin_port = uh->uh_sport;
+
+        /*
+         *  handle DHCP/BOOTP
+         */
+        if (ntohs(uh->uh_dport) == BOOTP_SERVER &&
+            (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
+             ip->ip_dst.s_addr == 0xffffffff)) {
+                bootp_input(m);
+                goto bad;
+            }
+
+        /*
+         *  handle TFTP
+         */
+        if (ntohs(uh->uh_dport) == TFTP_SERVER &&
+            ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
+            m->m_data += iphlen;
+            m->m_len -= iphlen;
+            tftp_input(&lhost, m);
+            m->m_data -= iphlen;
+            m->m_len += iphlen;
+            goto bad;
+        }
+
+        if (slirp->restricted) {
+            goto bad;
+        }
+
+       /*
+        * Locate pcb for datagram.
+        */
+       so = solookup(&slirp->udp_last_so, &slirp->udb, &lhost, NULL);
+
+       if (so == NULL) {
+         /*
+          * If there's no socket for this packet,
+          * create one
+          */
+         so = socreate(slirp);
+         if (udp_attach(so, AF_INET) == -1) {
+           DEBUG_MISC(" udp_attach errno = %d-%s", errno, strerror(errno));
+           sofree(so);
+           goto bad;
+         }
+
+         /*
+          * Setup fields
+          */
+         so->so_lfamily = AF_INET;
+         so->so_laddr = ip->ip_src;
+         so->so_lport = uh->uh_sport;
+
+         if ((so->so_iptos = udp_tos(so)) == 0)
+           so->so_iptos = ip->ip_tos;
+
+         /*
+          * XXXXX Here, check if it's in udpexec_list,
+          * and if it is, do the fork_exec() etc.
+          */
+       }
+
+        so->so_ffamily = AF_INET;
+        so->so_faddr = ip->ip_dst; /* XXX */
+        so->so_fport = uh->uh_dport; /* XXX */
+
+       iphlen += sizeof(struct udphdr);
+       m->m_len -= iphlen;
+       m->m_data += iphlen;
+
+       /*
+        * Now we sendto() the packet.
+        */
+       if(sosendto(so,m) == -1) {
+         m->m_len += iphlen;
+         m->m_data -= iphlen;
+         *ip=save_ip;
+         DEBUG_MISC("udp tx errno = %d-%s", errno, strerror(errno));
+         icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0,
+                         strerror(errno));
+         goto bad;
+       }
+
+       m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
+
+       /* restore the orig mbuf packet */
+       m->m_len += iphlen;
+       m->m_data -= iphlen;
+       *ip=save_ip;
+       so->so_m=m;         /* ICMP backup */
+
+       return;
+bad:
+       m_free(m);
+}
+
+int udp_output(struct socket *so, struct mbuf *m,
+                struct sockaddr_in *saddr, struct sockaddr_in *daddr,
+                int iptos)
+{
+       register struct udpiphdr *ui;
+       int error = 0;
+
+       DEBUG_CALL("udp_output");
+       DEBUG_ARG("so = %p", so);
+       DEBUG_ARG("m = %p", m);
+       DEBUG_ARG("saddr = %s", inet_ntoa(saddr->sin_addr));
+       DEBUG_ARG("daddr = %s", inet_ntoa(daddr->sin_addr));
+
+       /*
+        * Adjust for header
+        */
+       m->m_data -= sizeof(struct udpiphdr);
+       m->m_len += sizeof(struct udpiphdr);
+
+       /*
+        * Fill in mbuf with extended UDP header
+        * and addresses and length put into network format.
+        */
+       ui = mtod(m, struct udpiphdr *);
+    memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
+       ui->ui_x1 = 0;
+       ui->ui_pr = IPPROTO_UDP;
+       ui->ui_len = htons(m->m_len - sizeof(struct ip));
+       /* XXXXX Check for from-one-location sockets, or from-any-location sockets */
+        ui->ui_src = saddr->sin_addr;
+       ui->ui_dst = daddr->sin_addr;
+       ui->ui_sport = saddr->sin_port;
+       ui->ui_dport = daddr->sin_port;
+       ui->ui_ulen = ui->ui_len;
+
+       /*
+        * Stuff checksum and output datagram.
+        */
+       ui->ui_sum = 0;
+       if ((ui->ui_sum = cksum(m, m->m_len)) == 0)
+               ui->ui_sum = 0xffff;
+       ((struct ip *)ui)->ip_len = m->m_len;
+
+       ((struct ip *)ui)->ip_ttl = IPDEFTTL;
+       ((struct ip *)ui)->ip_tos = iptos;
+
+       error = ip_output(so, m);
+
+       return (error);
+}
+
+int
+udp_attach(struct socket *so, unsigned short af)
+{
+  so->s = slirp_socket(af, SOCK_DGRAM, 0);
+  if (so->s != -1) {
+    so->so_expire = curtime + SO_EXPIRE;
+    insque(so, &so->slirp->udb);
+  }
+  return(so->s);
+}
+
+void
+udp_detach(struct socket *so)
+{
+       so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
+       closesocket(so->s);
+       sofree(so);
+}
+
+static const struct tos_t udptos[] = {
+       {0, 53, IPTOS_LOWDELAY, 0},                     /* DNS */
+       {0, 0, 0, 0}
+};
+
+static uint8_t
+udp_tos(struct socket *so)
+{
+       int i = 0;
+
+       while(udptos[i].tos) {
+               if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
+                   (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
+                       so->so_emu = udptos[i].emu;
+                       return udptos[i].tos;
+               }
+               i++;
+       }
+
+       return 0;
+}
+
+struct socket *
+udp_listen(Slirp *slirp, uint32_t haddr, unsigned hport, uint32_t laddr,
+           unsigned lport, int flags)
+{
+        /* TODO: IPv6 */
+       struct sockaddr_in addr;
+       struct socket *so;
+       socklen_t addrlen = sizeof(struct sockaddr_in);
+
+       so = socreate(slirp);
+       so->s = slirp_socket(AF_INET,SOCK_DGRAM,0);
+        if (so->s < 0) {
+            sofree(so);
+            return NULL;
+        }
+       so->so_expire = curtime + SO_EXPIRE;
+       insque(so, &slirp->udb);
+
+       addr.sin_family = AF_INET;
+       addr.sin_addr.s_addr = haddr;
+       addr.sin_port = hport;
+
+       if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
+               udp_detach(so);
+               return NULL;
+       }
+       slirp_socket_set_fast_reuse(so->s);
+
+       getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
+       so->fhost.sin = addr;
+       sotranslate_accept(so);
+       so->so_lfamily = AF_INET;
+       so->so_lport = lport;
+       so->so_laddr.s_addr = laddr;
+       if (flags != SS_FACCEPTONCE)
+          so->so_expire = 0;
+
+       so->so_state &= SS_PERSISTENT_MASK;
+       so->so_state |= SS_ISFCONNECTED | flags;
+
+       return so;
+}
diff --git a/slirp/src/udp.h b/slirp/src/udp.h
new file mode 100644 (file)
index 0000000..3d29504
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 1982, 1986, 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. 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.
+ *
+ *     @(#)udp.h       8.1 (Berkeley) 6/10/93
+ * udp.h,v 1.3 1994/08/21 05:27:41 paul Exp
+ */
+
+#ifndef UDP_H
+#define UDP_H
+
+#define UDP_TTL 0x60
+#define UDP_UDPDATALEN 16192
+
+/*
+ * Udp protocol header.
+ * Per RFC 768, September, 1981.
+ */
+struct udphdr {
+    uint16_t uh_sport;          /* source port */
+    uint16_t uh_dport;          /* destination port */
+    int16_t  uh_ulen;           /* udp length */
+    uint16_t uh_sum;            /* udp checksum */
+};
+
+/*
+ * UDP kernel structures and variables.
+ */
+struct udpiphdr {
+               struct  ipovly ui_i;            /* overlaid ip structure */
+               struct  udphdr ui_u;            /* udp header */
+};
+#define ui_mbuf         ui_i.ih_mbuf.mptr
+#define ui_x1           ui_i.ih_x1
+#define ui_pr           ui_i.ih_pr
+#define ui_len          ui_i.ih_len
+#define ui_src          ui_i.ih_src
+#define ui_dst          ui_i.ih_dst
+#define ui_sport        ui_u.uh_sport
+#define ui_dport        ui_u.uh_dport
+#define ui_ulen         ui_u.uh_ulen
+#define ui_sum          ui_u.uh_sum
+
+/*
+ * Names for UDP sysctl objects
+ */
+#define UDPCTL_CHECKSUM         1       /* checksum UDP packets */
+#define UDPCTL_MAXID            2
+
+struct mbuf;
+
+void udp_init(Slirp *);
+void udp_cleanup(Slirp *);
+void udp_input(register struct mbuf *, int);
+int udp_attach(struct socket *, unsigned short af);
+void udp_detach(struct socket *);
+struct socket * udp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned,
+                           int);
+int udp_output(struct socket *so, struct mbuf *m,
+                struct sockaddr_in *saddr, struct sockaddr_in *daddr,
+                int iptos);
+
+void udp6_input(register struct mbuf *);
+int udp6_output(struct socket *so, struct mbuf *m,
+                struct sockaddr_in6 *saddr, struct sockaddr_in6 *daddr);
+
+#endif
diff --git a/slirp/src/udp6.c b/slirp/src/udp6.c
new file mode 100644 (file)
index 0000000..be5cba1
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron
+ */
+
+#include "slirp.h"
+#include "udp.h"
+#include "dhcpv6.h"
+
+void udp6_input(struct mbuf *m)
+{
+    Slirp *slirp = m->slirp;
+    struct ip6 *ip, save_ip;
+    struct udphdr *uh;
+    int iphlen = sizeof(struct ip6);
+    int len;
+    struct socket *so;
+    struct sockaddr_in6 lhost;
+
+    DEBUG_CALL("udp6_input");
+    DEBUG_ARG("m = %p", m);
+
+    if (slirp->restricted) {
+        goto bad;
+    }
+
+    ip = mtod(m, struct ip6 *);
+    m->m_len -= iphlen;
+    m->m_data += iphlen;
+    uh = mtod(m, struct udphdr *);
+    m->m_len += iphlen;
+    m->m_data -= iphlen;
+
+    if (ip6_cksum(m)) {
+        goto bad;
+    }
+
+    len = ntohs((uint16_t)uh->uh_ulen);
+
+    /*
+     * Make mbuf data length reflect UDP length.
+     * If not enough data to reflect UDP length, drop.
+     */
+    if (ntohs(ip->ip_pl) != len) {
+        if (len > ntohs(ip->ip_pl)) {
+            goto bad;
+        }
+        m_adj(m, len - ntohs(ip->ip_pl));
+        ip->ip_pl = htons(len);
+    }
+
+    /*
+     * Save a copy of the IP header in case we want restore it
+     * for sending an ICMP error message in response.
+     */
+    save_ip = *ip;
+
+    /* Locate pcb for datagram. */
+    lhost.sin6_family = AF_INET6;
+    lhost.sin6_addr = ip->ip_src;
+    lhost.sin6_port = uh->uh_sport;
+
+    /* handle DHCPv6 */
+    if (ntohs(uh->uh_dport) == DHCPV6_SERVER_PORT &&
+        (in6_equal(&ip->ip_dst, &slirp->vhost_addr6) ||
+         in6_dhcp_multicast(&ip->ip_dst))) {
+        m->m_data += iphlen;
+        m->m_len -= iphlen;
+        dhcpv6_input(&lhost, m);
+        m->m_data -= iphlen;
+        m->m_len += iphlen;
+        goto bad;
+    }
+
+    /* handle TFTP */
+    if (ntohs(uh->uh_dport) == TFTP_SERVER &&
+        !memcmp(ip->ip_dst.s6_addr, slirp->vhost_addr6.s6_addr, 16)) {
+        m->m_data += iphlen;
+        m->m_len -= iphlen;
+        tftp_input((struct sockaddr_storage *)&lhost, m);
+        m->m_data -= iphlen;
+        m->m_len += iphlen;
+        goto bad;
+    }
+
+    so = solookup(&slirp->udp_last_so, &slirp->udb,
+                  (struct sockaddr_storage *) &lhost, NULL);
+
+    if (so == NULL) {
+        /* If there's no socket for this packet, create one. */
+        so = socreate(slirp);
+        if (udp_attach(so, AF_INET6) == -1) {
+            DEBUG_MISC(" udp6_attach errno = %d-%s", errno, strerror(errno));
+            sofree(so);
+            goto bad;
+        }
+
+        /* Setup fields */
+        so->so_lfamily = AF_INET6;
+        so->so_laddr6 = ip->ip_src;
+        so->so_lport6 = uh->uh_sport;
+    }
+
+    so->so_ffamily = AF_INET6;
+    so->so_faddr6 = ip->ip_dst; /* XXX */
+    so->so_fport6 = uh->uh_dport; /* XXX */
+
+    iphlen += sizeof(struct udphdr);
+    m->m_len -= iphlen;
+    m->m_data += iphlen;
+
+    /*
+     * Now we sendto() the packet.
+     */
+    if (sosendto(so, m) == -1) {
+        m->m_len += iphlen;
+        m->m_data -= iphlen;
+        *ip = save_ip;
+        DEBUG_MISC("udp tx errno = %d-%s", errno, strerror(errno));
+        icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
+        goto bad;
+    }
+
+    m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
+
+    /* restore the orig mbuf packet */
+    m->m_len += iphlen;
+    m->m_data -= iphlen;
+    *ip = save_ip;
+    so->so_m = m;
+
+    return;
+bad:
+    m_free(m);
+}
+
+int udp6_output(struct socket *so, struct mbuf *m,
+        struct sockaddr_in6 *saddr, struct sockaddr_in6 *daddr)
+{
+    struct ip6 *ip;
+    struct udphdr *uh;
+
+    DEBUG_CALL("udp6_output");
+    DEBUG_ARG("so = %p", so);
+    DEBUG_ARG("m = %p", m);
+
+    /* adjust for header */
+    m->m_data -= sizeof(struct udphdr);
+    m->m_len += sizeof(struct udphdr);
+    uh = mtod(m, struct udphdr *);
+    m->m_data -= sizeof(struct ip6);
+    m->m_len += sizeof(struct ip6);
+    ip = mtod(m, struct ip6 *);
+
+    /* Build IP header */
+    ip->ip_pl = htons(m->m_len - sizeof(struct ip6));
+    ip->ip_nh = IPPROTO_UDP;
+    ip->ip_src = saddr->sin6_addr;
+    ip->ip_dst = daddr->sin6_addr;
+
+    /* Build UDP header */
+    uh->uh_sport = saddr->sin6_port;
+    uh->uh_dport = daddr->sin6_port;
+    uh->uh_ulen = ip->ip_pl;
+    uh->uh_sum = 0;
+    uh->uh_sum = ip6_cksum(m);
+    if (uh->uh_sum == 0) {
+        uh->uh_sum = 0xffff;
+    }
+
+    return ip6_output(so, m, 0);
+}
diff --git a/slirp/src/util.c b/slirp/src/util.c
new file mode 100644 (file)
index 0000000..5ec2fa8
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * util.c (mostly based on QEMU os-win32.c)
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010-2016 Red Hat, Inc.
+ *
+ * QEMU library functions for win32 which are shared between QEMU and
+ * the QEMU tools.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "util.h"
+
+#include <glib.h>
+#include <fcntl.h>
+#include <stdint.h>
+
+#if defined(_WIN32)
+int slirp_inet_aton(const char *cp, struct in_addr *ia)
+{
+    uint32_t addr = inet_addr(cp);
+    if (addr == 0xffffffff) {
+        return 0;
+    }
+    ia->s_addr = addr;
+    return 1;
+}
+#endif
+
+void slirp_set_nonblock(int fd)
+{
+#ifndef _WIN32
+    int f;
+    f = fcntl(fd, F_GETFL);
+    assert(f != -1);
+    f = fcntl(fd, F_SETFL, f | O_NONBLOCK);
+    assert(f != -1);
+#else
+    unsigned long opt = 1;
+    ioctlsocket(fd, FIONBIO, &opt);
+#endif
+}
+
+static void slirp_set_cloexec(int fd)
+{
+#ifndef _WIN32
+    int f;
+    f = fcntl(fd, F_GETFD);
+    assert(f != -1);
+    f = fcntl(fd, F_SETFD, f | FD_CLOEXEC);
+    assert(f != -1);
+#endif
+}
+
+/*
+ * Opens a socket with FD_CLOEXEC set
+ */
+int slirp_socket(int domain, int type, int protocol)
+{
+    int ret;
+
+#ifdef SOCK_CLOEXEC
+    ret = socket(domain, type | SOCK_CLOEXEC, protocol);
+    if (ret != -1 || errno != EINVAL) {
+        return ret;
+    }
+#endif
+    ret = socket(domain, type, protocol);
+    if (ret >= 0) {
+        slirp_set_cloexec(ret);
+    }
+
+    return ret;
+}
+
+#ifdef _WIN32
+static int socket_error(void)
+{
+    switch (WSAGetLastError()) {
+    case 0:
+        return 0;
+    case WSAEINTR:
+        return EINTR;
+    case WSAEINVAL:
+        return EINVAL;
+    case WSA_INVALID_HANDLE:
+        return EBADF;
+    case WSA_NOT_ENOUGH_MEMORY:
+        return ENOMEM;
+    case WSA_INVALID_PARAMETER:
+        return EINVAL;
+    case WSAENAMETOOLONG:
+        return ENAMETOOLONG;
+    case WSAENOTEMPTY:
+        return ENOTEMPTY;
+    case WSAEWOULDBLOCK:
+         /* not using EWOULDBLOCK as we don't want code to have
+          * to check both EWOULDBLOCK and EAGAIN */
+        return EAGAIN;
+    case WSAEINPROGRESS:
+        return EINPROGRESS;
+    case WSAEALREADY:
+        return EALREADY;
+    case WSAENOTSOCK:
+        return ENOTSOCK;
+    case WSAEDESTADDRREQ:
+        return EDESTADDRREQ;
+    case WSAEMSGSIZE:
+        return EMSGSIZE;
+    case WSAEPROTOTYPE:
+        return EPROTOTYPE;
+    case WSAENOPROTOOPT:
+        return ENOPROTOOPT;
+    case WSAEPROTONOSUPPORT:
+        return EPROTONOSUPPORT;
+    case WSAEOPNOTSUPP:
+        return EOPNOTSUPP;
+    case WSAEAFNOSUPPORT:
+        return EAFNOSUPPORT;
+    case WSAEADDRINUSE:
+        return EADDRINUSE;
+    case WSAEADDRNOTAVAIL:
+        return EADDRNOTAVAIL;
+    case WSAENETDOWN:
+        return ENETDOWN;
+    case WSAENETUNREACH:
+        return ENETUNREACH;
+    case WSAENETRESET:
+        return ENETRESET;
+    case WSAECONNABORTED:
+        return ECONNABORTED;
+    case WSAECONNRESET:
+        return ECONNRESET;
+    case WSAENOBUFS:
+        return ENOBUFS;
+    case WSAEISCONN:
+        return EISCONN;
+    case WSAENOTCONN:
+        return ENOTCONN;
+    case WSAETIMEDOUT:
+        return ETIMEDOUT;
+    case WSAECONNREFUSED:
+        return ECONNREFUSED;
+    case WSAELOOP:
+        return ELOOP;
+    case WSAEHOSTUNREACH:
+        return EHOSTUNREACH;
+    default:
+        return EIO;
+    }
+}
+
+#undef ioctlsocket
+int slirp_ioctlsocket_wrap(int fd, int req, void *val)
+{
+    int ret;
+    ret = ioctlsocket(fd, req, val);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+#undef closesocket
+int slirp_closesocket_wrap(int fd)
+{
+    int ret;
+    ret = closesocket(fd);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+#undef connect
+int slirp_connect_wrap(int sockfd, const struct sockaddr *addr, int addrlen)
+{
+    int ret;
+    ret = connect(sockfd, addr, addrlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+#undef listen
+int slirp_listen_wrap(int sockfd, int backlog)
+{
+    int ret;
+    ret = listen(sockfd, backlog);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+#undef bind
+int slirp_bind_wrap(int sockfd, const struct sockaddr *addr, int addrlen)
+{
+    int ret;
+    ret = bind(sockfd, addr, addrlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+#undef socket
+int slirp_socket_wrap(int domain, int type, int protocol)
+{
+    int ret;
+    ret = socket(domain, type, protocol);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+#undef accept
+int slirp_accept_wrap(int sockfd, struct sockaddr *addr, int *addrlen)
+{
+    int ret;
+    ret = accept(sockfd, addr, addrlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+#undef shutdown
+int slirp_shutdown_wrap(int sockfd, int how)
+{
+    int ret;
+    ret = shutdown(sockfd, how);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+#undef getsockopt
+int slirp_getsockopt_wrap(int sockfd, int level, int optname,
+                          void *optval, int *optlen)
+{
+    int ret;
+    ret = getsockopt(sockfd, level, optname, optval, optlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+#undef setsockopt
+int slirp_setsockopt_wrap(int sockfd, int level, int optname,
+                          const void *optval, int optlen)
+{
+    int ret;
+    ret = setsockopt(sockfd, level, optname, optval, optlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+#undef getpeername
+int slirp_getpeername_wrap(int sockfd, struct sockaddr *addr,
+                           int *addrlen)
+{
+    int ret;
+    ret = getpeername(sockfd, addr, addrlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+#undef getsockname
+int slirp_getsockname_wrap(int sockfd, struct sockaddr *addr,
+                           int *addrlen)
+{
+    int ret;
+    ret = getsockname(sockfd, addr, addrlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+#undef send
+ssize_t slirp_send_wrap(int sockfd, const void *buf, size_t len, int flags)
+{
+    int ret;
+    ret = send(sockfd, buf, len, flags);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+#undef sendto
+ssize_t slirp_sendto_wrap(int sockfd, const void *buf, size_t len, int flags,
+                     const struct sockaddr *addr, int addrlen)
+{
+    int ret;
+    ret = sendto(sockfd, buf, len, flags, addr, addrlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+#undef recv
+ssize_t slirp_recv_wrap(int sockfd, void *buf, size_t len, int flags)
+{
+    int ret;
+    ret = recv(sockfd, buf, len, flags);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+
+#undef recvfrom
+ssize_t slirp_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags,
+                            struct sockaddr *addr, int *addrlen)
+{
+    int ret;
+    ret = recvfrom(sockfd, buf, len, flags, addr, addrlen);
+    if (ret < 0) {
+        errno = socket_error();
+    }
+    return ret;
+}
+#endif /* WIN32 */
+
+void slirp_pstrcpy(char *buf, int buf_size, const char *str)
+{
+    int c;
+    char *q = buf;
+
+    if (buf_size <= 0)
+        return;
+
+    for(;;) {
+        c = *str++;
+        if (c == 0 || q >= buf + buf_size - 1)
+            break;
+        *q++ = c;
+    }
+    *q = '\0';
+}
diff --git a/slirp/src/util.h b/slirp/src/util.h
new file mode 100644 (file)
index 0000000..e94ee4e
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010-2019 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef UTIL_H_
+#define UTIL_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#else
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#endif
+
+#if defined(_WIN32)
+# define SLIRP_PACKED __attribute__((gcc_struct, packed))
+#else
+# define SLIRP_PACKED __attribute__((packed))
+#endif
+
+#ifndef DIV_ROUND_UP
+#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+#endif
+
+#ifndef container_of
+#define container_of(ptr, type, member) __extension__ ({    \
+    void *__mptr = (void *)(ptr);               \
+    ((type *)(__mptr - offsetof(type, member))); })
+#endif
+
+#if defined(_WIN32) /* CONFIG_IOVEC */
+# if !defined(IOV_MAX) /* XXX: to avoid duplicate with QEMU osdep.h */
+struct iovec {
+    void *iov_base;
+    size_t iov_len;
+};
+# endif
+#else
+#include <sys/uio.h>
+#endif
+
+#define SCALE_MS 1000000
+
+#define ETH_ALEN    6
+#define ETH_HLEN    14
+#define ETH_P_IP                  (0x0800)      /* Internet Protocol packet  */
+#define ETH_P_ARP                 (0x0806)      /* Address Resolution packet */
+#define ETH_P_IPV6                (0x86dd)
+#define ETH_P_VLAN                (0x8100)
+#define ETH_P_DVLAN               (0x88a8)
+#define ETH_P_NCSI                (0x88f8)
+#define ETH_P_UNKNOWN             (0xffff)
+
+/* FIXME: remove me when made standalone */
+#ifdef _WIN32
+#undef accept
+#undef bind
+#undef closesocket
+#undef connect
+#undef getpeername
+#undef getsockname
+#undef getsockopt
+#undef ioctlsocket
+#undef listen
+#undef recv
+#undef recvfrom
+#undef send
+#undef sendto
+#undef setsockopt
+#undef shutdown
+#undef socket
+#endif
+
+#ifdef _WIN32
+#define connect slirp_connect_wrap
+int slirp_connect_wrap(int fd, const struct sockaddr *addr, int addrlen);
+#define listen slirp_listen_wrap
+int slirp_listen_wrap(int fd, int backlog);
+#define bind slirp_bind_wrap
+int slirp_bind_wrap(int fd, const struct sockaddr *addr, int addrlen);
+#define socket slirp_socket_wrap
+int slirp_socket_wrap(int domain, int type, int protocol);
+#define accept slirp_accept_wrap
+int slirp_accept_wrap(int fd, struct sockaddr *addr, int *addrlen);
+#define shutdown slirp_shutdown_wrap
+int slirp_shutdown_wrap(int fd, int how);
+#define getpeername slirp_getpeername_wrap
+int slirp_getpeername_wrap(int fd, struct sockaddr *addr, int *addrlen);
+#define getsockname slirp_getsockname_wrap
+int slirp_getsockname_wrap(int fd, struct sockaddr *addr, int *addrlen);
+#define send slirp_send_wrap
+ssize_t slirp_send_wrap(int fd, const void *buf, size_t len, int flags);
+#define sendto slirp_sendto_wrap
+ssize_t slirp_sendto_wrap(int fd, const void *buf, size_t len, int flags,
+                          const struct sockaddr *dest_addr, int addrlen);
+#define recv slirp_recv_wrap
+ssize_t slirp_recv_wrap(int fd, void *buf, size_t len, int flags);
+#define recvfrom slirp_recvfrom_wrap
+ssize_t slirp_recvfrom_wrap(int fd, void *buf, size_t len, int flags,
+                            struct sockaddr *src_addr, int *addrlen);
+#define closesocket slirp_closesocket_wrap
+int slirp_closesocket_wrap(int fd);
+#define ioctlsocket slirp_ioctlsocket_wrap
+int slirp_ioctlsocket_wrap(int fd, int req, void *val);
+#define getsockopt slirp_getsockopt_wrap
+int slirp_getsockopt_wrap(int sockfd, int level, int optname,
+                     void *optval, int *optlen);
+#define setsockopt slirp_setsockopt_wrap
+int slirp_setsockopt_wrap(int sockfd, int level, int optname,
+                          const void *optval, int optlen);
+#define inet_aton slirp_inet_aton
+int slirp_inet_aton(const char *cp, struct in_addr *ia);
+#else
+#define closesocket(s) close(s)
+#define ioctlsocket(s, r, v) ioctl(s, r, v)
+#endif
+
+int slirp_socket(int domain, int type, int protocol);
+void slirp_set_nonblock(int fd);
+
+static inline int slirp_socket_set_nodelay(int fd)
+{
+    int v = 1;
+    return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
+}
+
+static inline int slirp_socket_set_fast_reuse(int fd)
+{
+#ifndef _WIN32
+    int v = 1;
+    return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v));
+#else
+    /* Enabling the reuse of an endpoint that was used by a socket still in
+     * TIME_WAIT state is usually performed by setting SO_REUSEADDR. On Windows
+     * fast reuse is the default and SO_REUSEADDR does strange things. So we
+     * don't have to do anything here. More info can be found at:
+     * http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621.aspx */
+    return 0;
+#endif
+}
+
+void slirp_pstrcpy(char *buf, int buf_size, const char *str);
+
+#endif
diff --git a/slirp/src/vmstate.c b/slirp/src/vmstate.c
new file mode 100644 (file)
index 0000000..4d08b47
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * VMState interpreter
+ *
+ * Copyright (c) 2009-2018 Red Hat Inc
+ *
+ * Authors:
+ *  Juan Quintela <quintela@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <glib.h>
+
+#include "stream.h"
+#include "vmstate.h"
+
+static int get_nullptr(SlirpIStream *f, void *pv, size_t size,
+                       const VMStateField *field)
+{
+    if (slirp_istream_read_u8(f) == VMS_NULLPTR_MARKER) {
+        return  0;
+    }
+    g_warning("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
+    return -EINVAL;
+}
+
+static int put_nullptr(SlirpOStream *f, void *pv, size_t size,
+                       const VMStateField *field)
+
+{
+    if (pv == NULL) {
+        slirp_ostream_write_u8(f, VMS_NULLPTR_MARKER);
+        return 0;
+    }
+    g_warning("vmstate: put_nullptr must be called with pv == NULL");
+    return -EINVAL;
+}
+
+const VMStateInfo slirp_vmstate_info_nullptr = {
+    .name = "uint64",
+    .get  = get_nullptr,
+    .put  = put_nullptr,
+};
+
+/* 8 bit unsigned int */
+
+static int get_uint8(SlirpIStream *f, void *pv, size_t size, const VMStateField *field)
+{
+    uint8_t *v = pv;
+    *v = slirp_istream_read_u8(f);
+    return 0;
+}
+
+static int put_uint8(SlirpOStream *f, void *pv, size_t size, const VMStateField *field)
+{
+    uint8_t *v = pv;
+    slirp_ostream_write_u8(f, *v);
+    return 0;
+}
+
+const VMStateInfo slirp_vmstate_info_uint8 = {
+    .name = "uint8",
+    .get  = get_uint8,
+    .put  = put_uint8,
+};
+
+/* 16 bit unsigned int */
+
+static int get_uint16(SlirpIStream *f, void *pv, size_t size,
+                      const VMStateField *field)
+{
+    uint16_t *v = pv;
+    *v = slirp_istream_read_u16(f);
+    return 0;
+}
+
+static int put_uint16(SlirpOStream *f, void *pv, size_t size,
+                      const VMStateField *field)
+{
+    uint16_t *v = pv;
+    slirp_ostream_write_u16(f, *v);
+    return 0;
+}
+
+const VMStateInfo slirp_vmstate_info_uint16 = {
+    .name = "uint16",
+    .get  = get_uint16,
+    .put  = put_uint16,
+};
+
+/* 32 bit unsigned int */
+
+static int get_uint32(SlirpIStream *f, void *pv, size_t size,
+                      const VMStateField *field)
+{
+    uint32_t *v = pv;
+    *v = slirp_istream_read_u32(f);
+    return 0;
+}
+
+static int put_uint32(SlirpOStream *f, void *pv, size_t size,
+                      const VMStateField *field)
+{
+    uint32_t *v = pv;
+    slirp_ostream_write_u32(f, *v);
+    return 0;
+}
+
+const VMStateInfo slirp_vmstate_info_uint32 = {
+    .name = "uint32",
+    .get  = get_uint32,
+    .put  = put_uint32,
+};
+
+/* 16 bit int */
+
+static int get_int16(SlirpIStream *f, void *pv, size_t size, const VMStateField *field)
+{
+    int16_t *v = pv;
+    *v = slirp_istream_read_i16(f);
+    return 0;
+}
+
+static int put_int16(SlirpOStream *f, void *pv, size_t size, const VMStateField *field)
+{
+    int16_t *v = pv;
+    slirp_ostream_write_i16(f, *v);
+    return 0;
+}
+
+const VMStateInfo slirp_vmstate_info_int16 = {
+    .name = "int16",
+    .get  = get_int16,
+    .put  = put_int16,
+};
+
+/* 32 bit int */
+
+static int get_int32(SlirpIStream *f, void *pv, size_t size, const VMStateField *field)
+{
+    int32_t *v = pv;
+    *v = slirp_istream_read_i32(f);
+    return 0;
+}
+
+static int put_int32(SlirpOStream *f, void *pv, size_t size, const VMStateField *field)
+{
+    int32_t *v = pv;
+    slirp_ostream_write_i32(f, *v);
+    return 0;
+}
+
+const VMStateInfo slirp_vmstate_info_int32 = {
+    .name = "int32",
+    .get  = get_int32,
+    .put  = put_int32,
+};
+
+/* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
+ * a temporary buffer and the pre_load/pre_save methods in the child vmsd
+ * copy stuff from the parent into the child and do calculations to fill
+ * in fields that don't really exist in the parent but need to be in the
+ * stream.
+ */
+static int get_tmp(SlirpIStream *f, void *pv, size_t size, const VMStateField *field)
+{
+    int ret;
+    const VMStateDescription *vmsd = field->vmsd;
+    int version_id = field->version_id;
+    void *tmp = g_malloc(size);
+
+    /* Writes the parent field which is at the start of the tmp */
+    *(void **)tmp = pv;
+    ret = slirp_vmstate_load_state(f, vmsd, tmp, version_id);
+    g_free(tmp);
+    return ret;
+}
+
+static int put_tmp(SlirpOStream *f, void *pv, size_t size, const VMStateField *field)
+{
+    const VMStateDescription *vmsd = field->vmsd;
+    void *tmp = g_malloc(size);
+    int ret;
+
+    /* Writes the parent field which is at the start of the tmp */
+    *(void **)tmp = pv;
+    ret = slirp_vmstate_save_state(f, vmsd, tmp);
+    g_free(tmp);
+
+    return ret;
+}
+
+const VMStateInfo slirp_vmstate_info_tmp = {
+    .name = "tmp",
+    .get = get_tmp,
+    .put = put_tmp,
+};
+
+/* uint8_t buffers */
+
+static int get_buffer(SlirpIStream *f, void *pv, size_t size,
+                      const VMStateField *field)
+{
+    slirp_istream_read(f, pv, size);
+    return 0;
+}
+
+static int put_buffer(SlirpOStream *f, void *pv, size_t size,
+                      const VMStateField *field)
+{
+    slirp_ostream_write(f, pv, size);
+    return 0;
+}
+
+const VMStateInfo slirp_vmstate_info_buffer = {
+    .name = "buffer",
+    .get  = get_buffer,
+    .put  = put_buffer,
+};
+
+static int vmstate_n_elems(void *opaque, const VMStateField *field)
+{
+    int n_elems = 1;
+
+    if (field->flags & VMS_ARRAY) {
+        n_elems = field->num;
+    } else if (field->flags & VMS_VARRAY_INT32) {
+        n_elems = *(int32_t *)(opaque + field->num_offset);
+    } else if (field->flags & VMS_VARRAY_UINT32) {
+        n_elems = *(uint32_t *)(opaque + field->num_offset);
+    } else if (field->flags & VMS_VARRAY_UINT16) {
+        n_elems = *(uint16_t *)(opaque + field->num_offset);
+    } else if (field->flags & VMS_VARRAY_UINT8) {
+        n_elems = *(uint8_t *)(opaque + field->num_offset);
+    }
+
+    if (field->flags & VMS_MULTIPLY_ELEMENTS) {
+        n_elems *= field->num;
+    }
+
+    return n_elems;
+}
+
+static int vmstate_size(void *opaque, const VMStateField *field)
+{
+    int size = field->size;
+
+    if (field->flags & VMS_VBUFFER) {
+        size = *(int32_t *)(opaque + field->size_offset);
+        if (field->flags & VMS_MULTIPLY) {
+            size *= field->size;
+        }
+    }
+
+    return size;
+}
+
+static int
+vmstate_save_state_v(SlirpOStream *f, const VMStateDescription *vmsd,
+                     void *opaque, int version_id)
+{
+    int ret = 0;
+    const VMStateField *field = vmsd->fields;
+
+    if (vmsd->pre_save) {
+        ret = vmsd->pre_save(opaque);
+        if (ret) {
+            g_warning("pre-save failed: %s", vmsd->name);
+            return ret;
+        }
+    }
+
+    while (field->name) {
+        if ((field->field_exists &&
+             field->field_exists(opaque, version_id)) ||
+            (!field->field_exists &&
+             field->version_id <= version_id)) {
+            void *first_elem = opaque + field->offset;
+            int i, n_elems = vmstate_n_elems(opaque, field);
+            int size = vmstate_size(opaque, field);
+
+            if (field->flags & VMS_POINTER) {
+                first_elem = *(void **)first_elem;
+                assert(first_elem || !n_elems || !size);
+            }
+            for (i = 0; i < n_elems; i++) {
+                void *curr_elem = first_elem + size * i;
+                ret = 0;
+
+                if (field->flags & VMS_ARRAY_OF_POINTER) {
+                    assert(curr_elem);
+                    curr_elem = *(void **)curr_elem;
+                }
+                if (!curr_elem && size) {
+                    /* if null pointer write placeholder and do not follow */
+                    assert(field->flags & VMS_ARRAY_OF_POINTER);
+                    ret = slirp_vmstate_info_nullptr.put(f, curr_elem, size, NULL);
+                } else if (field->flags & VMS_STRUCT) {
+                    ret = slirp_vmstate_save_state(f, field->vmsd, curr_elem);
+                } else if (field->flags & VMS_VSTRUCT) {
+                    ret = vmstate_save_state_v(f, field->vmsd, curr_elem,
+                                               field->struct_version_id);
+                } else {
+                    ret = field->info->put(f, curr_elem, size, field);
+                }
+                if (ret) {
+                    g_warning("Save of field %s/%s failed",
+                              vmsd->name, field->name);
+                    return ret;
+                }
+            }
+        } else {
+            if (field->flags & VMS_MUST_EXIST) {
+                g_warning("Output state validation failed: %s/%s",
+                          vmsd->name, field->name);
+                assert(!(field->flags & VMS_MUST_EXIST));
+            }
+        }
+        field++;
+    }
+
+    return 0;
+}
+
+int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd,
+                             void *opaque)
+{
+    return vmstate_save_state_v(f, vmsd, opaque, vmsd->version_id);
+}
+
+static void vmstate_handle_alloc(void *ptr, VMStateField *field, void *opaque)
+{
+    if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) {
+        size_t size = vmstate_size(opaque, field);
+        size *= vmstate_n_elems(opaque, field);
+        if (size) {
+            *(void **)ptr = g_malloc(size);
+        }
+    }
+}
+
+int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd,
+                             void *opaque, int version_id)
+{
+    VMStateField *field = vmsd->fields;
+    int ret = 0;
+
+    if (version_id > vmsd->version_id) {
+        g_warning("%s: incoming version_id %d is too new "
+                  "for local version_id %d",
+                  vmsd->name, version_id, vmsd->version_id);
+        return -EINVAL;
+    }
+    if (vmsd->pre_load) {
+        int ret = vmsd->pre_load(opaque);
+        if (ret) {
+            return ret;
+        }
+    }
+    while (field->name) {
+        if ((field->field_exists &&
+             field->field_exists(opaque, version_id)) ||
+            (!field->field_exists &&
+             field->version_id <= version_id)) {
+            void *first_elem = opaque + field->offset;
+            int i, n_elems = vmstate_n_elems(opaque, field);
+            int size = vmstate_size(opaque, field);
+
+            vmstate_handle_alloc(first_elem, field, opaque);
+            if (field->flags & VMS_POINTER) {
+                first_elem = *(void **)first_elem;
+                assert(first_elem || !n_elems || !size);
+            }
+            for (i = 0; i < n_elems; i++) {
+                void *curr_elem = first_elem + size * i;
+
+                if (field->flags & VMS_ARRAY_OF_POINTER) {
+                    curr_elem = *(void **)curr_elem;
+                }
+                if (!curr_elem && size) {
+                    /* if null pointer check placeholder and do not follow */
+                    assert(field->flags & VMS_ARRAY_OF_POINTER);
+                    ret = slirp_vmstate_info_nullptr.get(f, curr_elem, size, NULL);
+                } else if (field->flags & VMS_STRUCT) {
+                    ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem,
+                                             field->vmsd->version_id);
+                } else if (field->flags & VMS_VSTRUCT) {
+                    ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem,
+                                             field->struct_version_id);
+                } else {
+                    ret = field->info->get(f, curr_elem, size, field);
+                }
+                if (ret < 0) {
+                    g_warning("Failed to load %s:%s", vmsd->name,
+                              field->name);
+                    return ret;
+                }
+            }
+        } else if (field->flags & VMS_MUST_EXIST) {
+            g_warning("Input validation failed: %s/%s",
+                      vmsd->name, field->name);
+            return -1;
+        }
+        field++;
+    }
+    if (vmsd->post_load) {
+        ret = vmsd->post_load(opaque, version_id);
+    }
+    return ret;
+}
diff --git a/slirp/src/vmstate.h b/slirp/src/vmstate.h
new file mode 100644 (file)
index 0000000..cfa7b8c
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * QEMU migration/snapshot declarations
+ *
+ * Copyright (c) 2009-2011 Red Hat, Inc.
+ *
+ * Original author: Juan Quintela <quintela@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef VMSTATE_H_
+#define VMSTATE_H_
+
+#include <unistd.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include "slirp.h"
+#include "stream.h"
+
+#define stringify(s) tostring(s)
+#define tostring(s) #s
+
+typedef struct VMStateInfo VMStateInfo;
+typedef struct VMStateDescription VMStateDescription;
+typedef struct VMStateField VMStateField;
+
+int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd,
+                             void *opaque);
+int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd,
+                             void *opaque, int version_id);
+
+/* VMStateInfo allows customized migration of objects that don't fit in
+ * any category in VMStateFlags. Additional information is always passed
+ * into get and put in terms of field and vmdesc parameters. However
+ * these two parameters should only be used in cases when customized
+ * handling is needed, such as QTAILQ. For primitive data types such as
+ * integer, field and vmdesc parameters should be ignored inside get/put.
+ */
+struct VMStateInfo {
+    const char *name;
+    int (*get)(SlirpIStream *f, void *pv, size_t size, const VMStateField *field);
+    int (*put)(SlirpOStream *f, void *pv, size_t size, const VMStateField *field);
+};
+
+enum VMStateFlags {
+    /* Ignored */
+    VMS_SINGLE           = 0x001,
+
+    /* The struct member at opaque + VMStateField.offset is a pointer
+     * to the actual field (e.g. struct a { uint8_t *b;
+     * }). Dereference the pointer before using it as basis for
+     * further pointer arithmetic (see e.g. VMS_ARRAY). Does not
+     * affect the meaning of VMStateField.num_offset or
+     * VMStateField.size_offset; see VMS_VARRAY* and VMS_VBUFFER for
+     * those. */
+    VMS_POINTER          = 0x002,
+
+    /* The field is an array of fixed size. VMStateField.num contains
+     * the number of entries in the array. The size of each entry is
+     * given by VMStateField.size and / or opaque +
+     * VMStateField.size_offset; see VMS_VBUFFER and
+     * VMS_MULTIPLY. Each array entry will be processed individually
+     * (VMStateField.info.get()/put() if VMS_STRUCT is not set,
+     * recursion into VMStateField.vmsd if VMS_STRUCT is set). May not
+     * be combined with VMS_VARRAY*. */
+    VMS_ARRAY            = 0x004,
+
+    /* The field is itself a struct, containing one or more
+     * fields. Recurse into VMStateField.vmsd. Most useful in
+     * combination with VMS_ARRAY / VMS_VARRAY*, recursing into each
+     * array entry. */
+    VMS_STRUCT           = 0x008,
+
+    /* The field is an array of variable size. The int32_t at opaque +
+     * VMStateField.num_offset contains the number of entries in the
+     * array. See the VMS_ARRAY description regarding array handling
+     * in general. May not be combined with VMS_ARRAY or any other
+     * VMS_VARRAY*. */
+    VMS_VARRAY_INT32     = 0x010,
+
+    /* Ignored */
+    VMS_BUFFER           = 0x020,
+
+    /* The field is a (fixed-size or variable-size) array of pointers
+     * (e.g. struct a { uint8_t *b[]; }). Dereference each array entry
+     * before using it. Note: Does not imply any one of VMS_ARRAY /
+     * VMS_VARRAY*; these need to be set explicitly. */
+    VMS_ARRAY_OF_POINTER = 0x040,
+
+    /* The field is an array of variable size. The uint16_t at opaque
+     * + VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS)
+     * contains the number of entries in the array. See the VMS_ARRAY
+     * description regarding array handling in general. May not be
+     * combined with VMS_ARRAY or any other VMS_VARRAY*. */
+    VMS_VARRAY_UINT16    = 0x080,
+
+    /* The size of the individual entries (a single array entry if
+     * VMS_ARRAY or any of VMS_VARRAY* are set, or the field itself if
+     * neither is set) is variable (i.e. not known at compile-time),
+     * but the same for all entries. Use the int32_t at opaque +
+     * VMStateField.size_offset (subject to VMS_MULTIPLY) to determine
+     * the size of each (and every) entry. */
+    VMS_VBUFFER          = 0x100,
+
+    /* Multiply the entry size given by the int32_t at opaque +
+     * VMStateField.size_offset (see VMS_VBUFFER description) with
+     * VMStateField.size to determine the number of bytes to be
+     * allocated. Only valid in combination with VMS_VBUFFER. */
+    VMS_MULTIPLY         = 0x200,
+
+    /* The field is an array of variable size. The uint8_t at opaque +
+     * VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS)
+     * contains the number of entries in the array. See the VMS_ARRAY
+     * description regarding array handling in general. May not be
+     * combined with VMS_ARRAY or any other VMS_VARRAY*. */
+    VMS_VARRAY_UINT8     = 0x400,
+
+    /* The field is an array of variable size. The uint32_t at opaque
+     * + VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS)
+     * contains the number of entries in the array. See the VMS_ARRAY
+     * description regarding array handling in general. May not be
+     * combined with VMS_ARRAY or any other VMS_VARRAY*. */
+    VMS_VARRAY_UINT32    = 0x800,
+
+    /* Fail loading the serialised VM state if this field is missing
+     * from the input. */
+    VMS_MUST_EXIST       = 0x1000,
+
+    /* When loading serialised VM state, allocate memory for the
+     * (entire) field. Only valid in combination with
+     * VMS_POINTER. Note: Not all combinations with other flags are
+     * currently supported, e.g. VMS_ALLOC|VMS_ARRAY_OF_POINTER won't
+     * cause the individual entries to be allocated. */
+    VMS_ALLOC            = 0x2000,
+
+    /* Multiply the number of entries given by the integer at opaque +
+     * VMStateField.num_offset (see VMS_VARRAY*) with VMStateField.num
+     * to determine the number of entries in the array. Only valid in
+     * combination with one of VMS_VARRAY*. */
+    VMS_MULTIPLY_ELEMENTS = 0x4000,
+
+    /* A structure field that is like VMS_STRUCT, but uses
+     * VMStateField.struct_version_id to tell which version of the
+     * structure we are referencing to use. */
+    VMS_VSTRUCT           = 0x8000,
+};
+
+struct VMStateField {
+    const char *name;
+    size_t offset;
+    size_t size;
+    size_t start;
+    int num;
+    size_t num_offset;
+    size_t size_offset;
+    const VMStateInfo *info;
+    enum VMStateFlags flags;
+    const VMStateDescription *vmsd;
+    int version_id;
+    int struct_version_id;
+    bool (*field_exists)(void *opaque, int version_id);
+};
+
+struct VMStateDescription {
+    const char *name;
+    int version_id;
+    int (*pre_load)(void *opaque);
+    int (*post_load)(void *opaque, int version_id);
+    int (*pre_save)(void *opaque);
+    VMStateField *fields;
+};
+
+
+extern const VMStateInfo slirp_vmstate_info_int16;
+extern const VMStateInfo slirp_vmstate_info_int32;
+extern const VMStateInfo slirp_vmstate_info_uint8;
+extern const VMStateInfo slirp_vmstate_info_uint16;
+extern const VMStateInfo slirp_vmstate_info_uint32;
+
+/** Put this in the stream when migrating a null pointer.*/
+#define VMS_NULLPTR_MARKER (0x30U) /* '0' */
+extern const VMStateInfo slirp_vmstate_info_nullptr;
+
+extern const VMStateInfo slirp_vmstate_info_buffer;
+extern const VMStateInfo slirp_vmstate_info_tmp;
+
+#define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)
+#define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0)
+#define typeof_field(type, field) typeof(((type *)0)->field)
+#define type_check(t1,t2) ((t1*)0 - (t2*)0)
+
+#define vmstate_offset_value(_state, _field, _type)                  \
+    (offsetof(_state, _field) +                                      \
+     type_check(_type, typeof_field(_state, _field)))
+
+#define vmstate_offset_pointer(_state, _field, _type)                \
+    (offsetof(_state, _field) +                                      \
+     type_check_pointer(_type, typeof_field(_state, _field)))
+
+#define vmstate_offset_array(_state, _field, _type, _num)            \
+    (offsetof(_state, _field) +                                      \
+     type_check_array(_type, typeof_field(_state, _field), _num))
+
+#define vmstate_offset_buffer(_state, _field)                        \
+    vmstate_offset_array(_state, _field, uint8_t,                    \
+                         sizeof(typeof_field(_state, _field)))
+
+/* In the macros below, if there is a _version, that means the macro's
+ * field will be processed only if the version being received is >=
+ * the _version specified.  In general, if you add a new field, you
+ * would increment the structure's version and put that version
+ * number into the new field so it would only be processed with the
+ * new version.
+ *
+ * In particular, for VMSTATE_STRUCT() and friends the _version does
+ * *NOT* pick the version of the sub-structure.  It works just as
+ * specified above.  The version of the top-level structure received
+ * is passed down to all sub-structures.  This means that the
+ * sub-structures must have version that are compatible with all the
+ * structures that use them.
+ *
+ * If you want to specify the version of the sub-structure, use
+ * VMSTATE_VSTRUCT(), which allows the specific sub-structure version
+ * to be directly specified.
+ */
+
+#define VMSTATE_SINGLE_TEST(_field, _state, _test, _version, _info, _type) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .size         = sizeof(_type),                                   \
+    .info         = &(_info),                                        \
+    .flags        = VMS_SINGLE,                                      \
+    .offset       = vmstate_offset_value(_state, _field, _type),     \
+}
+
+#define VMSTATE_ARRAY(_field, _state, _num, _version, _info, _type) {\
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .num        = (_num),                                            \
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_ARRAY,                                         \
+    .offset     = vmstate_offset_array(_state, _field, _type, _num), \
+}
+
+#define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .vmsd         = &(_vmsd),                                        \
+    .size         = sizeof(_type),                                   \
+    .flags        = VMS_STRUCT,                                      \
+    .offset       = vmstate_offset_value(_state, _field, _type),     \
+}
+
+#define VMSTATE_STRUCT_POINTER_V(_field, _state, _version, _vmsd, _type) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                        \
+    .vmsd         = &(_vmsd),                                        \
+    .size         = sizeof(_type *),                                 \
+    .flags        = VMS_STRUCT|VMS_POINTER,                          \
+    .offset       = vmstate_offset_pointer(_state, _field, _type),   \
+}
+
+#define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, _vmsd, _type) { \
+    .name         = (stringify(_field)),                             \
+    .num          = (_num),                                          \
+    .field_exists = (_test),                                         \
+    .version_id   = (_version),                                      \
+    .vmsd         = &(_vmsd),                                        \
+    .size         = sizeof(_type),                                   \
+    .flags        = VMS_STRUCT|VMS_ARRAY,                            \
+    .offset       = vmstate_offset_array(_state, _field, _type, _num),\
+}
+
+#define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .size         = (_size - _start),                                \
+    .info         = &slirp_vmstate_info_buffer,                      \
+    .flags        = VMS_BUFFER,                                      \
+    .offset       = vmstate_offset_buffer(_state, _field) + _start,  \
+}
+
+#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _field_size) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .size_offset  = vmstate_offset_value(_state, _field_size, uint32_t),\
+    .info         = &slirp_vmstate_info_buffer,                      \
+    .flags        = VMS_VBUFFER|VMS_POINTER,                         \
+    .offset       = offsetof(_state, _field),                        \
+}
+
+#define QEMU_BUILD_BUG_ON_STRUCT(x)             \
+    struct {                                    \
+        int:(x) ? -1 : 1;                       \
+    }
+
+#define QEMU_BUILD_BUG_ON_ZERO(x) (sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)) - \
+                                   sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)))
+
+/* Allocate a temporary of type 'tmp_type', set tmp->parent to _state
+ * and execute the vmsd on the temporary.  Note that we're working with
+ * the whole of _state here, not a field within it.
+ * We compile time check that:
+ *    That _tmp_type contains a 'parent' member that's a pointer to the
+ *        '_state' type
+ *    That the pointer is right at the start of _tmp_type.
+ */
+#define VMSTATE_WITH_TMP(_state, _tmp_type, _vmsd) {                 \
+    .name         = "tmp",                                           \
+    .size         = sizeof(_tmp_type) +                              \
+                    QEMU_BUILD_BUG_ON_ZERO(offsetof(_tmp_type, parent) != 0) + \
+                    type_check_pointer(_state,                       \
+                        typeof_field(_tmp_type, parent)),            \
+    .vmsd         = &(_vmsd),                                        \
+    .info         = &slirp_vmstate_info_tmp,                         \
+}
+
+#define VMSTATE_SINGLE(_field, _state, _version, _info, _type)          \
+    VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type)
+
+#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type)        \
+    VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type)
+
+#define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type)          \
+    VMSTATE_STRUCT_POINTER_V(_field, _state, 0, _vmsd, _type)
+
+#define VMSTATE_STRUCT_ARRAY(_field, _state, _num, _version, _vmsd, _type) \
+    VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version,   \
+            _vmsd, _type)
+
+#define VMSTATE_INT16_V(_f, _s, _v)                                   \
+    VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_int16, int16_t)
+#define VMSTATE_INT32_V(_f, _s, _v)                                   \
+    VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_int32, int32_t)
+
+#define VMSTATE_UINT8_V(_f, _s, _v)                                   \
+    VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint8, uint8_t)
+#define VMSTATE_UINT16_V(_f, _s, _v)                                  \
+    VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint16, uint16_t)
+#define VMSTATE_UINT32_V(_f, _s, _v)                                  \
+    VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint32, uint32_t)
+
+#define VMSTATE_INT16(_f, _s)                                         \
+    VMSTATE_INT16_V(_f, _s, 0)
+#define VMSTATE_INT32(_f, _s)                                         \
+    VMSTATE_INT32_V(_f, _s, 0)
+
+#define VMSTATE_UINT8(_f, _s)                                         \
+    VMSTATE_UINT8_V(_f, _s, 0)
+#define VMSTATE_UINT16(_f, _s)                                        \
+    VMSTATE_UINT16_V(_f, _s, 0)
+#define VMSTATE_UINT32(_f, _s)                                        \
+    VMSTATE_UINT32_V(_f, _s, 0)
+
+#define VMSTATE_UINT16_TEST(_f, _s, _t)                               \
+    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, slirp_vmstate_info_uint16, uint16_t)
+
+#define VMSTATE_UINT32_TEST(_f, _s, _t)                                  \
+    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, slirp_vmstate_info_uint32, uint32_t)
+
+#define VMSTATE_INT16_ARRAY_V(_f, _s, _n, _v)                         \
+    VMSTATE_ARRAY(_f, _s, _n, _v, slirp_vmstate_info_int16, int16_t)
+
+#define VMSTATE_INT16_ARRAY(_f, _s, _n)                               \
+    VMSTATE_INT16_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_BUFFER_V(_f, _s, _v)                                    \
+    VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, 0, sizeof(typeof_field(_s, _f)))
+
+#define VMSTATE_BUFFER(_f, _s)                                        \
+    VMSTATE_BUFFER_V(_f, _s, 0)
+
+#define VMSTATE_END_OF_LIST()                                         \
+    {}
+
+#endif
diff --git a/slirp/state.c b/slirp/state.c
deleted file mode 100644 (file)
index 0e5a706..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * libslirp
- *
- * Copyright (c) 2004-2008 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu/osdep.h"
-
-#include "slirp.h"
-#include "state.h"
-#include "migration/vmstate.h"
-#include "migration/qemu-file-types.h"
-#include "migration/register.h"
-
-static int slirp_tcp_post_load(void *opaque, int version)
-{
-    tcp_template((struct tcpcb *)opaque);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_slirp_tcp = {
-    .name = "slirp-tcp",
-    .version_id = 0,
-    .post_load = slirp_tcp_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_INT16(t_state, struct tcpcb),
-        VMSTATE_INT16_ARRAY(t_timer, struct tcpcb, TCPT_NTIMERS),
-        VMSTATE_INT16(t_rxtshift, struct tcpcb),
-        VMSTATE_INT16(t_rxtcur, struct tcpcb),
-        VMSTATE_INT16(t_dupacks, struct tcpcb),
-        VMSTATE_UINT16(t_maxseg, struct tcpcb),
-        VMSTATE_UINT8(t_force, struct tcpcb),
-        VMSTATE_UINT16(t_flags, struct tcpcb),
-        VMSTATE_UINT32(snd_una, struct tcpcb),
-        VMSTATE_UINT32(snd_nxt, struct tcpcb),
-        VMSTATE_UINT32(snd_up, struct tcpcb),
-        VMSTATE_UINT32(snd_wl1, struct tcpcb),
-        VMSTATE_UINT32(snd_wl2, struct tcpcb),
-        VMSTATE_UINT32(iss, struct tcpcb),
-        VMSTATE_UINT32(snd_wnd, struct tcpcb),
-        VMSTATE_UINT32(rcv_wnd, struct tcpcb),
-        VMSTATE_UINT32(rcv_nxt, struct tcpcb),
-        VMSTATE_UINT32(rcv_up, struct tcpcb),
-        VMSTATE_UINT32(irs, struct tcpcb),
-        VMSTATE_UINT32(rcv_adv, struct tcpcb),
-        VMSTATE_UINT32(snd_max, struct tcpcb),
-        VMSTATE_UINT32(snd_cwnd, struct tcpcb),
-        VMSTATE_UINT32(snd_ssthresh, struct tcpcb),
-        VMSTATE_INT16(t_idle, struct tcpcb),
-        VMSTATE_INT16(t_rtt, struct tcpcb),
-        VMSTATE_UINT32(t_rtseq, struct tcpcb),
-        VMSTATE_INT16(t_srtt, struct tcpcb),
-        VMSTATE_INT16(t_rttvar, struct tcpcb),
-        VMSTATE_UINT16(t_rttmin, struct tcpcb),
-        VMSTATE_UINT32(max_sndwnd, struct tcpcb),
-        VMSTATE_UINT8(t_oobflags, struct tcpcb),
-        VMSTATE_UINT8(t_iobc, struct tcpcb),
-        VMSTATE_INT16(t_softerror, struct tcpcb),
-        VMSTATE_UINT8(snd_scale, struct tcpcb),
-        VMSTATE_UINT8(rcv_scale, struct tcpcb),
-        VMSTATE_UINT8(request_r_scale, struct tcpcb),
-        VMSTATE_UINT8(requested_s_scale, struct tcpcb),
-        VMSTATE_UINT32(ts_recent, struct tcpcb),
-        VMSTATE_UINT32(ts_recent_age, struct tcpcb),
-        VMSTATE_UINT32(last_ack_sent, struct tcpcb),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/* The sbuf has a pair of pointers that are migrated as offsets;
- * we calculate the offsets and restore the pointers using
- * pre_save/post_load on a tmp structure.
- */
-struct sbuf_tmp {
-    struct sbuf *parent;
-    uint32_t roff, woff;
-};
-
-static int sbuf_tmp_pre_save(void *opaque)
-{
-    struct sbuf_tmp *tmp = opaque;
-    tmp->woff = tmp->parent->sb_wptr - tmp->parent->sb_data;
-    tmp->roff = tmp->parent->sb_rptr - tmp->parent->sb_data;
-
-    return 0;
-}
-
-static int sbuf_tmp_post_load(void *opaque, int version)
-{
-    struct sbuf_tmp *tmp = opaque;
-    uint32_t requested_len = tmp->parent->sb_datalen;
-
-    /* Allocate the buffer space used by the field after the tmp */
-    sbreserve(tmp->parent, tmp->parent->sb_datalen);
-
-    if (tmp->parent->sb_datalen != requested_len) {
-        return -ENOMEM;
-    }
-    if (tmp->woff >= requested_len ||
-        tmp->roff >= requested_len) {
-        g_critical("invalid sbuf offsets r/w=%u/%u len=%u",
-                   tmp->roff, tmp->woff, requested_len);
-        return -EINVAL;
-    }
-
-    tmp->parent->sb_wptr = tmp->parent->sb_data + tmp->woff;
-    tmp->parent->sb_rptr = tmp->parent->sb_data + tmp->roff;
-
-    return 0;
-}
-
-
-static const VMStateDescription vmstate_slirp_sbuf_tmp = {
-    .name = "slirp-sbuf-tmp",
-    .post_load = sbuf_tmp_post_load,
-    .pre_save  = sbuf_tmp_pre_save,
-    .version_id = 0,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(woff, struct sbuf_tmp),
-        VMSTATE_UINT32(roff, struct sbuf_tmp),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_slirp_sbuf = {
-    .name = "slirp-sbuf",
-    .version_id = 0,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(sb_cc, struct sbuf),
-        VMSTATE_UINT32(sb_datalen, struct sbuf),
-        VMSTATE_WITH_TMP(struct sbuf, struct sbuf_tmp, vmstate_slirp_sbuf_tmp),
-        VMSTATE_VBUFFER_UINT32(sb_data, struct sbuf, 0, NULL, sb_datalen),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static bool slirp_older_than_v4(void *opaque, int version_id)
-{
-    return version_id < 4;
-}
-
-static bool slirp_family_inet(void *opaque, int version_id)
-{
-    union slirp_sockaddr *ssa = (union slirp_sockaddr *)opaque;
-    return ssa->ss.ss_family == AF_INET;
-}
-
-static int slirp_socket_pre_load(void *opaque)
-{
-    struct socket *so = opaque;
-    if (tcp_attach(so) < 0) {
-        return -ENOMEM;
-    }
-    /* Older versions don't load these fields */
-    so->so_ffamily = AF_INET;
-    so->so_lfamily = AF_INET;
-    return 0;
-}
-
-#ifndef _WIN32
-#define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_UINT32_TEST(f, s, t)
-#else
-/* Win uses u_long rather than uint32_t - but it's still 32bits long */
-#define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_SINGLE_TEST(f, s, t, 0, \
-                                       vmstate_info_uint32, u_long)
-#endif
-
-/* The OS provided ss_family field isn't that portable; it's size
- * and type varies (16/8 bit, signed, unsigned)
- * and the values it contains aren't fully portable.
- */
-typedef struct SS_FamilyTmpStruct {
-    union slirp_sockaddr    *parent;
-    uint16_t                 portable_family;
-} SS_FamilyTmpStruct;
-
-#define SS_FAMILY_MIG_IPV4   2  /* Linux, BSD, Win... */
-#define SS_FAMILY_MIG_IPV6  10  /* Linux */
-#define SS_FAMILY_MIG_OTHER 0xffff
-
-static int ss_family_pre_save(void *opaque)
-{
-    SS_FamilyTmpStruct *tss = opaque;
-
-    tss->portable_family = SS_FAMILY_MIG_OTHER;
-
-    if (tss->parent->ss.ss_family == AF_INET) {
-        tss->portable_family = SS_FAMILY_MIG_IPV4;
-    } else if (tss->parent->ss.ss_family == AF_INET6) {
-        tss->portable_family = SS_FAMILY_MIG_IPV6;
-    }
-
-    return 0;
-}
-
-static int ss_family_post_load(void *opaque, int version_id)
-{
-    SS_FamilyTmpStruct *tss = opaque;
-
-    switch (tss->portable_family) {
-    case SS_FAMILY_MIG_IPV4:
-        tss->parent->ss.ss_family = AF_INET;
-        break;
-    case SS_FAMILY_MIG_IPV6:
-    case 23: /* compatibility: AF_INET6 from mingw */
-    case 28: /* compatibility: AF_INET6 from FreeBSD sys/socket.h */
-        tss->parent->ss.ss_family = AF_INET6;
-        break;
-    default:
-        g_critical("invalid ss_family type %x", tss->portable_family);
-        return -EINVAL;
-    }
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_slirp_ss_family = {
-    .name = "slirp-socket-addr/ss_family",
-    .pre_save  = ss_family_pre_save,
-    .post_load = ss_family_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT16(portable_family, SS_FamilyTmpStruct),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_slirp_socket_addr = {
-    .name = "slirp-socket-addr",
-    .version_id = 4,
-    .fields = (VMStateField[]) {
-        VMSTATE_WITH_TMP(union slirp_sockaddr, SS_FamilyTmpStruct,
-                            vmstate_slirp_ss_family),
-        VMSTATE_SIN4_ADDR(sin.sin_addr.s_addr, union slirp_sockaddr,
-                            slirp_family_inet),
-        VMSTATE_UINT16_TEST(sin.sin_port, union slirp_sockaddr,
-                            slirp_family_inet),
-
-#if 0
-        /* Untested: Needs checking by someone with IPv6 test */
-        VMSTATE_BUFFER_TEST(sin6.sin6_addr, union slirp_sockaddr,
-                            slirp_family_inet6),
-        VMSTATE_UINT16_TEST(sin6.sin6_port, union slirp_sockaddr,
-                            slirp_family_inet6),
-        VMSTATE_UINT32_TEST(sin6.sin6_flowinfo, union slirp_sockaddr,
-                            slirp_family_inet6),
-        VMSTATE_UINT32_TEST(sin6.sin6_scope_id, union slirp_sockaddr,
-                            slirp_family_inet6),
-#endif
-
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_slirp_socket = {
-    .name = "slirp-socket",
-    .version_id = 4,
-    .pre_load = slirp_socket_pre_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(so_urgc, struct socket),
-        /* Pre-v4 versions */
-        VMSTATE_SIN4_ADDR(so_faddr.s_addr, struct socket,
-                            slirp_older_than_v4),
-        VMSTATE_SIN4_ADDR(so_laddr.s_addr, struct socket,
-                            slirp_older_than_v4),
-        VMSTATE_UINT16_TEST(so_fport, struct socket, slirp_older_than_v4),
-        VMSTATE_UINT16_TEST(so_lport, struct socket, slirp_older_than_v4),
-        /* v4 and newer */
-        VMSTATE_STRUCT(fhost, struct socket, 4, vmstate_slirp_socket_addr,
-                       union slirp_sockaddr),
-        VMSTATE_STRUCT(lhost, struct socket, 4, vmstate_slirp_socket_addr,
-                       union slirp_sockaddr),
-
-        VMSTATE_UINT8(so_iptos, struct socket),
-        VMSTATE_UINT8(so_emu, struct socket),
-        VMSTATE_UINT8(so_type, struct socket),
-        VMSTATE_INT32(so_state, struct socket),
-        VMSTATE_STRUCT(so_rcv, struct socket, 0, vmstate_slirp_sbuf,
-                       struct sbuf),
-        VMSTATE_STRUCT(so_snd, struct socket, 0, vmstate_slirp_sbuf,
-                       struct sbuf),
-        VMSTATE_STRUCT_POINTER(so_tcpcb, struct socket, vmstate_slirp_tcp,
-                       struct tcpcb),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_slirp_bootp_client = {
-    .name = "slirp_bootpclient",
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT16(allocated, BOOTPClient),
-        VMSTATE_BUFFER(macaddr, BOOTPClient),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_slirp = {
-    .name = "slirp",
-    .version_id = 4,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT16_V(ip_id, Slirp, 2),
-        VMSTATE_STRUCT_ARRAY(bootp_clients, Slirp, NB_BOOTP_CLIENTS, 3,
-                             vmstate_slirp_bootp_client, BOOTPClient),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void slirp_state_save(QEMUFile *f, void *opaque)
-{
-    Slirp *slirp = opaque;
-    struct gfwd_list *ex_ptr;
-
-    for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
-        if (ex_ptr->write_cb) {
-            struct socket *so;
-            so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr,
-                                       ntohs(ex_ptr->ex_fport));
-            if (!so) {
-                continue;
-            }
-
-            qemu_put_byte(f, 42);
-            vmstate_save_state(f, &vmstate_slirp_socket, so, NULL);
-        }
-    qemu_put_byte(f, 0);
-
-    vmstate_save_state(f, &vmstate_slirp, slirp, NULL);
-}
-
-
-static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
-{
-    Slirp *slirp = opaque;
-    struct gfwd_list *ex_ptr;
-
-    while (qemu_get_byte(f)) {
-        int ret;
-        struct socket *so = socreate(slirp);
-
-        ret = vmstate_load_state(f, &vmstate_slirp_socket, so, version_id);
-        if (ret < 0) {
-            return ret;
-        }
-
-        if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) !=
-            slirp->vnetwork_addr.s_addr) {
-            return -EINVAL;
-        }
-        for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
-            if (ex_ptr->write_cb &&
-                so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
-                so->so_fport == ex_ptr->ex_fport) {
-                break;
-            }
-        }
-        if (!ex_ptr) {
-            return -EINVAL;
-        }
-    }
-
-    return vmstate_load_state(f, &vmstate_slirp, slirp, version_id);
-}
-
-void slirp_state_register(Slirp *slirp)
-{
-    static SaveVMHandlers savevm_slirp_state = {
-        .save_state = slirp_state_save,
-        .load_state = slirp_state_load,
-    };
-
-    register_savevm_live(NULL, "slirp", 0, 4, &savevm_slirp_state, slirp);
-}
-
-void slirp_state_unregister(Slirp *slirp)
-{
-    unregister_savevm(NULL, "slirp", slirp);
-}
diff --git a/slirp/state.h b/slirp/state.h
deleted file mode 100644 (file)
index 1548668..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef SLIRP_STATE_H_
-#define SLIRP_STATE_H_
-
-#include "libslirp.h"
-
-void slirp_state_register(Slirp *slirp);
-void slirp_state_unregister(Slirp *slirp);
-
-#endif /* SLIRP_STATE_H_ */
diff --git a/slirp/tcp.h b/slirp/tcp.h
deleted file mode 100644 (file)
index 47aaea6..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 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. 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.
- *
- *     @(#)tcp.h       8.1 (Berkeley) 6/10/93
- * tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp
- */
-
-#ifndef TCP_H
-#define TCP_H
-
-#include <glib.h>
-
-typedef        uint32_t tcp_seq;
-
-#define      PR_SLOWHZ       2               /* 2 slow timeouts per second (approx) */
-#define      PR_FASTHZ       5               /* 5 fast timeouts per second (not important) */
-
-#define TCP_SNDSPACE 8192
-#define TCP_RCVSPACE 8192
-
-/*
- * TCP header.
- * Per RFC 793, September, 1981.
- */
-#define tcphdr slirp_tcphdr
-struct tcphdr {
-       uint16_t th_sport;              /* source port */
-       uint16_t th_dport;              /* destination port */
-       tcp_seq th_seq;                 /* sequence number */
-       tcp_seq th_ack;                 /* acknowledgement number */
-#if G_BYTE_ORDER == G_BIG_ENDIAN
-       uint8_t th_off:4,               /* data offset */
-               th_x2:4;                /* (unused) */
-#else
-       uint8_t th_x2:4,                /* (unused) */
-               th_off:4;               /* data offset */
-#endif
-       uint8_t th_flags;
-       uint16_t th_win;                /* window */
-       uint16_t th_sum;                /* checksum */
-       uint16_t th_urp;                /* urgent pointer */
-};
-
-#include "tcp_var.h"
-
-#ifndef TH_FIN
-#define        TH_FIN  0x01
-#define        TH_SYN  0x02
-#define        TH_RST  0x04
-#define        TH_PUSH 0x08
-#define        TH_ACK  0x10
-#define        TH_URG  0x20
-#endif
-
-#ifndef TCPOPT_EOL
-#define        TCPOPT_EOL              0
-#define        TCPOPT_NOP              1
-#define        TCPOPT_MAXSEG           2
-#define TCPOPT_WINDOW          3
-#define TCPOPT_SACK_PERMITTED  4               /* Experimental */
-#define TCPOPT_SACK            5               /* Experimental */
-#define TCPOPT_TIMESTAMP       8
-
-#define TCPOPT_TSTAMP_HDR      \
-    (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP)
-#endif
-
-#ifndef TCPOLEN_MAXSEG
-#define    TCPOLEN_MAXSEG              4
-#define    TCPOLEN_WINDOW              3
-#define    TCPOLEN_SACK_PERMITTED      2
-#define    TCPOLEN_TIMESTAMP           10
-#define    TCPOLEN_TSTAMP_APPA         (TCPOLEN_TIMESTAMP+2) /* appendix A */
-#endif
-
-/*
- * Default maximum segment size for TCP.
- * With an IP MSS of 576, this is 536,
- * but 512 is probably more convenient.
- * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)).
- *
- * We make this 1460 because we only care about Ethernet in the qemu context.
- */
-#undef TCP_MSS
-#define        TCP_MSS 1460
-#undef TCP6_MSS
-#define TCP6_MSS 1440
-
-#undef TCP_MAXWIN
-#define        TCP_MAXWIN      65535   /* largest value for (unscaled) window */
-
-#undef TCP_MAX_WINSHIFT
-#define TCP_MAX_WINSHIFT       14      /* maximum window shift */
-
-/*
- * User-settable options (used with setsockopt).
- *
- * We don't use the system headers on unix because we have conflicting
- * local structures. We can't avoid the system definitions on Windows,
- * so we undefine them.
- */
-#undef TCP_NODELAY
-#define        TCP_NODELAY     0x01    /* don't delay send to coalesce packets */
-#undef TCP_MAXSEG
-
-/*
- * TCP FSM state definitions.
- * Per RFC793, September, 1981.
- */
-
-#define TCP_NSTATES     11
-
-#define TCPS_CLOSED             0       /* closed */
-#define TCPS_LISTEN             1       /* listening for connection */
-#define TCPS_SYN_SENT           2       /* active, have sent syn */
-#define TCPS_SYN_RECEIVED       3       /* have send and received syn */
-/* states < TCPS_ESTABLISHED are those where connections not established */
-#define TCPS_ESTABLISHED        4       /* established */
-#define TCPS_CLOSE_WAIT         5       /* rcvd fin, waiting for close */
-/* states > TCPS_CLOSE_WAIT are those where user has closed */
-#define TCPS_FIN_WAIT_1         6       /* have closed, sent fin */
-#define TCPS_CLOSING            7       /* closed xchd FIN; await FIN ACK */
-#define TCPS_LAST_ACK           8       /* had fin and close; await FIN ACK */
-/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */
-#define TCPS_FIN_WAIT_2         9       /* have closed, fin is acked */
-#define TCPS_TIME_WAIT          10      /* in 2*msl quiet wait after close */
-
-#define TCPS_HAVERCVDSYN(s)     ((s) >= TCPS_SYN_RECEIVED)
-#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED)
-#define TCPS_HAVERCVDFIN(s)     ((s) >= TCPS_TIME_WAIT)
-
-/*
- * TCP sequence numbers are 32 bit integers operated
- * on with modular arithmetic.  These macros can be
- * used to compare such integers.
- */
-#define SEQ_LT(a,b)     ((int)((a)-(b)) < 0)
-#define SEQ_LEQ(a,b)    ((int)((a)-(b)) <= 0)
-#define SEQ_GT(a,b)     ((int)((a)-(b)) > 0)
-#define SEQ_GEQ(a,b)    ((int)((a)-(b)) >= 0)
-
-/*
- * Macros to initialize tcp sequence numbers for
- * send and receive from initial send and receive
- * sequence numbers.
- */
-#define tcp_rcvseqinit(tp) \
-     (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1
-
-#define tcp_sendseqinit(tp) \
-    (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss
-
-#define TCP_ISSINCR     (125*1024)      /* increment for tcp_iss each second */
-
-#endif
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
deleted file mode 100644 (file)
index 6749b32..0000000
+++ /dev/null
@@ -1,1554 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994
- *     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. 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.
- *
- *     @(#)tcp_input.c 8.5 (Berkeley) 4/10/94
- * tcp_input.c,v 1.10 1994/10/13 18:36:32 wollman Exp
- */
-
-/*
- * Changes and additions relating to SLiRP
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#include "slirp.h"
-#include "ip_icmp.h"
-
-#define        TCPREXMTTHRESH 3
-
-#define TCP_PAWS_IDLE  (24 * 24 * 60 * 60 * PR_SLOWHZ)
-
-/* for modulo comparisons of timestamps */
-#define TSTMP_LT(a,b)  ((int)((a)-(b)) < 0)
-#define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0)
-
-/*
- * Insert segment ti into reassembly queue of tcp with
- * control block tp.  Return TH_FIN if reassembly now includes
- * a segment with FIN.  The macro form does the common case inline
- * (segment is the next to be received on an established connection,
- * and the queue is empty), avoiding linkage into and removal
- * from the queue and repetition of various conversions.
- * Set DELACK for segments received in order, but ack immediately
- * when segments are out of order (so fast retransmit can work).
- */
-#define        TCP_REASS(tp, ti, m, so, flags) { \
-       if ((ti)->ti_seq == (tp)->rcv_nxt && \
-        tcpfrag_list_empty(tp) && \
-           (tp)->t_state == TCPS_ESTABLISHED) { \
-               tp->t_flags |= TF_DELACK; \
-               (tp)->rcv_nxt += (ti)->ti_len; \
-               flags = (ti)->ti_flags & TH_FIN; \
-               if (so->so_emu) { \
-                       if (tcp_emu((so),(m))) sbappend(so, (m)); \
-               } else \
-                       sbappend((so), (m)); \
-       } else { \
-               (flags) = tcp_reass((tp), (ti), (m)); \
-               tp->t_flags |= TF_ACKNOW; \
-       } \
-}
-
-static void tcp_dooptions(struct tcpcb *tp, uint8_t *cp, int cnt,
-                          struct tcpiphdr *ti);
-static void tcp_xmit_timer(register struct tcpcb *tp, int rtt);
-
-static int
-tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti,
-          struct mbuf *m)
-{
-       register struct tcpiphdr *q;
-       struct socket *so = tp->t_socket;
-       int flags;
-
-       /*
-        * Call with ti==NULL after become established to
-        * force pre-ESTABLISHED data up to user socket.
-        */
-        if (ti == NULL)
-               goto present;
-
-       /*
-        * Find a segment which begins after this one does.
-        */
-       for (q = tcpfrag_list_first(tp); !tcpfrag_list_end(q, tp);
-            q = tcpiphdr_next(q))
-               if (SEQ_GT(q->ti_seq, ti->ti_seq))
-                       break;
-
-       /*
-        * If there is a preceding segment, it may provide some of
-        * our data already.  If so, drop the data from the incoming
-        * segment.  If it provides all of our data, drop us.
-        */
-       if (!tcpfrag_list_end(tcpiphdr_prev(q), tp)) {
-               register int i;
-               q = tcpiphdr_prev(q);
-               /* conversion to int (in i) handles seq wraparound */
-               i = q->ti_seq + q->ti_len - ti->ti_seq;
-               if (i > 0) {
-                       if (i >= ti->ti_len) {
-                               m_free(m);
-                               /*
-                                * Try to present any queued data
-                                * at the left window edge to the user.
-                                * This is needed after the 3-WHS
-                                * completes.
-                                */
-                               goto present;   /* ??? */
-                       }
-                       m_adj(m, i);
-                       ti->ti_len -= i;
-                       ti->ti_seq += i;
-               }
-               q = tcpiphdr_next(q);
-       }
-       ti->ti_mbuf = m;
-
-       /*
-        * While we overlap succeeding segments trim them or,
-        * if they are completely covered, dequeue them.
-        */
-       while (!tcpfrag_list_end(q, tp)) {
-               register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq;
-               if (i <= 0)
-                       break;
-               if (i < q->ti_len) {
-                       q->ti_seq += i;
-                       q->ti_len -= i;
-                       m_adj(q->ti_mbuf, i);
-                       break;
-               }
-               q = tcpiphdr_next(q);
-               m = tcpiphdr_prev(q)->ti_mbuf;
-               remque(tcpiphdr2qlink(tcpiphdr_prev(q)));
-               m_free(m);
-       }
-
-       /*
-        * Stick new segment in its place.
-        */
-       insque(tcpiphdr2qlink(ti), tcpiphdr2qlink(tcpiphdr_prev(q)));
-
-present:
-       /*
-        * Present data to user, advancing rcv_nxt through
-        * completed sequence space.
-        */
-       if (!TCPS_HAVEESTABLISHED(tp->t_state))
-               return (0);
-       ti = tcpfrag_list_first(tp);
-       if (tcpfrag_list_end(ti, tp) || ti->ti_seq != tp->rcv_nxt)
-               return (0);
-       if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len)
-               return (0);
-       do {
-               tp->rcv_nxt += ti->ti_len;
-               flags = ti->ti_flags & TH_FIN;
-               remque(tcpiphdr2qlink(ti));
-               m = ti->ti_mbuf;
-               ti = tcpiphdr_next(ti);
-               if (so->so_state & SS_FCANTSENDMORE)
-                       m_free(m);
-               else {
-                       if (so->so_emu) {
-                               if (tcp_emu(so,m)) sbappend(so, m);
-                       } else
-                               sbappend(so, m);
-               }
-       } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt);
-       return (flags);
-}
-
-/*
- * TCP input routine, follows pages 65-76 of the
- * protocol specification dated September, 1981 very closely.
- */
-void
-tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
-{
-       struct ip save_ip, *ip;
-       struct ip6 save_ip6, *ip6;
-       register struct tcpiphdr *ti;
-       char *optp = NULL;
-       int optlen = 0;
-       int len, tlen, off;
-        register struct tcpcb *tp = NULL;
-       register int tiflags;
-        struct socket *so = NULL;
-       int todrop, acked, ourfinisacked, needoutput = 0;
-       int iss = 0;
-       uint32_t tiwin;
-       int ret;
-       struct sockaddr_storage lhost, fhost;
-       struct sockaddr_in *lhost4, *fhost4;
-       struct sockaddr_in6 *lhost6, *fhost6;
-    struct gfwd_list *ex_ptr;
-    Slirp *slirp;
-
-       DEBUG_CALL("tcp_input");
-       DEBUG_ARG("m = %p  iphlen = %2d  inso = %p",
-              m, iphlen, inso);
-
-       /*
-        * If called with m == 0, then we're continuing the connect
-        */
-       if (m == NULL) {
-               so = inso;
-               slirp = so->slirp;
-
-               /* Re-set a few variables */
-               tp = sototcpcb(so);
-               m = so->so_m;
-                so->so_m = NULL;
-               ti = so->so_ti;
-               tiwin = ti->ti_win;
-               tiflags = ti->ti_flags;
-
-               goto cont_conn;
-       }
-       slirp = m->slirp;
-
-       ip = mtod(m, struct ip *);
-       ip6 = mtod(m, struct ip6 *);
-
-       switch (af) {
-       case AF_INET:
-           if (iphlen > sizeof(struct ip)) {
-               ip_stripoptions(m, (struct mbuf *)0);
-               iphlen = sizeof(struct ip);
-           }
-           /* XXX Check if too short */
-
-
-           /*
-            * Save a copy of the IP header in case we want restore it
-            * for sending an ICMP error message in response.
-            */
-           save_ip = *ip;
-           save_ip.ip_len += iphlen;
-
-           /*
-            * Get IP and TCP header together in first mbuf.
-            * Note: IP leaves IP header in first mbuf.
-            */
-           m->m_data -= sizeof(struct tcpiphdr) - sizeof(struct ip)
-                                                - sizeof(struct tcphdr);
-           m->m_len += sizeof(struct tcpiphdr) - sizeof(struct ip)
-                                               - sizeof(struct tcphdr);
-           ti = mtod(m, struct tcpiphdr *);
-
-           /*
-            * Checksum extended TCP header and data.
-            */
-           tlen = ip->ip_len;
-           tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
-           memset(&ti->ih_mbuf, 0 , sizeof(struct mbuf_ptr));
-           memset(&ti->ti, 0, sizeof(ti->ti));
-           ti->ti_x0 = 0;
-           ti->ti_src = save_ip.ip_src;
-           ti->ti_dst = save_ip.ip_dst;
-           ti->ti_pr = save_ip.ip_p;
-           ti->ti_len = htons((uint16_t)tlen);
-           break;
-
-       case AF_INET6:
-           /*
-            * Save a copy of the IP header in case we want restore it
-            * for sending an ICMP error message in response.
-            */
-           save_ip6 = *ip6;
-           /*
-            * Get IP and TCP header together in first mbuf.
-            * Note: IP leaves IP header in first mbuf.
-            */
-           m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip6)
-                                                + sizeof(struct tcphdr));
-           m->m_len  += sizeof(struct tcpiphdr) - (sizeof(struct ip6)
-                                                + sizeof(struct tcphdr));
-           ti = mtod(m, struct tcpiphdr *);
-
-           tlen = ip6->ip_pl;
-           tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
-           memset(&ti->ih_mbuf, 0 , sizeof(struct mbuf_ptr));
-           memset(&ti->ti, 0, sizeof(ti->ti));
-           ti->ti_x0 = 0;
-           ti->ti_src6 = save_ip6.ip_src;
-           ti->ti_dst6 = save_ip6.ip_dst;
-           ti->ti_nh6 = save_ip6.ip_nh;
-           ti->ti_len = htons((uint16_t)tlen);
-           break;
-
-       default:
-           g_assert_not_reached();
-       }
-
-       len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
-       if (cksum(m, len)) {
-           goto drop;
-       }
-
-       /*
-        * Check that TCP offset makes sense,
-        * pull out TCP options and adjust length.              XXX
-        */
-       off = ti->ti_off << 2;
-       if (off < sizeof (struct tcphdr) || off > tlen) {
-         goto drop;
-       }
-       tlen -= off;
-       ti->ti_len = tlen;
-       if (off > sizeof (struct tcphdr)) {
-         optlen = off - sizeof (struct tcphdr);
-         optp = mtod(m, char *) + sizeof (struct tcpiphdr);
-       }
-       tiflags = ti->ti_flags;
-
-       /*
-        * Convert TCP protocol specific fields to host format.
-        */
-       NTOHL(ti->ti_seq);
-       NTOHL(ti->ti_ack);
-       NTOHS(ti->ti_win);
-       NTOHS(ti->ti_urp);
-
-       /*
-        * Drop TCP, IP headers and TCP options.
-        */
-       m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
-       m->m_len  -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
-
-       /*
-        * Locate pcb for segment.
-        */
-findso:
-       lhost.ss_family = af;
-       fhost.ss_family = af;
-       switch (af) {
-       case AF_INET:
-           lhost4 = (struct sockaddr_in *) &lhost;
-           lhost4->sin_addr = ti->ti_src;
-           lhost4->sin_port = ti->ti_sport;
-           fhost4 = (struct sockaddr_in *) &fhost;
-           fhost4->sin_addr = ti->ti_dst;
-           fhost4->sin_port = ti->ti_dport;
-           break;
-       case AF_INET6:
-           lhost6 = (struct sockaddr_in6 *) &lhost;
-           lhost6->sin6_addr = ti->ti_src6;
-           lhost6->sin6_port = ti->ti_sport;
-           fhost6 = (struct sockaddr_in6 *) &fhost;
-           fhost6->sin6_addr = ti->ti_dst6;
-           fhost6->sin6_port = ti->ti_dport;
-           break;
-       default:
-           g_assert_not_reached();
-       }
-
-       so = solookup(&slirp->tcp_last_so, &slirp->tcb, &lhost, &fhost);
-
-       /*
-        * If the state is CLOSED (i.e., TCB does not exist) then
-        * all data in the incoming segment is discarded.
-        * If the TCB exists but is in CLOSED state, it is embryonic,
-        * but should either do a listen or a connect soon.
-        *
-        * state == CLOSED means we've done socreate() but haven't
-        * attached it to a protocol yet...
-        *
-        * XXX If a TCB does not exist, and the TH_SYN flag is
-        * the only flag set, then create a session, mark it
-        * as if it was LISTENING, and continue...
-        */
-        if (so == NULL) {
-          if (slirp->restricted) {
-            /* Any hostfwds will have an existing socket, so we only get here
-             * for non-hostfwd connections. These should be dropped, unless it
-             * happens to be a guestfwd.
-             */
-            for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
-                if (ex_ptr->ex_fport == ti->ti_dport &&
-                    ti->ti_dst.s_addr == ex_ptr->ex_addr.s_addr) {
-                    break;
-                }
-            }
-            if (!ex_ptr) {
-                goto dropwithreset;
-            }
-          }
-
-         if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN)
-           goto dropwithreset;
-
-          so = socreate(slirp);
-         if (tcp_attach(so) < 0) {
-            g_free(so); /* Not sofree (if it failed, it's not insqued) */
-            goto dropwithreset;
-         }
-
-         sbreserve(&so->so_snd, TCP_SNDSPACE);
-         sbreserve(&so->so_rcv, TCP_RCVSPACE);
-
-         so->lhost.ss = lhost;
-         so->fhost.ss = fhost;
-
-         so->so_iptos = tcp_tos(so);
-         if (so->so_iptos == 0) {
-             switch (af) {
-             case AF_INET:
-                 so->so_iptos = ((struct ip *)ti)->ip_tos;
-                 break;
-             case AF_INET6:
-                 break;
-             default:
-                 g_assert_not_reached();
-             }
-         }
-
-         tp = sototcpcb(so);
-         tp->t_state = TCPS_LISTEN;
-       }
-
-        /*
-         * If this is a still-connecting socket, this probably
-         * a retransmit of the SYN.  Whether it's a retransmit SYN
-        * or something else, we nuke it.
-         */
-        if (so->so_state & SS_ISFCONNECTING)
-                goto drop;
-
-       tp = sototcpcb(so);
-
-       /* XXX Should never fail */
-        if (tp == NULL)
-               goto dropwithreset;
-       if (tp->t_state == TCPS_CLOSED)
-               goto drop;
-
-       tiwin = ti->ti_win;
-
-       /*
-        * Segment received on connection.
-        * Reset idle time and keep-alive timer.
-        */
-       tp->t_idle = 0;
-       if (slirp_do_keepalive)
-          tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
-       else
-          tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
-
-       /*
-        * Process options if not in LISTEN state,
-        * else do it below (after getting remote address).
-        */
-       if (optp && tp->t_state != TCPS_LISTEN)
-               tcp_dooptions(tp, (uint8_t *)optp, optlen, ti);
-
-       /*
-        * Header prediction: check for the two common cases
-        * of a uni-directional data xfer.  If the packet has
-        * no control flags, is in-sequence, the window didn't
-        * change and we're not retransmitting, it's a
-        * candidate.  If the length is zero and the ack moved
-        * forward, we're the sender side of the xfer.  Just
-        * free the data acked & wake any higher level process
-        * that was blocked waiting for space.  If the length
-        * is non-zero and the ack didn't move, we're the
-        * receiver side.  If we're getting packets in-order
-        * (the reassembly queue is empty), add the data to
-        * the socket buffer and note that we need a delayed ack.
-        *
-        * XXX Some of these tests are not needed
-        * eg: the tiwin == tp->snd_wnd prevents many more
-        * predictions.. with no *real* advantage..
-        */
-       if (tp->t_state == TCPS_ESTABLISHED &&
-           (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&
-           ti->ti_seq == tp->rcv_nxt &&
-           tiwin && tiwin == tp->snd_wnd &&
-           tp->snd_nxt == tp->snd_max) {
-               if (ti->ti_len == 0) {
-                       if (SEQ_GT(ti->ti_ack, tp->snd_una) &&
-                           SEQ_LEQ(ti->ti_ack, tp->snd_max) &&
-                           tp->snd_cwnd >= tp->snd_wnd) {
-                               /*
-                                * this is a pure ack for outstanding data.
-                                */
-                               if (tp->t_rtt &&
-                                   SEQ_GT(ti->ti_ack, tp->t_rtseq))
-                                       tcp_xmit_timer(tp, tp->t_rtt);
-                               acked = ti->ti_ack - tp->snd_una;
-                               sodrop(so, acked);
-                               tp->snd_una = ti->ti_ack;
-                               m_free(m);
-
-                               /*
-                                * If all outstanding data are acked, stop
-                                * retransmit timer, otherwise restart timer
-                                * using current (possibly backed-off) value.
-                                * If process is waiting for space,
-                                * wakeup/selwakeup/signal.  If data
-                                * are ready to send, let tcp_output
-                                * decide between more output or persist.
-                                */
-                               if (tp->snd_una == tp->snd_max)
-                                       tp->t_timer[TCPT_REXMT] = 0;
-                               else if (tp->t_timer[TCPT_PERSIST] == 0)
-                                       tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
-
-                               /*
-                                * This is called because sowwakeup might have
-                                * put data into so_snd.  Since we don't so sowwakeup,
-                                * we don't need this.. XXX???
-                                */
-                               if (so->so_snd.sb_cc)
-                                       (void) tcp_output(tp);
-
-                               return;
-                       }
-               } else if (ti->ti_ack == tp->snd_una &&
-                   tcpfrag_list_empty(tp) &&
-                   ti->ti_len <= sbspace(&so->so_rcv)) {
-                       /*
-                        * this is a pure, in-sequence data packet
-                        * with nothing on the reassembly queue and
-                        * we have enough buffer space to take it.
-                        */
-                       tp->rcv_nxt += ti->ti_len;
-                       /*
-                        * Add data to socket buffer.
-                        */
-                       if (so->so_emu) {
-                               if (tcp_emu(so,m)) sbappend(so, m);
-                       } else
-                               sbappend(so, m);
-
-                       /*
-                        * If this is a short packet, then ACK now - with Nagel
-                        *      congestion avoidance sender won't send more until
-                        *      he gets an ACK.
-                        *
-                        * It is better to not delay acks at all to maximize
-                        * TCP throughput.  See RFC 2581.
-                        */
-                       tp->t_flags |= TF_ACKNOW;
-                       tcp_output(tp);
-                       return;
-               }
-       } /* header prediction */
-       /*
-        * Calculate amount of space in receive window,
-        * and then do TCP input processing.
-        * Receive window is amount of space in rcv queue,
-        * but not less than advertised window.
-        */
-       { int win;
-          win = sbspace(&so->so_rcv);
-         if (win < 0)
-           win = 0;
-          tp->rcv_wnd = MAX(win, (int)(tp->rcv_adv - tp->rcv_nxt));
-       }
-
-       switch (tp->t_state) {
-
-       /*
-        * If the state is LISTEN then ignore segment if it contains an RST.
-        * If the segment contains an ACK then it is bad and send a RST.
-        * If it does not contain a SYN then it is not interesting; drop it.
-        * Don't bother responding if the destination was a broadcast.
-        * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial
-        * tp->iss, and send a segment:
-        *     <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>
-        * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss.
-        * Fill in remote peer address fields if not previously specified.
-        * Enter SYN_RECEIVED state, and process any other fields of this
-        * segment in this state.
-        */
-       case TCPS_LISTEN: {
-
-         if (tiflags & TH_RST)
-           goto drop;
-         if (tiflags & TH_ACK)
-           goto dropwithreset;
-         if ((tiflags & TH_SYN) == 0)
-           goto drop;
-
-         /*
-          * This has way too many gotos...
-          * But a bit of spaghetti code never hurt anybody :)
-          */
-
-         /*
-          * If this is destined for the control address, then flag to
-          * tcp_ctl once connected, otherwise connect
-          */
-         if (af == AF_INET &&
-                (so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
-                slirp->vnetwork_addr.s_addr) {
-           if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr &&
-               so->so_faddr.s_addr != slirp->vnameserver_addr.s_addr) {
-               /* May be an add exec */
-               for (ex_ptr = slirp->guestfwd_list; ex_ptr;
-                    ex_ptr = ex_ptr->ex_next) {
-                 if(ex_ptr->ex_fport == so->so_fport &&
-                    so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
-                   so->so_state |= SS_CTL;
-                   break;
-                 }
-               }
-               if (so->so_state & SS_CTL) {
-                   goto cont_input;
-               }
-           }
-           /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */
-         }
-
-         if (so->so_emu & EMU_NOCONNECT) {
-           so->so_emu &= ~EMU_NOCONNECT;
-           goto cont_input;
-         }
-
-         if ((tcp_fconnect(so, so->so_ffamily) == -1) &&
-              (errno != EAGAIN) &&
-              (errno != EINPROGRESS) && (errno != EWOULDBLOCK)
-          ) {
-           uint8_t code;
-           DEBUG_MISC(" tcp fconnect errno = %d-%s", errno, strerror(errno));
-           if(errno == ECONNREFUSED) {
-             /* ACK the SYN, send RST to refuse the connection */
-             tcp_respond(tp, ti, m, ti->ti_seq + 1, (tcp_seq) 0,
-                         TH_RST | TH_ACK, af);
-           } else {
-             switch (af) {
-             case AF_INET:
-               code = ICMP_UNREACH_NET;
-               if (errno == EHOSTUNREACH) {
-                 code = ICMP_UNREACH_HOST;
-               }
-               break;
-             case AF_INET6:
-               code = ICMP6_UNREACH_NO_ROUTE;
-               if (errno == EHOSTUNREACH) {
-                 code = ICMP6_UNREACH_ADDRESS;
-               }
-               break;
-             default:
-               g_assert_not_reached();
-             }
-             HTONL(ti->ti_seq);             /* restore tcp header */
-             HTONL(ti->ti_ack);
-             HTONS(ti->ti_win);
-             HTONS(ti->ti_urp);
-             m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
-             m->m_len  += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
-             switch (af) {
-             case AF_INET:
-               m->m_data += sizeof(struct tcpiphdr) - sizeof(struct ip)
-                                                    - sizeof(struct tcphdr);
-               m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct ip)
-                                                    - sizeof(struct tcphdr);
-               *ip = save_ip;
-               icmp_send_error(m, ICMP_UNREACH, code, 0, strerror(errno));
-               break;
-             case AF_INET6:
-               m->m_data += sizeof(struct tcpiphdr) - (sizeof(struct ip6)
-                                                    + sizeof(struct tcphdr));
-               m->m_len  -= sizeof(struct tcpiphdr) - (sizeof(struct ip6)
-                                                    + sizeof(struct tcphdr));
-               *ip6 = save_ip6;
-               icmp6_send_error(m, ICMP6_UNREACH, code);
-               break;
-             default:
-               g_assert_not_reached();
-             }
-           }
-            tcp_close(tp);
-           m_free(m);
-         } else {
-           /*
-            * Haven't connected yet, save the current mbuf
-            * and ti, and return
-            * XXX Some OS's don't tell us whether the connect()
-            * succeeded or not.  So we must time it out.
-            */
-           so->so_m = m;
-           so->so_ti = ti;
-           tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
-           tp->t_state = TCPS_SYN_RECEIVED;
-           /*
-            * Initialize receive sequence numbers now so that we can send a
-            * valid RST if the remote end rejects our connection.
-            */
-           tp->irs = ti->ti_seq;
-           tcp_rcvseqinit(tp);
-           tcp_template(tp);
-         }
-         return;
-
-       cont_conn:
-         /* m==NULL
-          * Check if the connect succeeded
-          */
-         if (so->so_state & SS_NOFDREF) {
-           tp = tcp_close(tp);
-           goto dropwithreset;
-         }
-       cont_input:
-         tcp_template(tp);
-
-         if (optp)
-           tcp_dooptions(tp, (uint8_t *)optp, optlen, ti);
-
-         if (iss)
-           tp->iss = iss;
-         else
-           tp->iss = slirp->tcp_iss;
-         slirp->tcp_iss += TCP_ISSINCR/2;
-         tp->irs = ti->ti_seq;
-         tcp_sendseqinit(tp);
-         tcp_rcvseqinit(tp);
-         tp->t_flags |= TF_ACKNOW;
-         tp->t_state = TCPS_SYN_RECEIVED;
-         tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
-         goto trimthenstep6;
-       } /* case TCPS_LISTEN */
-
-       /*
-        * If the state is SYN_SENT:
-        *      if seg contains an ACK, but not for our SYN, drop the input.
-        *      if seg contains a RST, then drop the connection.
-        *      if seg does not contain SYN, then drop it.
-        * Otherwise this is an acceptable SYN segment
-        *      initialize tp->rcv_nxt and tp->irs
-        *      if seg contains ack then advance tp->snd_una
-        *      if SYN has been acked change to ESTABLISHED else SYN_RCVD state
-        *      arrange for segment to be acked (eventually)
-        *      continue processing rest of data/controls, beginning with URG
-        */
-       case TCPS_SYN_SENT:
-               if ((tiflags & TH_ACK) &&
-                   (SEQ_LEQ(ti->ti_ack, tp->iss) ||
-                    SEQ_GT(ti->ti_ack, tp->snd_max)))
-                       goto dropwithreset;
-
-               if (tiflags & TH_RST) {
-                        if (tiflags & TH_ACK) {
-                                tcp_drop(tp, 0); /* XXX Check t_softerror! */
-                        }
-                       goto drop;
-               }
-
-               if ((tiflags & TH_SYN) == 0)
-                       goto drop;
-               if (tiflags & TH_ACK) {
-                       tp->snd_una = ti->ti_ack;
-                       if (SEQ_LT(tp->snd_nxt, tp->snd_una))
-                               tp->snd_nxt = tp->snd_una;
-               }
-
-               tp->t_timer[TCPT_REXMT] = 0;
-               tp->irs = ti->ti_seq;
-               tcp_rcvseqinit(tp);
-               tp->t_flags |= TF_ACKNOW;
-               if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) {
-                       soisfconnected(so);
-                       tp->t_state = TCPS_ESTABLISHED;
-
-                       (void) tcp_reass(tp, (struct tcpiphdr *)0,
-                               (struct mbuf *)0);
-                       /*
-                        * if we didn't have to retransmit the SYN,
-                        * use its rtt as our initial srtt & rtt var.
-                        */
-                       if (tp->t_rtt)
-                               tcp_xmit_timer(tp, tp->t_rtt);
-               } else
-                       tp->t_state = TCPS_SYN_RECEIVED;
-
-trimthenstep6:
-               /*
-                * Advance ti->ti_seq to correspond to first data byte.
-                * If data, trim to stay within window,
-                * dropping FIN if necessary.
-                */
-               ti->ti_seq++;
-               if (ti->ti_len > tp->rcv_wnd) {
-                       todrop = ti->ti_len - tp->rcv_wnd;
-                       m_adj(m, -todrop);
-                       ti->ti_len = tp->rcv_wnd;
-                       tiflags &= ~TH_FIN;
-               }
-               tp->snd_wl1 = ti->ti_seq - 1;
-               tp->rcv_up = ti->ti_seq;
-               goto step6;
-       } /* switch tp->t_state */
-       /*
-        * States other than LISTEN or SYN_SENT.
-        * Check that at least some bytes of segment are within
-        * receive window.  If segment begins before rcv_nxt,
-        * drop leading data (and SYN); if nothing left, just ack.
-        */
-       todrop = tp->rcv_nxt - ti->ti_seq;
-       if (todrop > 0) {
-               if (tiflags & TH_SYN) {
-                       tiflags &= ~TH_SYN;
-                       ti->ti_seq++;
-                       if (ti->ti_urp > 1)
-                               ti->ti_urp--;
-                       else
-                               tiflags &= ~TH_URG;
-                       todrop--;
-               }
-               /*
-                * Following if statement from Stevens, vol. 2, p. 960.
-                */
-               if (todrop > ti->ti_len
-                   || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) {
-                       /*
-                        * Any valid FIN must be to the left of the window.
-                        * At this point the FIN must be a duplicate or out
-                        * of sequence; drop it.
-                        */
-                       tiflags &= ~TH_FIN;
-
-                       /*
-                        * Send an ACK to resynchronize and drop any data.
-                        * But keep on processing for RST or ACK.
-                        */
-                       tp->t_flags |= TF_ACKNOW;
-                       todrop = ti->ti_len;
-               }
-               m_adj(m, todrop);
-               ti->ti_seq += todrop;
-               ti->ti_len -= todrop;
-               if (ti->ti_urp > todrop)
-                       ti->ti_urp -= todrop;
-               else {
-                       tiflags &= ~TH_URG;
-                       ti->ti_urp = 0;
-               }
-       }
-       /*
-        * If new data are received on a connection after the
-        * user processes are gone, then RST the other end.
-        */
-       if ((so->so_state & SS_NOFDREF) &&
-           tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) {
-               tp = tcp_close(tp);
-               goto dropwithreset;
-       }
-
-       /*
-        * If segment ends after window, drop trailing data
-        * (and PUSH and FIN); if nothing left, just ACK.
-        */
-       todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd);
-       if (todrop > 0) {
-               if (todrop >= ti->ti_len) {
-                       /*
-                        * If a new connection request is received
-                        * while in TIME_WAIT, drop the old connection
-                        * and start over if the sequence numbers
-                        * are above the previous ones.
-                        */
-                       if (tiflags & TH_SYN &&
-                           tp->t_state == TCPS_TIME_WAIT &&
-                           SEQ_GT(ti->ti_seq, tp->rcv_nxt)) {
-                               iss = tp->rcv_nxt + TCP_ISSINCR;
-                               tp = tcp_close(tp);
-                               goto findso;
-                       }
-                       /*
-                        * If window is closed can only take segments at
-                        * window edge, and have to drop data and PUSH from
-                        * incoming segments.  Continue processing, but
-                        * remember to ack.  Otherwise, drop segment
-                        * and ack.
-                        */
-                       if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) {
-                               tp->t_flags |= TF_ACKNOW;
-                       } else {
-                               goto dropafterack;
-                       }
-               }
-               m_adj(m, -todrop);
-               ti->ti_len -= todrop;
-               tiflags &= ~(TH_PUSH|TH_FIN);
-       }
-
-       /*
-        * If the RST bit is set examine the state:
-        *    SYN_RECEIVED STATE:
-        *      If passive open, return to LISTEN state.
-        *      If active open, inform user that connection was refused.
-        *    ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES:
-        *      Inform user that connection was reset, and close tcb.
-        *    CLOSING, LAST_ACK, TIME_WAIT STATES
-        *      Close the tcb.
-        */
-       if (tiflags&TH_RST) switch (tp->t_state) {
-
-       case TCPS_SYN_RECEIVED:
-       case TCPS_ESTABLISHED:
-       case TCPS_FIN_WAIT_1:
-       case TCPS_FIN_WAIT_2:
-       case TCPS_CLOSE_WAIT:
-               tp->t_state = TCPS_CLOSED;
-                tcp_close(tp);
-               goto drop;
-
-       case TCPS_CLOSING:
-       case TCPS_LAST_ACK:
-       case TCPS_TIME_WAIT:
-                tcp_close(tp);
-               goto drop;
-       }
-
-       /*
-        * If a SYN is in the window, then this is an
-        * error and we send an RST and drop the connection.
-        */
-       if (tiflags & TH_SYN) {
-               tp = tcp_drop(tp,0);
-               goto dropwithreset;
-       }
-
-       /*
-        * If the ACK bit is off we drop the segment and return.
-        */
-       if ((tiflags & TH_ACK) == 0) goto drop;
-
-       /*
-        * Ack processing.
-        */
-       switch (tp->t_state) {
-       /*
-        * In SYN_RECEIVED state if the ack ACKs our SYN then enter
-        * ESTABLISHED state and continue processing, otherwise
-        * send an RST.  una<=ack<=max
-        */
-       case TCPS_SYN_RECEIVED:
-
-               if (SEQ_GT(tp->snd_una, ti->ti_ack) ||
-                   SEQ_GT(ti->ti_ack, tp->snd_max))
-                       goto dropwithreset;
-               tp->t_state = TCPS_ESTABLISHED;
-               /*
-                * The sent SYN is ack'ed with our sequence number +1
-                * The first data byte already in the buffer will get
-                * lost if no correction is made.  This is only needed for
-                * SS_CTL since the buffer is empty otherwise.
-                * tp->snd_una++; or:
-                */
-               tp->snd_una=ti->ti_ack;
-               if (so->so_state & SS_CTL) {
-                 /* So tcp_ctl reports the right state */
-                 ret = tcp_ctl(so);
-                 if (ret == 1) {
-                   soisfconnected(so);
-                   so->so_state &= ~SS_CTL;   /* success XXX */
-                 } else if (ret == 2) {
-                   so->so_state &= SS_PERSISTENT_MASK;
-                   so->so_state |= SS_NOFDREF; /* CTL_CMD */
-                 } else {
-                   needoutput = 1;
-                   tp->t_state = TCPS_FIN_WAIT_1;
-                 }
-               } else {
-                 soisfconnected(so);
-               }
-
-               (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);
-               tp->snd_wl1 = ti->ti_seq - 1;
-               /* Avoid ack processing; snd_una==ti_ack  =>  dup ack */
-               goto synrx_to_est;
-               /* fall into ... */
-
-       /*
-        * In ESTABLISHED state: drop duplicate ACKs; ACK out of range
-        * ACKs.  If the ack is in the range
-        *      tp->snd_una < ti->ti_ack <= tp->snd_max
-        * then advance tp->snd_una to ti->ti_ack and drop
-        * data from the retransmission queue.  If this ACK reflects
-        * more up to date window information we update our window information.
-        */
-       case TCPS_ESTABLISHED:
-       case TCPS_FIN_WAIT_1:
-       case TCPS_FIN_WAIT_2:
-       case TCPS_CLOSE_WAIT:
-       case TCPS_CLOSING:
-       case TCPS_LAST_ACK:
-       case TCPS_TIME_WAIT:
-
-               if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
-                       if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {
-                         DEBUG_MISC(" dup ack  m = %p  so = %p", m, so);
-                               /*
-                                * If we have outstanding data (other than
-                                * a window probe), this is a completely
-                                * duplicate ack (ie, window info didn't
-                                * change), the ack is the biggest we've
-                                * seen and we've seen exactly our rexmt
-                                * threshold of them, assume a packet
-                                * has been dropped and retransmit it.
-                                * Kludge snd_nxt & the congestion
-                                * window so we send only this one
-                                * packet.
-                                *
-                                * We know we're losing at the current
-                                * window size so do congestion avoidance
-                                * (set ssthresh to half the current window
-                                * and pull our congestion window back to
-                                * the new ssthresh).
-                                *
-                                * Dup acks mean that packets have left the
-                                * network (they're now cached at the receiver)
-                                * so bump cwnd by the amount in the receiver
-                                * to keep a constant cwnd packets in the
-                                * network.
-                                */
-                               if (tp->t_timer[TCPT_REXMT] == 0 ||
-                                   ti->ti_ack != tp->snd_una)
-                                       tp->t_dupacks = 0;
-                               else if (++tp->t_dupacks == TCPREXMTTHRESH) {
-                                       tcp_seq onxt = tp->snd_nxt;
-                                       unsigned win =
-                                                MIN(tp->snd_wnd, tp->snd_cwnd) /
-                                                2 / tp->t_maxseg;
-
-                                       if (win < 2)
-                                               win = 2;
-                                       tp->snd_ssthresh = win * tp->t_maxseg;
-                                       tp->t_timer[TCPT_REXMT] = 0;
-                                       tp->t_rtt = 0;
-                                       tp->snd_nxt = ti->ti_ack;
-                                       tp->snd_cwnd = tp->t_maxseg;
-                                       (void) tcp_output(tp);
-                                       tp->snd_cwnd = tp->snd_ssthresh +
-                                              tp->t_maxseg * tp->t_dupacks;
-                                       if (SEQ_GT(onxt, tp->snd_nxt))
-                                               tp->snd_nxt = onxt;
-                                       goto drop;
-                               } else if (tp->t_dupacks > TCPREXMTTHRESH) {
-                                       tp->snd_cwnd += tp->t_maxseg;
-                                       (void) tcp_output(tp);
-                                       goto drop;
-                               }
-                       } else
-                               tp->t_dupacks = 0;
-                       break;
-               }
-       synrx_to_est:
-               /*
-                * If the congestion window was inflated to account
-                * for the other side's cached packets, retract it.
-                */
-               if (tp->t_dupacks > TCPREXMTTHRESH &&
-                   tp->snd_cwnd > tp->snd_ssthresh)
-                       tp->snd_cwnd = tp->snd_ssthresh;
-               tp->t_dupacks = 0;
-               if (SEQ_GT(ti->ti_ack, tp->snd_max)) {
-                       goto dropafterack;
-               }
-               acked = ti->ti_ack - tp->snd_una;
-
-               /*
-                * If transmit timer is running and timed sequence
-                * number was acked, update smoothed round trip time.
-                * Since we now have an rtt measurement, cancel the
-                * timer backoff (cf., Phil Karn's retransmit alg.).
-                * Recompute the initial retransmit timer.
-                */
-               if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq))
-                       tcp_xmit_timer(tp,tp->t_rtt);
-
-               /*
-                * If all outstanding data is acked, stop retransmit
-                * timer and remember to restart (more output or persist).
-                * If there is more data to be acked, restart retransmit
-                * timer, using current (possibly backed-off) value.
-                */
-               if (ti->ti_ack == tp->snd_max) {
-                       tp->t_timer[TCPT_REXMT] = 0;
-                       needoutput = 1;
-               } else if (tp->t_timer[TCPT_PERSIST] == 0)
-                       tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
-               /*
-                * When new data is acked, open the congestion window.
-                * If the window gives us less than ssthresh packets
-                * in flight, open exponentially (maxseg per packet).
-                * Otherwise open linearly: maxseg per window
-                * (maxseg^2 / cwnd per packet).
-                */
-               {
-                 register unsigned cw = tp->snd_cwnd;
-                 register unsigned incr = tp->t_maxseg;
-
-                 if (cw > tp->snd_ssthresh)
-                   incr = incr * incr / cw;
-                  tp->snd_cwnd = MIN(cw + incr, TCP_MAXWIN << tp->snd_scale);
-               }
-               if (acked > so->so_snd.sb_cc) {
-                       tp->snd_wnd -= so->so_snd.sb_cc;
-                       sodrop(so, (int)so->so_snd.sb_cc);
-                       ourfinisacked = 1;
-               } else {
-                       sodrop(so, acked);
-                       tp->snd_wnd -= acked;
-                       ourfinisacked = 0;
-               }
-               tp->snd_una = ti->ti_ack;
-               if (SEQ_LT(tp->snd_nxt, tp->snd_una))
-                       tp->snd_nxt = tp->snd_una;
-
-               switch (tp->t_state) {
-
-               /*
-                * In FIN_WAIT_1 STATE in addition to the processing
-                * for the ESTABLISHED state if our FIN is now acknowledged
-                * then enter FIN_WAIT_2.
-                */
-               case TCPS_FIN_WAIT_1:
-                       if (ourfinisacked) {
-                               /*
-                                * If we can't receive any more
-                                * data, then closing user can proceed.
-                                * Starting the timer is contrary to the
-                                * specification, but if we don't get a FIN
-                                * we'll hang forever.
-                                */
-                               if (so->so_state & SS_FCANTRCVMORE) {
-                                       tp->t_timer[TCPT_2MSL] = TCP_MAXIDLE;
-                               }
-                               tp->t_state = TCPS_FIN_WAIT_2;
-                       }
-                       break;
-
-               /*
-                * In CLOSING STATE in addition to the processing for
-                * the ESTABLISHED state if the ACK acknowledges our FIN
-                * then enter the TIME-WAIT state, otherwise ignore
-                * the segment.
-                */
-               case TCPS_CLOSING:
-                       if (ourfinisacked) {
-                               tp->t_state = TCPS_TIME_WAIT;
-                               tcp_canceltimers(tp);
-                               tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
-                       }
-                       break;
-
-               /*
-                * In LAST_ACK, we may still be waiting for data to drain
-                * and/or to be acked, as well as for the ack of our FIN.
-                * If our FIN is now acknowledged, delete the TCB,
-                * enter the closed state and return.
-                */
-               case TCPS_LAST_ACK:
-                       if (ourfinisacked) {
-                                tcp_close(tp);
-                               goto drop;
-                       }
-                       break;
-
-               /*
-                * In TIME_WAIT state the only thing that should arrive
-                * is a retransmission of the remote FIN.  Acknowledge
-                * it and restart the finack timer.
-                */
-               case TCPS_TIME_WAIT:
-                       tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
-                       goto dropafterack;
-               }
-       } /* switch(tp->t_state) */
-
-step6:
-       /*
-        * Update window information.
-        * Don't look at window if no ACK: TAC's send garbage on first SYN.
-        */
-       if ((tiflags & TH_ACK) &&
-           (SEQ_LT(tp->snd_wl1, ti->ti_seq) ||
-           (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||
-           (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) {
-               tp->snd_wnd = tiwin;
-               tp->snd_wl1 = ti->ti_seq;
-               tp->snd_wl2 = ti->ti_ack;
-               if (tp->snd_wnd > tp->max_sndwnd)
-                       tp->max_sndwnd = tp->snd_wnd;
-               needoutput = 1;
-       }
-
-       /*
-        * Process segments with URG.
-        */
-       if ((tiflags & TH_URG) && ti->ti_urp &&
-           TCPS_HAVERCVDFIN(tp->t_state) == 0) {
-               /*
-                * This is a kludge, but if we receive and accept
-                * random urgent pointers, we'll crash in
-                * soreceive.  It's hard to imagine someone
-                * actually wanting to send this much urgent data.
-                */
-               if (ti->ti_urp + so->so_rcv.sb_cc > so->so_rcv.sb_datalen) {
-                       ti->ti_urp = 0;
-                       tiflags &= ~TH_URG;
-                       goto dodata;
-               }
-               /*
-                * If this segment advances the known urgent pointer,
-                * then mark the data stream.  This should not happen
-                * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since
-                * a FIN has been received from the remote side.
-                * In these states we ignore the URG.
-                *
-                * According to RFC961 (Assigned Protocols),
-                * the urgent pointer points to the last octet
-                * of urgent data.  We continue, however,
-                * to consider it to indicate the first octet
-                * of data past the urgent section as the original
-                * spec states (in one of two places).
-                */
-               if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) {
-                       tp->rcv_up = ti->ti_seq + ti->ti_urp;
-                       so->so_urgc =  so->so_rcv.sb_cc +
-                               (tp->rcv_up - tp->rcv_nxt); /* -1; */
-                       tp->rcv_up = ti->ti_seq + ti->ti_urp;
-
-               }
-       } else
-               /*
-                * If no out of band data is expected,
-                * pull receive urgent pointer along
-                * with the receive window.
-                */
-               if (SEQ_GT(tp->rcv_nxt, tp->rcv_up))
-                       tp->rcv_up = tp->rcv_nxt;
-dodata:
-
-       /*
-        * If this is a small packet, then ACK now - with Nagel
-        *      congestion avoidance sender won't send more until
-        *      he gets an ACK.
-        */
-       if (ti->ti_len && (unsigned)ti->ti_len <= 5 &&
-           ((struct tcpiphdr_2 *)ti)->first_char == (char)27) {
-               tp->t_flags |= TF_ACKNOW;
-       }
-
-       /*
-        * Process the segment text, merging it into the TCP sequencing queue,
-        * and arranging for acknowledgment of receipt if necessary.
-        * This process logically involves adjusting tp->rcv_wnd as data
-        * is presented to the user (this happens in tcp_usrreq.c,
-        * case PRU_RCVD).  If a FIN has already been received on this
-        * connection then we just ignore the text.
-        */
-       if ((ti->ti_len || (tiflags&TH_FIN)) &&
-           TCPS_HAVERCVDFIN(tp->t_state) == 0) {
-               TCP_REASS(tp, ti, m, so, tiflags);
-       } else {
-               m_free(m);
-               tiflags &= ~TH_FIN;
-       }
-
-       /*
-        * If FIN is received ACK the FIN and let the user know
-        * that the connection is closing.
-        */
-       if (tiflags & TH_FIN) {
-               if (TCPS_HAVERCVDFIN(tp->t_state) == 0) {
-                       /*
-                        * If we receive a FIN we can't send more data,
-                        * set it SS_FDRAIN
-                         * Shutdown the socket if there is no rx data in the
-                        * buffer.
-                        * soread() is called on completion of shutdown() and
-                        * will got to TCPS_LAST_ACK, and use tcp_output()
-                        * to send the FIN.
-                        */
-                       sofwdrain(so);
-
-                       tp->t_flags |= TF_ACKNOW;
-                       tp->rcv_nxt++;
-               }
-               switch (tp->t_state) {
-
-               /*
-                * In SYN_RECEIVED and ESTABLISHED STATES
-                * enter the CLOSE_WAIT state.
-                */
-               case TCPS_SYN_RECEIVED:
-               case TCPS_ESTABLISHED:
-                 if(so->so_emu == EMU_CTL)        /* no shutdown on socket */
-                   tp->t_state = TCPS_LAST_ACK;
-                 else
-                   tp->t_state = TCPS_CLOSE_WAIT;
-                 break;
-
-               /*
-                * If still in FIN_WAIT_1 STATE FIN has not been acked so
-                * enter the CLOSING state.
-                */
-               case TCPS_FIN_WAIT_1:
-                       tp->t_state = TCPS_CLOSING;
-                       break;
-
-               /*
-                * In FIN_WAIT_2 state enter the TIME_WAIT state,
-                * starting the time-wait timer, turning off the other
-                * standard timers.
-                */
-               case TCPS_FIN_WAIT_2:
-                       tp->t_state = TCPS_TIME_WAIT;
-                       tcp_canceltimers(tp);
-                       tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
-                       break;
-
-               /*
-                * In TIME_WAIT state restart the 2 MSL time_wait timer.
-                */
-               case TCPS_TIME_WAIT:
-                       tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
-                       break;
-               }
-       }
-
-       /*
-        * Return any desired output.
-        */
-       if (needoutput || (tp->t_flags & TF_ACKNOW)) {
-               (void) tcp_output(tp);
-       }
-       return;
-
-dropafterack:
-       /*
-        * Generate an ACK dropping incoming segment if it occupies
-        * sequence space, where the ACK reflects our state.
-        */
-       if (tiflags & TH_RST)
-               goto drop;
-       m_free(m);
-       tp->t_flags |= TF_ACKNOW;
-       (void) tcp_output(tp);
-       return;
-
-dropwithreset:
-       /* reuses m if m!=NULL, m_free() unnecessary */
-       if (tiflags & TH_ACK)
-               tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST, af);
-       else {
-               if (tiflags & TH_SYN) ti->ti_len++;
-               tcp_respond(tp, ti, m, ti->ti_seq + ti->ti_len, (tcp_seq) 0,
-                   TH_RST | TH_ACK, af);
-       }
-
-       return;
-
-drop:
-       /*
-        * Drop space held by incoming segment and return.
-        */
-       m_free(m);
-}
-
-static void
-tcp_dooptions(struct tcpcb *tp, uint8_t *cp, int cnt, struct tcpiphdr *ti)
-{
-       uint16_t mss;
-       int opt, optlen;
-
-       DEBUG_CALL("tcp_dooptions");
-       DEBUG_ARG("tp = %p  cnt=%i", tp, cnt);
-
-       for (; cnt > 0; cnt -= optlen, cp += optlen) {
-               opt = cp[0];
-               if (opt == TCPOPT_EOL)
-                       break;
-               if (opt == TCPOPT_NOP)
-                       optlen = 1;
-               else {
-                       optlen = cp[1];
-                       if (optlen <= 0)
-                               break;
-               }
-               switch (opt) {
-
-               default:
-                       continue;
-
-               case TCPOPT_MAXSEG:
-                       if (optlen != TCPOLEN_MAXSEG)
-                               continue;
-                       if (!(ti->ti_flags & TH_SYN))
-                               continue;
-                       memcpy((char *) &mss, (char *) cp + 2, sizeof(mss));
-                       NTOHS(mss);
-                       (void) tcp_mss(tp, mss);        /* sets t_maxseg */
-                       break;
-               }
-       }
-}
-
-/*
- * Collect new round-trip time estimate
- * and update averages and current timeout.
- */
-
-static void
-tcp_xmit_timer(register struct tcpcb *tp, int rtt)
-{
-       register short delta;
-
-       DEBUG_CALL("tcp_xmit_timer");
-       DEBUG_ARG("tp = %p", tp);
-       DEBUG_ARG("rtt = %d", rtt);
-
-       if (tp->t_srtt != 0) {
-               /*
-                * srtt is stored as fixed point with 3 bits after the
-                * binary point (i.e., scaled by 8).  The following magic
-                * is equivalent to the smoothing algorithm in rfc793 with
-                * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed
-                * point).  Adjust rtt to origin 0.
-                */
-               delta = rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT);
-               if ((tp->t_srtt += delta) <= 0)
-                       tp->t_srtt = 1;
-               /*
-                * We accumulate a smoothed rtt variance (actually, a
-                * smoothed mean difference), then set the retransmit
-                * timer to smoothed rtt + 4 times the smoothed variance.
-                * rttvar is stored as fixed point with 2 bits after the
-                * binary point (scaled by 4).  The following is
-                * equivalent to rfc793 smoothing with an alpha of .75
-                * (rttvar = rttvar*3/4 + |delta| / 4).  This replaces
-                * rfc793's wired-in beta.
-                */
-               if (delta < 0)
-                       delta = -delta;
-               delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT);
-               if ((tp->t_rttvar += delta) <= 0)
-                       tp->t_rttvar = 1;
-       } else {
-               /*
-                * No rtt measurement yet - use the unsmoothed rtt.
-                * Set the variance to half the rtt (so our first
-                * retransmit happens at 3*rtt).
-                */
-               tp->t_srtt = rtt << TCP_RTT_SHIFT;
-               tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1);
-       }
-       tp->t_rtt = 0;
-       tp->t_rxtshift = 0;
-
-       /*
-        * the retransmit should happen at rtt + 4 * rttvar.
-        * Because of the way we do the smoothing, srtt and rttvar
-        * will each average +1/2 tick of bias.  When we compute
-        * the retransmit timer, we want 1/2 tick of rounding and
-        * 1 extra tick because of +-1/2 tick uncertainty in the
-        * firing of the timer.  The bias will give us exactly the
-        * 1.5 tick we need.  But, because the bias is
-        * statistical, we have to test that we don't drop below
-        * the minimum feasible timer (which is 2 ticks).
-        */
-       TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp),
-           (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */
-
-       /*
-        * We received an ack for a packet that wasn't retransmitted;
-        * it is probably safe to discard any error indications we've
-        * received recently.  This isn't quite right, but close enough
-        * for now (a route might have failed after we sent a segment,
-        * and the return path might not be symmetrical).
-        */
-       tp->t_softerror = 0;
-}
-
-/*
- * Determine a reasonable value for maxseg size.
- * If the route is known, check route for mtu.
- * If none, use an mss that can be handled on the outgoing
- * interface without forcing IP to fragment; if bigger than
- * an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES
- * to utilize large mbufs.  If no route is found, route has no mtu,
- * or the destination isn't local, use a default, hopefully conservative
- * size (usually 512 or the default IP max size, but no more than the mtu
- * of the interface), as we can't discover anything about intervening
- * gateways or networks.  We also initialize the congestion/slow start
- * window to be a single segment if the destination isn't local.
- * While looking at the routing entry, we also initialize other path-dependent
- * parameters from pre-set or cached values in the routing entry.
- */
-
-int
-tcp_mss(struct tcpcb *tp, unsigned offer)
-{
-       struct socket *so = tp->t_socket;
-       int mss;
-
-       DEBUG_CALL("tcp_mss");
-       DEBUG_ARG("tp = %p", tp);
-       DEBUG_ARG("offer = %d", offer);
-
-       switch (so->so_ffamily) {
-       case AF_INET:
-            mss = MIN(IF_MTU, IF_MRU) - sizeof(struct tcphdr)
-                                     - sizeof(struct ip);
-           break;
-       case AF_INET6:
-            mss = MIN(IF_MTU, IF_MRU) - sizeof(struct tcphdr)
-                                     - sizeof(struct ip6);
-           break;
-       default:
-           g_assert_not_reached();
-       }
-
-       if (offer)
-            mss = MIN(mss, offer);
-        mss = MAX(mss, 32);
-       if (mss < tp->t_maxseg || offer != 0)
-          tp->t_maxseg = mss;
-
-       tp->snd_cwnd = mss;
-
-       sbreserve(&so->so_snd, TCP_SNDSPACE + ((TCP_SNDSPACE % mss) ?
-                                               (mss - (TCP_SNDSPACE % mss)) :
-                                               0));
-       sbreserve(&so->so_rcv, TCP_RCVSPACE + ((TCP_RCVSPACE % mss) ?
-                                               (mss - (TCP_RCVSPACE % mss)) :
-                                               0));
-
-       DEBUG_MISC(" returning mss = %d", mss);
-
-       return mss;
-}
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
deleted file mode 100644 (file)
index e9674df..0000000
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 1988, 1990, 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. 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.
- *
- *     @(#)tcp_output.c        8.3 (Berkeley) 12/30/93
- * tcp_output.c,v 1.3 1994/09/15 10:36:55 davidg Exp
- */
-
-/*
- * Changes and additions relating to SLiRP
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#include "slirp.h"
-
-static const uint8_t  tcp_outflags[TCP_NSTATES] = {
-       TH_RST|TH_ACK, 0,      TH_SYN,        TH_SYN|TH_ACK,
-       TH_ACK,        TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK,
-       TH_FIN|TH_ACK, TH_ACK, TH_ACK,
-};
-
-
-#undef MAX_TCPOPTLEN
-#define MAX_TCPOPTLEN  32      /* max # bytes that go in options */
-
-/*
- * Tcp output routine: figure out what should be sent and send it.
- */
-int
-tcp_output(struct tcpcb *tp)
-{
-       register struct socket *so = tp->t_socket;
-       register long len, win;
-       int off, flags, error;
-       register struct mbuf *m;
-       register struct tcpiphdr *ti, tcpiph_save;
-       struct ip *ip;
-       struct ip6 *ip6;
-       uint8_t opt[MAX_TCPOPTLEN];
-       unsigned optlen, hdrlen;
-       int idle, sendalot;
-
-       DEBUG_CALL("tcp_output");
-       DEBUG_ARG("tp = %p", tp);
-
-       /*
-        * Determine length of data that should be transmitted,
-        * and flags that will be used.
-        * If there is some data or critical controls (SYN, RST)
-        * to send, then transmit; otherwise, investigate further.
-        */
-       idle = (tp->snd_max == tp->snd_una);
-       if (idle && tp->t_idle >= tp->t_rxtcur)
-               /*
-                * We have been idle for "a while" and no acks are
-                * expected to clock out any data we send --
-                * slow start to get ack "clock" running again.
-                */
-               tp->snd_cwnd = tp->t_maxseg;
-again:
-       sendalot = 0;
-       off = tp->snd_nxt - tp->snd_una;
-        win = MIN(tp->snd_wnd, tp->snd_cwnd);
-
-       flags = tcp_outflags[tp->t_state];
-
-       DEBUG_MISC(" --- tcp_output flags = 0x%x", flags);
-
-       /*
-        * If in persist timeout with window of 0, send 1 byte.
-        * Otherwise, if window is small but nonzero
-        * and timer expired, we will send what we can
-        * and go to transmit state.
-        */
-       if (tp->t_force) {
-               if (win == 0) {
-                       /*
-                        * If we still have some data to send, then
-                        * clear the FIN bit.  Usually this would
-                        * happen below when it realizes that we
-                        * aren't sending all the data.  However,
-                        * if we have exactly 1 byte of unset data,
-                        * then it won't clear the FIN bit below,
-                        * and if we are in persist state, we wind
-                        * up sending the packet without recording
-                        * that we sent the FIN bit.
-                        *
-                        * We can't just blindly clear the FIN bit,
-                        * because if we don't have any more data
-                        * to send then the probe will be the FIN
-                        * itself.
-                        */
-                       if (off < so->so_snd.sb_cc)
-                               flags &= ~TH_FIN;
-                       win = 1;
-               } else {
-                       tp->t_timer[TCPT_PERSIST] = 0;
-                       tp->t_rxtshift = 0;
-               }
-       }
-
-        len = MIN(so->so_snd.sb_cc, win) - off;
-
-       if (len < 0) {
-               /*
-                * If FIN has been sent but not acked,
-                * but we haven't been called to retransmit,
-                * len will be -1.  Otherwise, window shrank
-                * after we sent into it.  If window shrank to 0,
-                * cancel pending retransmit and pull snd_nxt
-                * back to (closed) window.  We will enter persist
-                * state below.  If the window didn't close completely,
-                * just wait for an ACK.
-                */
-               len = 0;
-               if (win == 0) {
-                       tp->t_timer[TCPT_REXMT] = 0;
-                       tp->snd_nxt = tp->snd_una;
-               }
-       }
-
-       if (len > tp->t_maxseg) {
-               len = tp->t_maxseg;
-               sendalot = 1;
-       }
-       if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
-               flags &= ~TH_FIN;
-
-       win = sbspace(&so->so_rcv);
-
-       /*
-        * Sender silly window avoidance.  If connection is idle
-        * and can send all data, a maximum segment,
-        * at least a maximum default-size segment do it,
-        * or are forced, do it; otherwise don't bother.
-        * If peer's buffer is tiny, then send
-        * when window is at least half open.
-        * If retransmitting (possibly after persist timer forced us
-        * to send into a small window), then must resend.
-        */
-       if (len) {
-               if (len == tp->t_maxseg)
-                       goto send;
-               if ((1 || idle || tp->t_flags & TF_NODELAY) &&
-                   len + off >= so->so_snd.sb_cc)
-                       goto send;
-               if (tp->t_force)
-                       goto send;
-               if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0)
-                       goto send;
-               if (SEQ_LT(tp->snd_nxt, tp->snd_max))
-                       goto send;
-       }
-
-       /*
-        * Compare available window to amount of window
-        * known to peer (as advertised window less
-        * next expected input).  If the difference is at least two
-        * max size segments, or at least 50% of the maximum possible
-        * window, then want to send a window update to peer.
-        */
-       if (win > 0) {
-               /*
-                * "adv" is the amount we can increase the window,
-                * taking into account that we are limited by
-                * TCP_MAXWIN << tp->rcv_scale.
-                */
-                long adv = MIN(win, (long)TCP_MAXWIN << tp->rcv_scale) -
-                       (tp->rcv_adv - tp->rcv_nxt);
-
-               if (adv >= (long) (2 * tp->t_maxseg))
-                       goto send;
-               if (2 * adv >= (long) so->so_rcv.sb_datalen)
-                       goto send;
-       }
-
-       /*
-        * Send if we owe peer an ACK.
-        */
-       if (tp->t_flags & TF_ACKNOW)
-               goto send;
-       if (flags & (TH_SYN|TH_RST))
-               goto send;
-       if (SEQ_GT(tp->snd_up, tp->snd_una))
-               goto send;
-       /*
-        * If our state indicates that FIN should be sent
-        * and we have not yet done so, or we're retransmitting the FIN,
-        * then we need to send.
-        */
-       if (flags & TH_FIN &&
-           ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una))
-               goto send;
-
-       /*
-        * TCP window updates are not reliable, rather a polling protocol
-        * using ``persist'' packets is used to insure receipt of window
-        * updates.  The three ``states'' for the output side are:
-        *      idle                    not doing retransmits or persists
-        *      persisting              to move a small or zero window
-        *      (re)transmitting        and thereby not persisting
-        *
-        * tp->t_timer[TCPT_PERSIST]
-        *      is set when we are in persist state.
-        * tp->t_force
-        *      is set when we are called to send a persist packet.
-        * tp->t_timer[TCPT_REXMT]
-        *      is set when we are retransmitting
-        * The output side is idle when both timers are zero.
-        *
-        * If send window is too small, there is data to transmit, and no
-        * retransmit or persist is pending, then go to persist state.
-        * If nothing happens soon, send when timer expires:
-        * if window is nonzero, transmit what we can,
-        * otherwise force out a byte.
-        */
-       if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 &&
-           tp->t_timer[TCPT_PERSIST] == 0) {
-               tp->t_rxtshift = 0;
-               tcp_setpersist(tp);
-       }
-
-       /*
-        * No reason to send a segment, just return.
-        */
-       return (0);
-
-send:
-       /*
-        * Before ESTABLISHED, force sending of initial options
-        * unless TCP set not to do any options.
-        * NOTE: we assume that the IP/TCP header plus TCP options
-        * always fit in a single mbuf, leaving room for a maximum
-        * link header, i.e.
-        *      max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN
-        */
-       optlen = 0;
-       hdrlen = sizeof (struct tcpiphdr);
-       if (flags & TH_SYN) {
-               tp->snd_nxt = tp->iss;
-               if ((tp->t_flags & TF_NOOPT) == 0) {
-                       uint16_t mss;
-
-                       opt[0] = TCPOPT_MAXSEG;
-                       opt[1] = 4;
-                       mss = htons((uint16_t) tcp_mss(tp, 0));
-                       memcpy((char *)(opt + 2), (char *)&mss, sizeof(mss));
-                       optlen = 4;
-               }
-       }
-
-       hdrlen += optlen;
-
-       /*
-        * Adjust data length if insertion of options will
-        * bump the packet length beyond the t_maxseg length.
-        */
-        if (len > tp->t_maxseg - optlen) {
-               len = tp->t_maxseg - optlen;
-               sendalot = 1;
-        }
-
-       /*
-        * Grab a header mbuf, attaching a copy of data to
-        * be transmitted, and initialize the header from
-        * the template for sends on this connection.
-        */
-       if (len) {
-               m = m_get(so->slirp);
-               if (m == NULL) {
-                       error = 1;
-                       goto out;
-               }
-               m->m_data += IF_MAXLINKHDR;
-               m->m_len = hdrlen;
-
-               sbcopy(&so->so_snd, off, (int) len, mtod(m, char *) + hdrlen);
-               m->m_len += len;
-
-               /*
-                * If we're sending everything we've got, set PUSH.
-                * (This will keep happy those implementations which only
-                * give data to the user when a buffer fills or
-                * a PUSH comes in.)
-                */
-               if (off + len == so->so_snd.sb_cc)
-                       flags |= TH_PUSH;
-       } else {
-               m = m_get(so->slirp);
-               if (m == NULL) {
-                       error = 1;
-                       goto out;
-               }
-               m->m_data += IF_MAXLINKHDR;
-               m->m_len = hdrlen;
-       }
-
-       ti = mtod(m, struct tcpiphdr *);
-
-       memcpy((char *)ti, &tp->t_template, sizeof (struct tcpiphdr));
-
-       /*
-        * Fill in fields, remembering maximum advertised
-        * window for use in delaying messages about window sizes.
-        * If resending a FIN, be sure not to use a new sequence number.
-        */
-       if (flags & TH_FIN && tp->t_flags & TF_SENTFIN &&
-           tp->snd_nxt == tp->snd_max)
-               tp->snd_nxt--;
-       /*
-        * If we are doing retransmissions, then snd_nxt will
-        * not reflect the first unsent octet.  For ACK only
-        * packets, we do not want the sequence number of the
-        * retransmitted packet, we want the sequence number
-        * of the next unsent octet.  So, if there is no data
-        * (and no SYN or FIN), use snd_max instead of snd_nxt
-        * when filling in ti_seq.  But if we are in persist
-        * state, snd_max might reflect one byte beyond the
-        * right edge of the window, so use snd_nxt in that
-        * case, since we know we aren't doing a retransmission.
-        * (retransmit and persist are mutually exclusive...)
-        */
-       if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST])
-               ti->ti_seq = htonl(tp->snd_nxt);
-       else
-               ti->ti_seq = htonl(tp->snd_max);
-       ti->ti_ack = htonl(tp->rcv_nxt);
-       if (optlen) {
-               memcpy((char *)(ti + 1), (char *)opt, optlen);
-               ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2;
-       }
-       ti->ti_flags = flags;
-       /*
-        * Calculate receive window.  Don't shrink window,
-        * but avoid silly window syndrome.
-        */
-       if (win < (long)(so->so_rcv.sb_datalen / 4) && win < (long)tp->t_maxseg)
-               win = 0;
-       if (win > (long)TCP_MAXWIN << tp->rcv_scale)
-               win = (long)TCP_MAXWIN << tp->rcv_scale;
-       if (win < (long)(tp->rcv_adv - tp->rcv_nxt))
-               win = (long)(tp->rcv_adv - tp->rcv_nxt);
-       ti->ti_win = htons((uint16_t) (win>>tp->rcv_scale));
-
-       if (SEQ_GT(tp->snd_up, tp->snd_una)) {
-               ti->ti_urp = htons((uint16_t)(tp->snd_up - ntohl(ti->ti_seq)));
-               ti->ti_flags |= TH_URG;
-       } else
-               /*
-                * If no urgent pointer to send, then we pull
-                * the urgent pointer to the left edge of the send window
-                * so that it doesn't drift into the send window on sequence
-                * number wraparound.
-                */
-               tp->snd_up = tp->snd_una;               /* drag it along */
-
-       /*
-        * Put TCP length in extended header, and then
-        * checksum extended header and data.
-        */
-       if (len + optlen)
-               ti->ti_len = htons((uint16_t)(sizeof (struct tcphdr) +
-                   optlen + len));
-       ti->ti_sum = cksum(m, (int)(hdrlen + len));
-
-       /*
-        * In transmit state, time the transmission and arrange for
-        * the retransmit.  In persist state, just set snd_max.
-        */
-       if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) {
-               tcp_seq startseq = tp->snd_nxt;
-
-               /*
-                * Advance snd_nxt over sequence space of this segment.
-                */
-               if (flags & (TH_SYN|TH_FIN)) {
-                       if (flags & TH_SYN)
-                               tp->snd_nxt++;
-                       if (flags & TH_FIN) {
-                               tp->snd_nxt++;
-                               tp->t_flags |= TF_SENTFIN;
-                       }
-               }
-               tp->snd_nxt += len;
-               if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
-                       tp->snd_max = tp->snd_nxt;
-                       /*
-                        * Time this transmission if not a retransmission and
-                        * not currently timing anything.
-                        */
-                       if (tp->t_rtt == 0) {
-                               tp->t_rtt = 1;
-                               tp->t_rtseq = startseq;
-                       }
-               }
-
-               /*
-                * Set retransmit timer if not currently set,
-                * and not doing an ack or a keep-alive probe.
-                * Initial value for retransmit timer is smoothed
-                * round-trip time + 2 * round-trip time variance.
-                * Initialize shift counter which is used for backoff
-                * of retransmit time.
-                */
-               if (tp->t_timer[TCPT_REXMT] == 0 &&
-                   tp->snd_nxt != tp->snd_una) {
-                       tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
-                       if (tp->t_timer[TCPT_PERSIST]) {
-                               tp->t_timer[TCPT_PERSIST] = 0;
-                               tp->t_rxtshift = 0;
-                       }
-               }
-       } else
-               if (SEQ_GT(tp->snd_nxt + len, tp->snd_max))
-                       tp->snd_max = tp->snd_nxt + len;
-
-       /*
-        * Fill in IP length and desired time to live and
-        * send to IP level.  There should be a better way
-        * to handle ttl and tos; we could keep them in
-        * the template, but need a way to checksum without them.
-        */
-       m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */
-       tcpiph_save = *mtod(m, struct tcpiphdr *);
-
-       switch (so->so_ffamily) {
-       case AF_INET:
-           m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
-                                                - sizeof(struct ip);
-           m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
-                                                - sizeof(struct ip);
-           ip = mtod(m, struct ip *);
-
-           ip->ip_len = m->m_len;
-           ip->ip_dst = tcpiph_save.ti_dst;
-           ip->ip_src = tcpiph_save.ti_src;
-           ip->ip_p = tcpiph_save.ti_pr;
-
-           ip->ip_ttl = IPDEFTTL;
-           ip->ip_tos = so->so_iptos;
-           error = ip_output(so, m);
-           break;
-
-       case AF_INET6:
-           m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
-                                                - sizeof(struct ip6);
-           m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
-                                                - sizeof(struct ip6);
-           ip6 = mtod(m, struct ip6 *);
-
-           ip6->ip_pl = tcpiph_save.ti_len;
-           ip6->ip_dst = tcpiph_save.ti_dst6;
-           ip6->ip_src = tcpiph_save.ti_src6;
-           ip6->ip_nh = tcpiph_save.ti_nh6;
-
-           error = ip6_output(so, m, 0);
-           break;
-
-       default:
-           g_assert_not_reached();
-       }
-
-       if (error) {
-out:
-               return (error);
-       }
-
-       /*
-        * Data sent (as far as we can tell).
-        * If this advertises a larger window than any other segment,
-        * then remember the size of the advertised window.
-        * Any pending ACK has now been sent.
-        */
-       if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))
-               tp->rcv_adv = tp->rcv_nxt + win;
-       tp->last_ack_sent = tp->rcv_nxt;
-       tp->t_flags &= ~(TF_ACKNOW|TF_DELACK);
-       if (sendalot)
-               goto again;
-
-       return (0);
-}
-
-void
-tcp_setpersist(struct tcpcb *tp)
-{
-    int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1;
-
-       /*
-        * Start/restart persistence timer.
-        */
-       TCPT_RANGESET(tp->t_timer[TCPT_PERSIST],
-           t * tcp_backoff[tp->t_rxtshift],
-           TCPTV_PERSMIN, TCPTV_PERSMAX);
-       if (tp->t_rxtshift < TCP_MAXRXTSHIFT)
-               tp->t_rxtshift++;
-}
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
deleted file mode 100644 (file)
index 262a42d..0000000
+++ /dev/null
@@ -1,985 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 1988, 1990, 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. 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.
- *
- *     @(#)tcp_subr.c  8.1 (Berkeley) 6/10/93
- * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp
- */
-
-/*
- * Changes and additions relating to SLiRP
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#include "slirp.h"
-
-/* patchable/settable parameters for tcp */
-/* Don't do rfc1323 performance enhancements */
-#define TCP_DO_RFC1323 0
-
-/*
- * Tcp initialization
- */
-void
-tcp_init(Slirp *slirp)
-{
-    slirp->tcp_iss = 1;                /* wrong */
-    slirp->tcb.so_next = slirp->tcb.so_prev = &slirp->tcb;
-    slirp->tcp_last_so = &slirp->tcb;
-}
-
-void tcp_cleanup(Slirp *slirp)
-{
-    while (slirp->tcb.so_next != &slirp->tcb) {
-        tcp_close(sototcpcb(slirp->tcb.so_next));
-    }
-}
-
-/*
- * Create template to be used to send tcp packets on a connection.
- * Call after host entry created, fills
- * in a skeletal tcp/ip header, minimizing the amount of work
- * necessary when the connection is used.
- */
-void
-tcp_template(struct tcpcb *tp)
-{
-       struct socket *so = tp->t_socket;
-       register struct tcpiphdr *n = &tp->t_template;
-
-       n->ti_mbuf = NULL;
-       memset(&n->ti, 0, sizeof(n->ti));
-       n->ti_x0 = 0;
-       switch (so->so_ffamily) {
-       case AF_INET:
-           n->ti_pr = IPPROTO_TCP;
-           n->ti_len = htons(sizeof(struct tcphdr));
-           n->ti_src = so->so_faddr;
-           n->ti_dst = so->so_laddr;
-           n->ti_sport = so->so_fport;
-           n->ti_dport = so->so_lport;
-           break;
-
-       case AF_INET6:
-           n->ti_nh6 = IPPROTO_TCP;
-           n->ti_len = htons(sizeof(struct tcphdr));
-           n->ti_src6 = so->so_faddr6;
-           n->ti_dst6 = so->so_laddr6;
-           n->ti_sport = so->so_fport6;
-           n->ti_dport = so->so_lport6;
-           break;
-
-       default:
-           g_assert_not_reached();
-       }
-
-       n->ti_seq = 0;
-       n->ti_ack = 0;
-       n->ti_x2 = 0;
-       n->ti_off = 5;
-       n->ti_flags = 0;
-       n->ti_win = 0;
-       n->ti_sum = 0;
-       n->ti_urp = 0;
-}
-
-/*
- * Send a single message to the TCP at address specified by
- * the given TCP/IP header.  If m == 0, then we make a copy
- * of the tcpiphdr at ti and send directly to the addressed host.
- * This is used to force keep alive messages out using the TCP
- * template for a connection tp->t_template.  If flags are given
- * then we send a message back to the TCP which originated the
- * segment ti, and discard the mbuf containing it and any other
- * attached mbufs.
- *
- * In any case the ack and sequence number of the transmitted
- * segment are as specified by the parameters.
- */
-void
-tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
-            tcp_seq ack, tcp_seq seq, int flags, unsigned short af)
-{
-       register int tlen;
-       int win = 0;
-
-       DEBUG_CALL("tcp_respond");
-       DEBUG_ARG("tp = %p", tp);
-       DEBUG_ARG("ti = %p", ti);
-       DEBUG_ARG("m = %p", m);
-       DEBUG_ARG("ack = %u", ack);
-       DEBUG_ARG("seq = %u", seq);
-       DEBUG_ARG("flags = %x", flags);
-
-       if (tp)
-               win = sbspace(&tp->t_socket->so_rcv);
-        if (m == NULL) {
-               if (!tp || (m = m_get(tp->t_socket->slirp)) == NULL)
-                       return;
-               tlen = 0;
-               m->m_data += IF_MAXLINKHDR;
-               *mtod(m, struct tcpiphdr *) = *ti;
-               ti = mtod(m, struct tcpiphdr *);
-               switch (af) {
-               case AF_INET:
-                   ti->ti.ti_i4.ih_x1 = 0;
-                   break;
-               case AF_INET6:
-                   ti->ti.ti_i6.ih_x1 = 0;
-                   break;
-               default:
-                   g_assert_not_reached();
-               }
-               flags = TH_ACK;
-       } else {
-               /*
-                * ti points into m so the next line is just making
-                * the mbuf point to ti
-                */
-               m->m_data = (char *)ti;
-
-               m->m_len = sizeof (struct tcpiphdr);
-               tlen = 0;
-#define xchg(a,b,type) { type t; t=a; a=b; b=t; }
-               switch (af) {
-               case AF_INET:
-                   xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32_t);
-                   xchg(ti->ti_dport, ti->ti_sport, uint16_t);
-                   break;
-               case AF_INET6:
-                   xchg(ti->ti_dst6, ti->ti_src6, struct in6_addr);
-                   xchg(ti->ti_dport, ti->ti_sport, uint16_t);
-                   break;
-               default:
-                   g_assert_not_reached();
-               }
-#undef xchg
-       }
-       ti->ti_len = htons((uint16_t)(sizeof (struct tcphdr) + tlen));
-       tlen += sizeof (struct tcpiphdr);
-       m->m_len = tlen;
-
-       ti->ti_mbuf = NULL;
-       ti->ti_x0 = 0;
-       ti->ti_seq = htonl(seq);
-       ti->ti_ack = htonl(ack);
-       ti->ti_x2 = 0;
-       ti->ti_off = sizeof (struct tcphdr) >> 2;
-       ti->ti_flags = flags;
-       if (tp)
-               ti->ti_win = htons((uint16_t) (win >> tp->rcv_scale));
-       else
-               ti->ti_win = htons((uint16_t)win);
-       ti->ti_urp = 0;
-       ti->ti_sum = 0;
-       ti->ti_sum = cksum(m, tlen);
-
-       struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
-       struct ip *ip;
-       struct ip6 *ip6;
-
-       switch (af) {
-       case AF_INET:
-           m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
-                                                - sizeof(struct ip);
-           m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
-                                                - sizeof(struct ip);
-           ip = mtod(m, struct ip *);
-           ip->ip_len = m->m_len;
-           ip->ip_dst = tcpiph_save.ti_dst;
-           ip->ip_src = tcpiph_save.ti_src;
-           ip->ip_p = tcpiph_save.ti_pr;
-
-           if (flags & TH_RST) {
-               ip->ip_ttl = MAXTTL;
-           } else {
-               ip->ip_ttl = IPDEFTTL;
-           }
-
-           ip_output(NULL, m);
-           break;
-
-       case AF_INET6:
-           m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
-                                                - sizeof(struct ip6);
-           m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
-                                                - sizeof(struct ip6);
-           ip6 = mtod(m, struct ip6 *);
-           ip6->ip_pl = tcpiph_save.ti_len;
-           ip6->ip_dst = tcpiph_save.ti_dst6;
-           ip6->ip_src = tcpiph_save.ti_src6;
-           ip6->ip_nh = tcpiph_save.ti_nh6;
-
-           ip6_output(NULL, m, 0);
-           break;
-
-       default:
-           g_assert_not_reached();
-       }
-}
-
-/*
- * Create a new TCP control block, making an
- * empty reassembly queue and hooking it to the argument
- * protocol control block.
- */
-struct tcpcb *
-tcp_newtcpcb(struct socket *so)
-{
-       register struct tcpcb *tp;
-
-       tp = (struct tcpcb *)malloc(sizeof(*tp));
-       if (tp == NULL)
-               return ((struct tcpcb *)0);
-
-       memset((char *) tp, 0, sizeof(struct tcpcb));
-       tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp;
-       tp->t_maxseg = (so->so_ffamily == AF_INET) ? TCP_MSS : TCP6_MSS;
-
-       tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
-       tp->t_socket = so;
-
-       /*
-        * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
-        * rtt estimate.  Set rttvar so that srtt + 2 * rttvar gives
-        * reasonable initial retransmit time.
-        */
-       tp->t_srtt = TCPTV_SRTTBASE;
-       tp->t_rttvar = TCPTV_SRTTDFLT << 2;
-       tp->t_rttmin = TCPTV_MIN;
-
-       TCPT_RANGESET(tp->t_rxtcur,
-           ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
-           TCPTV_MIN, TCPTV_REXMTMAX);
-
-       tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
-       tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
-       tp->t_state = TCPS_CLOSED;
-
-       so->so_tcpcb = tp;
-
-       return (tp);
-}
-
-/*
- * Drop a TCP connection, reporting
- * the specified error.  If connection is synchronized,
- * then send a RST to peer.
- */
-struct tcpcb *tcp_drop(struct tcpcb *tp, int err)
-{
-       DEBUG_CALL("tcp_drop");
-       DEBUG_ARG("tp = %p", tp);
-       DEBUG_ARG("errno = %d", errno);
-
-       if (TCPS_HAVERCVDSYN(tp->t_state)) {
-               tp->t_state = TCPS_CLOSED;
-               (void) tcp_output(tp);
-       }
-       return (tcp_close(tp));
-}
-
-/*
- * Close a TCP control block:
- *     discard all space held by the tcp
- *     discard internet protocol block
- *     wake up any sleepers
- */
-struct tcpcb *
-tcp_close(struct tcpcb *tp)
-{
-       register struct tcpiphdr *t;
-       struct socket *so = tp->t_socket;
-       Slirp *slirp = so->slirp;
-       register struct mbuf *m;
-
-       DEBUG_CALL("tcp_close");
-       DEBUG_ARG("tp = %p", tp);
-
-       /* free the reassembly queue, if any */
-       t = tcpfrag_list_first(tp);
-       while (!tcpfrag_list_end(t, tp)) {
-               t = tcpiphdr_next(t);
-               m = tcpiphdr_prev(t)->ti_mbuf;
-               remque(tcpiphdr2qlink(tcpiphdr_prev(t)));
-               m_free(m);
-       }
-       free(tp);
-        so->so_tcpcb = NULL;
-       /* clobber input socket cache if we're closing the cached connection */
-       if (so == slirp->tcp_last_so)
-               slirp->tcp_last_so = &slirp->tcb;
-       so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
-       closesocket(so->s);
-       sbfree(&so->so_rcv);
-       sbfree(&so->so_snd);
-       sofree(so);
-       return ((struct tcpcb *)0);
-}
-
-/*
- * TCP protocol interface to socket abstraction.
- */
-
-/*
- * User issued close, and wish to trail through shutdown states:
- * if never received SYN, just forget it.  If got a SYN from peer,
- * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
- * If already got a FIN from peer, then almost done; go to LAST_ACK
- * state.  In all other cases, have already sent FIN to peer (e.g.
- * after PRU_SHUTDOWN), and just have to play tedious game waiting
- * for peer to send FIN or not respond to keep-alives, etc.
- * We can let the user exit from the close as soon as the FIN is acked.
- */
-void
-tcp_sockclosed(struct tcpcb *tp)
-{
-
-       DEBUG_CALL("tcp_sockclosed");
-       DEBUG_ARG("tp = %p", tp);
-
-       if (!tp) {
-               return;
-       }
-
-       switch (tp->t_state) {
-
-       case TCPS_CLOSED:
-       case TCPS_LISTEN:
-       case TCPS_SYN_SENT:
-               tp->t_state = TCPS_CLOSED;
-               tp = tcp_close(tp);
-               break;
-
-       case TCPS_SYN_RECEIVED:
-       case TCPS_ESTABLISHED:
-               tp->t_state = TCPS_FIN_WAIT_1;
-               break;
-
-       case TCPS_CLOSE_WAIT:
-               tp->t_state = TCPS_LAST_ACK;
-               break;
-       }
-       tcp_output(tp);
-}
-
-/*
- * Connect to a host on the Internet
- * Called by tcp_input
- * Only do a connect, the tcp fields will be set in tcp_input
- * return 0 if there's a result of the connect,
- * else return -1 means we're still connecting
- * The return value is almost always -1 since the socket is
- * nonblocking.  Connect returns after the SYN is sent, and does
- * not wait for ACK+SYN.
- */
-int tcp_fconnect(struct socket *so, unsigned short af)
-{
-  int ret=0;
-
-  DEBUG_CALL("tcp_fconnect");
-  DEBUG_ARG("so = %p", so);
-
-  ret = so->s = slirp_socket(af, SOCK_STREAM, 0);
-  if (ret >= 0) {
-    int opt, s=so->s;
-    struct sockaddr_storage addr;
-
-    slirp_set_nonblock(s);
-    so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
-    slirp_socket_set_fast_reuse(s);
-    opt = 1;
-    setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
-    opt = 1;
-    setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
-
-    addr = so->fhost.ss;
-    DEBUG_CALL(" connect()ing");
-    sotranslate_out(so, &addr);
-
-    /* We don't care what port we get */
-    ret = connect(s, (struct sockaddr *)&addr, sockaddr_size(&addr));
-
-    /*
-     * If it's not in progress, it failed, so we just return 0,
-     * without clearing SS_NOFDREF
-     */
-    soisfconnecting(so);
-  }
-
-  return(ret);
-}
-
-/*
- * Accept the socket and connect to the local-host
- *
- * We have a problem. The correct thing to do would be
- * to first connect to the local-host, and only if the
- * connection is accepted, then do an accept() here.
- * But, a) we need to know who's trying to connect
- * to the socket to be able to SYN the local-host, and
- * b) we are already connected to the foreign host by
- * the time it gets to accept(), so... We simply accept
- * here and SYN the local-host.
- */
-void tcp_connect(struct socket *inso)
-{
-    Slirp *slirp = inso->slirp;
-    struct socket *so;
-    struct sockaddr_storage addr;
-    socklen_t addrlen = sizeof(struct sockaddr_storage);
-    struct tcpcb *tp;
-    int s, opt;
-
-    DEBUG_CALL("tcp_connect");
-    DEBUG_ARG("inso = %p", inso);
-
-    /*
-     * If it's an SS_ACCEPTONCE socket, no need to socreate()
-     * another socket, just use the accept() socket.
-     */
-    if (inso->so_state & SS_FACCEPTONCE) {
-        /* FACCEPTONCE already have a tcpcb */
-        so = inso;
-    } else {
-        so = socreate(slirp);
-        if (tcp_attach(so) < 0) {
-            g_free(so); /* NOT sofree */
-            return;
-        }
-        so->lhost = inso->lhost;
-        so->so_ffamily = inso->so_ffamily;
-    }
-
-    tcp_mss(sototcpcb(so), 0);
-
-    s = accept(inso->s, (struct sockaddr *)&addr, &addrlen);
-    if (s < 0) {
-        tcp_close(sototcpcb(so)); /* This will sofree() as well */
-        return;
-    }
-    slirp_set_nonblock(s);
-    so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
-    slirp_socket_set_fast_reuse(s);
-    opt = 1;
-    setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
-    slirp_socket_set_nodelay(s);
-
-    so->fhost.ss = addr;
-    sotranslate_accept(so);
-
-    /* Close the accept() socket, set right state */
-    if (inso->so_state & SS_FACCEPTONCE) {
-        /* If we only accept once, close the accept() socket */
-        so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
-        closesocket(so->s);
-
-        /* Don't select it yet, even though we have an FD */
-        /* if it's not FACCEPTONCE, it's already NOFDREF */
-        so->so_state = SS_NOFDREF;
-    }
-    so->s = s;
-    so->so_state |= SS_INCOMING;
-
-    so->so_iptos = tcp_tos(so);
-    tp = sototcpcb(so);
-
-    tcp_template(tp);
-
-    tp->t_state = TCPS_SYN_SENT;
-    tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
-    tp->iss = slirp->tcp_iss;
-    slirp->tcp_iss += TCP_ISSINCR/2;
-    tcp_sendseqinit(tp);
-    tcp_output(tp);
-}
-
-/*
- * Attach a TCPCB to a socket.
- */
-int
-tcp_attach(struct socket *so)
-{
-       if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL)
-          return -1;
-
-       insque(so, &so->slirp->tcb);
-
-       return 0;
-}
-
-/*
- * Set the socket's type of service field
- */
-static const struct tos_t tcptos[] = {
-         {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */
-         {21, 21, IPTOS_LOWDELAY,  EMU_FTP},   /* ftp control */
-         {0, 23, IPTOS_LOWDELAY, 0},   /* telnet */
-         {0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */
-         {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT},   /* rlogin */
-         {0, 544, IPTOS_LOWDELAY, EMU_KSH},            /* kshell */
-         {0, 543, IPTOS_LOWDELAY, 0},  /* klogin */
-         {0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */
-         {0, 6668, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC undernet */
-         {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */
-         {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */
-         {0, 0, 0, 0}
-};
-
-static struct emu_t *tcpemu = NULL;
-
-/*
- * Return TOS according to the above table
- */
-uint8_t
-tcp_tos(struct socket *so)
-{
-       int i = 0;
-       struct emu_t *emup;
-
-       while(tcptos[i].tos) {
-               if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) ||
-                   (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) {
-                       so->so_emu = tcptos[i].emu;
-                       return tcptos[i].tos;
-               }
-               i++;
-       }
-
-       /* Nope, lets see if there's a user-added one */
-       for (emup = tcpemu; emup; emup = emup->next) {
-               if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) ||
-                   (emup->lport && (ntohs(so->so_lport) == emup->lport))) {
-                       so->so_emu = emup->emu;
-                       return emup->tos;
-               }
-       }
-
-       return 0;
-}
-
-/*
- * Emulate programs that try and connect to us
- * This includes ftp (the data connection is
- * initiated by the server) and IRC (DCC CHAT and
- * DCC SEND) for now
- *
- * NOTE: It's possible to crash SLiRP by sending it
- * unstandard strings to emulate... if this is a problem,
- * more checks are needed here
- *
- * XXX Assumes the whole command came in one packet
- *
- * XXX Some ftp clients will have their TOS set to
- * LOWDELAY and so Nagel will kick in.  Because of this,
- * we'll get the first letter, followed by the rest, so
- * we simply scan for ORT instead of PORT...
- * DCC doesn't have this problem because there's other stuff
- * in the packet before the DCC command.
- *
- * Return 1 if the mbuf m is still valid and should be
- * sbappend()ed
- *
- * NOTE: if you return 0 you MUST m_free() the mbuf!
- */
-int
-tcp_emu(struct socket *so, struct mbuf *m)
-{
-       Slirp *slirp = so->slirp;
-       unsigned n1, n2, n3, n4, n5, n6;
-        char buff[257];
-       uint32_t laddr;
-       unsigned lport;
-       char *bptr;
-
-       DEBUG_CALL("tcp_emu");
-       DEBUG_ARG("so = %p", so);
-       DEBUG_ARG("m = %p", m);
-
-       switch(so->so_emu) {
-               int x, i;
-
-        case EMU_IDENT:
-               /*
-                * Identification protocol as per rfc-1413
-                */
-
-               {
-                       struct socket *tmpso;
-                       struct sockaddr_in addr;
-                       socklen_t addrlen = sizeof(struct sockaddr_in);
-                       struct sbuf *so_rcv = &so->so_rcv;
-
-                       if (m->m_len > so_rcv->sb_datalen
-                                       - (so_rcv->sb_wptr - so_rcv->sb_data)) {
-                           return 1;
-                       }
-
-                       memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
-                       so_rcv->sb_wptr += m->m_len;
-                       so_rcv->sb_rptr += m->m_len;
-                       m->m_data[m->m_len] = 0; /* NULL terminate */
-                       if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) {
-                               if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) {
-                                       HTONS(n1);
-                                       HTONS(n2);
-                                       /* n2 is the one on our host */
-                                       for (tmpso = slirp->tcb.so_next;
-                                            tmpso != &slirp->tcb;
-                                            tmpso = tmpso->so_next) {
-                                               if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr &&
-                                                   tmpso->so_lport == n2 &&
-                                                   tmpso->so_faddr.s_addr == so->so_faddr.s_addr &&
-                                                   tmpso->so_fport == n1) {
-                                                       if (getsockname(tmpso->s,
-                                                               (struct sockaddr *)&addr, &addrlen) == 0)
-                                                          n2 = ntohs(addr.sin_port);
-                                                       break;
-                                               }
-                                       }
-                               }
-                                so_rcv->sb_cc = snprintf(so_rcv->sb_data,
-                                                         so_rcv->sb_datalen,
-                                                         "%d,%d\r\n", n1, n2);
-                               so_rcv->sb_rptr = so_rcv->sb_data;
-                               so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc;
-                       }
-                       m_free(m);
-                       return 0;
-               }
-
-        case EMU_FTP: /* ftp */
-                *(m->m_data+m->m_len) = 0; /* NUL terminate for strstr */
-               if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) {
-                       /*
-                        * Need to emulate the PORT command
-                        */
-                       x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]",
-                                  &n1, &n2, &n3, &n4, &n5, &n6, buff);
-                       if (x < 6)
-                          return 1;
-
-                       laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
-                       lport = htons((n5 << 8) | (n6));
-
-                       if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr,
-                                            lport, SS_FACCEPTONCE)) == NULL) {
-                          return 1;
-                       }
-                       n6 = ntohs(so->so_fport);
-
-                       n5 = (n6 >> 8) & 0xff;
-                       n6 &= 0xff;
-
-                       laddr = ntohl(so->so_faddr.s_addr);
-
-                       n1 = ((laddr >> 24) & 0xff);
-                       n2 = ((laddr >> 16) & 0xff);
-                       n3 = ((laddr >> 8)  & 0xff);
-                       n4 =  (laddr & 0xff);
-
-                       m->m_len = bptr - m->m_data; /* Adjust length */
-                        m->m_len += snprintf(bptr, m->m_size - m->m_len,
-                                             "ORT %d,%d,%d,%d,%d,%d\r\n%s",
-                                             n1, n2, n3, n4, n5, n6, x==7?buff:"");
-                       return 1;
-               } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
-                       /*
-                        * Need to emulate the PASV response
-                        */
-                       x = sscanf(bptr, "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]",
-                                  &n1, &n2, &n3, &n4, &n5, &n6, buff);
-                       if (x < 6)
-                          return 1;
-
-                       laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
-                       lport = htons((n5 << 8) | (n6));
-
-                       if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr,
-                                            lport, SS_FACCEPTONCE)) == NULL) {
-                          return 1;
-                       }
-                       n6 = ntohs(so->so_fport);
-
-                       n5 = (n6 >> 8) & 0xff;
-                       n6 &= 0xff;
-
-                       laddr = ntohl(so->so_faddr.s_addr);
-
-                       n1 = ((laddr >> 24) & 0xff);
-                       n2 = ((laddr >> 16) & 0xff);
-                       n3 = ((laddr >> 8)  & 0xff);
-                       n4 =  (laddr & 0xff);
-
-                       m->m_len = bptr - m->m_data; /* Adjust length */
-                       m->m_len += snprintf(bptr, m->m_size - m->m_len,
-                                             "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
-                                             n1, n2, n3, n4, n5, n6, x==7?buff:"");
-
-                       return 1;
-               }
-
-               return 1;
-
-        case EMU_KSH:
-               /*
-                * The kshell (Kerberos rsh) and shell services both pass
-                * a local port port number to carry signals to the server
-                * and stderr to the client.  It is passed at the beginning
-                * of the connection as a NUL-terminated decimal ASCII string.
-                */
-               so->so_emu = 0;
-               for (lport = 0, i = 0; i < m->m_len-1; ++i) {
-                       if (m->m_data[i] < '0' || m->m_data[i] > '9')
-                               return 1;       /* invalid number */
-                       lport *= 10;
-                       lport += m->m_data[i] - '0';
-               }
-               if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
-                   (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr,
-                                    htons(lport), SS_FACCEPTONCE)) != NULL)
-                    m->m_len = snprintf(m->m_data, m->m_size, "%d",
-                                        ntohs(so->so_fport)) + 1;
-               return 1;
-
-        case EMU_IRC:
-               /*
-                * Need to emulate DCC CHAT, DCC SEND and DCC MOVE
-                */
-               *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */
-               if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL)
-                        return 1;
-
-               /* The %256s is for the broken mIRC */
-               if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
-                       if ((so = tcp_listen(slirp, INADDR_ANY, 0,
-                                            htonl(laddr), htons(lport),
-                                            SS_FACCEPTONCE)) == NULL) {
-                               return 1;
-                       }
-                       m->m_len = bptr - m->m_data; /* Adjust length */
-                        m->m_len += snprintf(bptr, m->m_size,
-                                             "DCC CHAT chat %lu %u%c\n",
-                                             (unsigned long)ntohl(so->so_faddr.s_addr),
-                                             ntohs(so->so_fport), 1);
-               } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
-                       if ((so = tcp_listen(slirp, INADDR_ANY, 0,
-                                            htonl(laddr), htons(lport),
-                                            SS_FACCEPTONCE)) == NULL) {
-                               return 1;
-                       }
-                       m->m_len = bptr - m->m_data; /* Adjust length */
-                        m->m_len += snprintf(bptr, m->m_size,
-                                             "DCC SEND %s %lu %u %u%c\n", buff,
-                                             (unsigned long)ntohl(so->so_faddr.s_addr),
-                                             ntohs(so->so_fport), n1, 1);
-               } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
-                       if ((so = tcp_listen(slirp, INADDR_ANY, 0,
-                                            htonl(laddr), htons(lport),
-                                            SS_FACCEPTONCE)) == NULL) {
-                               return 1;
-                       }
-                       m->m_len = bptr - m->m_data; /* Adjust length */
-                        m->m_len += snprintf(bptr, m->m_size,
-                                             "DCC MOVE %s %lu %u %u%c\n", buff,
-                                             (unsigned long)ntohl(so->so_faddr.s_addr),
-                                             ntohs(so->so_fport), n1, 1);
-               }
-               return 1;
-
-        case EMU_REALAUDIO:
-                /*
-                * RealAudio emulation - JP. We must try to parse the incoming
-                * data and try to find the two characters that contain the
-                * port number. Then we redirect an udp port and replace the
-                * number with the real port we got.
-                *
-                * The 1.0 beta versions of the player are not supported
-                * any more.
-                *
-                * A typical packet for player version 1.0 (release version):
-                *
-                * 0000:50 4E 41 00 05
-                * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 ........g.l.c..P
-                * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH
-                * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v
-                * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB
-                *
-                * Now the port number 0x1BD7 is found at offset 0x04 of the
-                * Now the port number 0x1BD7 is found at offset 0x04 of the
-                * second packet. This time we received five bytes first and
-                * then the rest. You never know how many bytes you get.
-                *
-                * A typical packet for player version 2.0 (beta):
-                *
-                * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA.............
-                * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .gux.c..Win2.0.0
-                * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/
-                * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas
-                * 0040:65 2E 72 61 79 53 00 00 06 36 42                e.rayS...6B
-                *
-                * Port number 0x1BC1 is found at offset 0x0d.
-                *
-                * This is just a horrible switch statement. Variable ra tells
-                * us where we're going.
-                */
-
-               bptr = m->m_data;
-               while (bptr < m->m_data + m->m_len) {
-                       uint16_t p;
-                       static int ra = 0;
-                       char ra_tbl[4];
-
-                       ra_tbl[0] = 0x50;
-                       ra_tbl[1] = 0x4e;
-                       ra_tbl[2] = 0x41;
-                       ra_tbl[3] = 0;
-
-                       switch (ra) {
-                        case 0:
-                        case 2:
-                        case 3:
-                               if (*bptr++ != ra_tbl[ra]) {
-                                       ra = 0;
-                                       continue;
-                               }
-                               break;
-
-                        case 1:
-                               /*
-                                * We may get 0x50 several times, ignore them
-                                */
-                               if (*bptr == 0x50) {
-                                       ra = 1;
-                                       bptr++;
-                                       continue;
-                               } else if (*bptr++ != ra_tbl[ra]) {
-                                       ra = 0;
-                                       continue;
-                               }
-                               break;
-
-                        case 4:
-                               /*
-                                * skip version number
-                                */
-                               bptr++;
-                               break;
-
-                        case 5:
-                               /*
-                                * The difference between versions 1.0 and
-                                * 2.0 is here. For future versions of
-                                * the player this may need to be modified.
-                                */
-                               if (*(bptr + 1) == 0x02)
-                                  bptr += 8;
-                               else
-                                  bptr += 4;
-                               break;
-
-                        case 6:
-                               /* This is the field containing the port
-                                * number that RA-player is listening to.
-                                */
-                               lport = (((uint8_t*)bptr)[0] << 8)
-                               + ((uint8_t *)bptr)[1];
-                               if (lport < 6970)
-                                  lport += 256;   /* don't know why */
-                               if (lport < 6970 || lport > 7170)
-                                  return 1;       /* failed */
-
-                               /* try to get udp port between 6970 - 7170 */
-                               for (p = 6970; p < 7071; p++) {
-                                       if (udp_listen(slirp, INADDR_ANY,
-                                                      htons(p),
-                                                      so->so_laddr.s_addr,
-                                                      htons(lport),
-                                                      SS_FACCEPTONCE)) {
-                                               break;
-                                       }
-                               }
-                               if (p == 7071)
-                                  p = 0;
-                               *(uint8_t *)bptr++ = (p >> 8) & 0xff;
-                                *(uint8_t *)bptr = p & 0xff;
-                               ra = 0;
-                               return 1;   /* port redirected, we're done */
-                               break;
-
-                        default:
-                               ra = 0;
-                       }
-                       ra++;
-               }
-               return 1;
-
-        default:
-               /* Ooops, not emulated, won't call tcp_emu again */
-               so->so_emu = 0;
-               return 1;
-       }
-}
-
-/*
- * Do misc. config of SLiRP while its running.
- * Return 0 if this connections is to be closed, 1 otherwise,
- * return 2 if this is a command-line connection
- */
-int tcp_ctl(struct socket *so)
-{
-    Slirp *slirp = so->slirp;
-    struct sbuf *sb = &so->so_snd;
-    struct gfwd_list *ex_ptr;
-
-    DEBUG_CALL("tcp_ctl");
-    DEBUG_ARG("so = %p", so);
-
-    if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
-        /* Check if it's pty_exec */
-        for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
-            if (ex_ptr->ex_fport == so->so_fport &&
-                so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
-                if (ex_ptr->write_cb) {
-                    so->s = -1;
-                    so->guestfwd = ex_ptr;
-                    return 1;
-                }
-                DEBUG_MISC(" executing %s", ex_ptr->ex_exec);
-                return fork_exec(so, ex_ptr->ex_exec);
-            }
-        }
-    }
-    sb->sb_cc =
-        snprintf(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data),
-                 "Error: No application configured.\r\n");
-    sb->sb_wptr += sb->sb_cc;
-    return 0;
-}
diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c
deleted file mode 100644 (file)
index 7be5457..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 1988, 1990, 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. 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.
- *
- *     @(#)tcp_timer.c 8.1 (Berkeley) 6/10/93
- * tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp
- */
-
-#include "slirp.h"
-
-static struct tcpcb *tcp_timers(register struct tcpcb *tp, int timer);
-
-/*
- * Fast timeout routine for processing delayed acks
- */
-void
-tcp_fasttimo(Slirp *slirp)
-{
-       register struct socket *so;
-       register struct tcpcb *tp;
-
-       DEBUG_CALL("tcp_fasttimo");
-
-       so = slirp->tcb.so_next;
-       if (so)
-       for (; so != &slirp->tcb; so = so->so_next)
-               if ((tp = (struct tcpcb *)so->so_tcpcb) &&
-                   (tp->t_flags & TF_DELACK)) {
-                       tp->t_flags &= ~TF_DELACK;
-                       tp->t_flags |= TF_ACKNOW;
-                       (void) tcp_output(tp);
-               }
-}
-
-/*
- * Tcp protocol timeout routine called every 500 ms.
- * Updates the timers in all active tcb's and
- * causes finite state machine actions if timers expire.
- */
-void
-tcp_slowtimo(Slirp *slirp)
-{
-       register struct socket *ip, *ipnxt;
-       register struct tcpcb *tp;
-       register int i;
-
-       DEBUG_CALL("tcp_slowtimo");
-
-       /*
-        * Search through tcb's and update active timers.
-        */
-       ip = slirp->tcb.so_next;
-        if (ip == NULL) {
-            return;
-        }
-       for (; ip != &slirp->tcb; ip = ipnxt) {
-               ipnxt = ip->so_next;
-               tp = sototcpcb(ip);
-                if (tp == NULL) {
-                        continue;
-                }
-               for (i = 0; i < TCPT_NTIMERS; i++) {
-                       if (tp->t_timer[i] && --tp->t_timer[i] == 0) {
-                               tcp_timers(tp,i);
-                               if (ipnxt->so_prev != ip)
-                                       goto tpgone;
-                       }
-               }
-               tp->t_idle++;
-               if (tp->t_rtt)
-                  tp->t_rtt++;
-tpgone:
-               ;
-       }
-       slirp->tcp_iss += TCP_ISSINCR/PR_SLOWHZ;        /* increment iss */
-       slirp->tcp_now++;                               /* for timestamps */
-}
-
-/*
- * Cancel all timers for TCP tp.
- */
-void
-tcp_canceltimers(struct tcpcb *tp)
-{
-       register int i;
-
-       for (i = 0; i < TCPT_NTIMERS; i++)
-               tp->t_timer[i] = 0;
-}
-
-const int tcp_backoff[TCP_MAXRXTSHIFT + 1] =
-   { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
-
-/*
- * TCP timer processing.
- */
-static struct tcpcb *
-tcp_timers(register struct tcpcb *tp, int timer)
-{
-       register int rexmt;
-
-       DEBUG_CALL("tcp_timers");
-
-       switch (timer) {
-
-       /*
-        * 2 MSL timeout in shutdown went off.  If we're closed but
-        * still waiting for peer to close and connection has been idle
-        * too long, or if 2MSL time is up from TIME_WAIT, delete connection
-        * control block.  Otherwise, check again in a bit.
-        */
-       case TCPT_2MSL:
-               if (tp->t_state != TCPS_TIME_WAIT &&
-                   tp->t_idle <= TCP_MAXIDLE)
-                       tp->t_timer[TCPT_2MSL] = TCPTV_KEEPINTVL;
-               else
-                       tp = tcp_close(tp);
-               break;
-
-       /*
-        * Retransmission timer went off.  Message has not
-        * been acked within retransmit interval.  Back off
-        * to a longer retransmit interval and retransmit one segment.
-        */
-       case TCPT_REXMT:
-
-               /*
-                * XXXXX If a packet has timed out, then remove all the queued
-                * packets for that session.
-                */
-
-               if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
-                       /*
-                        * This is a hack to suit our terminal server here at the uni of canberra
-                        * since they have trouble with zeroes... It usually lets them through
-                        * unharmed, but under some conditions, it'll eat the zeros.  If we
-                        * keep retransmitting it, it'll keep eating the zeroes, so we keep
-                        * retransmitting, and eventually the connection dies...
-                        * (this only happens on incoming data)
-                        *
-                        * So, if we were gonna drop the connection from too many retransmits,
-                        * don't... instead halve the t_maxseg, which might break up the NULLs and
-                        * let them through
-                        *
-                        * *sigh*
-                        */
-
-                       tp->t_maxseg >>= 1;
-                       if (tp->t_maxseg < 32) {
-                               /*
-                                * We tried our best, now the connection must die!
-                                */
-                               tp->t_rxtshift = TCP_MAXRXTSHIFT;
-                               tp = tcp_drop(tp, tp->t_softerror);
-                               /* tp->t_softerror : ETIMEDOUT); */ /* XXX */
-                               return (tp); /* XXX */
-                       }
-
-                       /*
-                        * Set rxtshift to 6, which is still at the maximum
-                        * backoff time
-                        */
-                       tp->t_rxtshift = 6;
-               }
-               rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
-               TCPT_RANGESET(tp->t_rxtcur, rexmt,
-                   (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */
-               tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
-               /*
-                * If losing, let the lower level know and try for
-                * a better route.  Also, if we backed off this far,
-                * our srtt estimate is probably bogus.  Clobber it
-                * so we'll take the next rtt measurement as our srtt;
-                * move the current srtt into rttvar to keep the current
-                * retransmit times until then.
-                */
-               if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
-                       tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
-                       tp->t_srtt = 0;
-               }
-               tp->snd_nxt = tp->snd_una;
-               /*
-                * If timing a segment in this window, stop the timer.
-                */
-               tp->t_rtt = 0;
-               /*
-                * Close the congestion window down to one segment
-                * (we'll open it by one segment for each ack we get).
-                * Since we probably have a window's worth of unacked
-                * data accumulated, this "slow start" keeps us from
-                * dumping all that data as back-to-back packets (which
-                * might overwhelm an intermediate gateway).
-                *
-                * There are two phases to the opening: Initially we
-                * open by one mss on each ack.  This makes the window
-                * size increase exponentially with time.  If the
-                * window is larger than the path can handle, this
-                * exponential growth results in dropped packet(s)
-                * almost immediately.  To get more time between
-                * drops but still "push" the network to take advantage
-                * of improving conditions, we switch from exponential
-                * to linear window opening at some threshold size.
-                * For a threshold, we use half the current window
-                * size, truncated to a multiple of the mss.
-                *
-                * (the minimum cwnd that will give us exponential
-                * growth is 2 mss.  We don't allow the threshold
-                * to go below this.)
-                */
-               {
-                unsigned win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
-               if (win < 2)
-                       win = 2;
-               tp->snd_cwnd = tp->t_maxseg;
-               tp->snd_ssthresh = win * tp->t_maxseg;
-               tp->t_dupacks = 0;
-               }
-               (void) tcp_output(tp);
-               break;
-
-       /*
-        * Persistence timer into zero window.
-        * Force a byte to be output, if possible.
-        */
-       case TCPT_PERSIST:
-               tcp_setpersist(tp);
-               tp->t_force = 1;
-               (void) tcp_output(tp);
-               tp->t_force = 0;
-               break;
-
-       /*
-        * Keep-alive timer went off; send something
-        * or drop connection if idle for too long.
-        */
-       case TCPT_KEEP:
-               if (tp->t_state < TCPS_ESTABLISHED)
-                       goto dropit;
-
-               if (slirp_do_keepalive && tp->t_state <= TCPS_CLOSE_WAIT) {
-                       if (tp->t_idle >= TCPTV_KEEP_IDLE + TCP_MAXIDLE)
-                               goto dropit;
-                       /*
-                        * Send a packet designed to force a response
-                        * if the peer is up and reachable:
-                        * either an ACK if the connection is still alive,
-                        * or an RST if the peer has closed the connection
-                        * due to timeout or reboot.
-                        * Using sequence number tp->snd_una-1
-                        * causes the transmitted zero-length segment
-                        * to lie outside the receive window;
-                        * by the protocol spec, this requires the
-                        * correspondent TCP to respond.
-                        */
-                       tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
-                           tp->rcv_nxt, tp->snd_una - 1, 0,
-                           tp->t_socket->so_ffamily);
-                       tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
-               } else
-                       tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
-               break;
-
-       dropit:
-               tp = tcp_drop(tp, 0);
-               break;
-       }
-
-       return (tp);
-}
diff --git a/slirp/tcp_timer.h b/slirp/tcp_timer.h
deleted file mode 100644 (file)
index b25b391..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 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. 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.
- *
- *     @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93
- * tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp
- */
-
-#ifndef TCP_TIMER_H
-#define TCP_TIMER_H
-
-/*
- * Definitions of the TCP timers.  These timers are counted
- * down PR_SLOWHZ times a second.
- */
-#define        TCPT_NTIMERS    4
-
-#define        TCPT_REXMT      0               /* retransmit */
-#define        TCPT_PERSIST    1               /* retransmit persistence */
-#define        TCPT_KEEP       2               /* keep alive */
-#define        TCPT_2MSL       3               /* 2*msl quiet time timer */
-
-/*
- * The TCPT_REXMT timer is used to force retransmissions.
- * The TCP has the TCPT_REXMT timer set whenever segments
- * have been sent for which ACKs are expected but not yet
- * received.  If an ACK is received which advances tp->snd_una,
- * then the retransmit timer is cleared (if there are no more
- * outstanding segments) or reset to the base value (if there
- * are more ACKs expected).  Whenever the retransmit timer goes off,
- * we retransmit one unacknowledged segment, and do a backoff
- * on the retransmit timer.
- *
- * The TCPT_PERSIST timer is used to keep window size information
- * flowing even if the window goes shut.  If all previous transmissions
- * have been acknowledged (so that there are no retransmissions in progress),
- * and the window is too small to bother sending anything, then we start
- * the TCPT_PERSIST timer.  When it expires, if the window is nonzero,
- * we go to transmit state.  Otherwise, at intervals send a single byte
- * into the peer's window to force him to update our window information.
- * We do this at most as often as TCPT_PERSMIN time intervals,
- * but no more frequently than the current estimate of round-trip
- * packet time.  The TCPT_PERSIST timer is cleared whenever we receive
- * a window update from the peer.
- *
- * The TCPT_KEEP timer is used to keep connections alive.  If an
- * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time,
- * but not yet established, then we drop the connection.  Once the connection
- * is established, if the connection is idle for TCPTV_KEEP_IDLE time
- * (and keepalives have been enabled on the socket), we begin to probe
- * the connection.  We force the peer to send us a segment by sending:
- *     <SEQ=SND.UNA-1><ACK=RCV.NXT><CTL=ACK>
- * This segment is (deliberately) outside the window, and should elicit
- * an ack segment in response from the peer.  If, despite the TCPT_KEEP
- * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE
- * amount of time probing, then we drop the connection.
- */
-
-/*
- * Time constants.
- */
-#define TCPTV_MSL       ( 5*PR_SLOWHZ)          /* max seg lifetime (hah!) */
-
-#define        TCPTV_SRTTBASE  0                       /* base roundtrip time;
-                                                  if 0, no idea yet */
-#define        TCPTV_SRTTDFLT  (  3*PR_SLOWHZ)         /* assumed RTT if no info */
-
-#define        TCPTV_PERSMIN   (  5*PR_SLOWHZ)         /* retransmit persistence */
-#define        TCPTV_PERSMAX   ( 60*PR_SLOWHZ)         /* maximum persist interval */
-
-#define        TCPTV_KEEP_INIT ( 75*PR_SLOWHZ)         /* initial connect keep alive */
-#define        TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ)      /* dflt time before probing */
-#define        TCPTV_KEEPINTVL ( 75*PR_SLOWHZ)         /* default probe interval */
-#define        TCPTV_KEEPCNT   8                       /* max probes before drop */
-
-#define        TCPTV_MIN       (  1*PR_SLOWHZ)         /* minimum allowable value */
-#define TCPTV_REXMTMAX  ( 12*PR_SLOWHZ)                /* max allowable REXMT value */
-
-#define        TCP_LINGERTIME  120                     /* linger at most 2 minutes */
-
-#define TCP_MAXRXTSHIFT 12                      /* maximum retransmits */
-
-
-/*
- * Force a time value to be in a certain range.
- */
-#define        TCPT_RANGESET(tv, value, tvmin, tvmax) { \
-       (tv) = (value); \
-       if ((tv) < (tvmin)) \
-               (tv) = (tvmin); \
-       else if ((tv) > (tvmax)) \
-               (tv) = (tvmax); \
-}
-
-extern const int tcp_backoff[];
-
-struct tcpcb;
-
-void tcp_fasttimo(Slirp *);
-void tcp_slowtimo(Slirp *);
-void tcp_canceltimers(struct tcpcb *);
-
-#endif
diff --git a/slirp/tcp_var.h b/slirp/tcp_var.h
deleted file mode 100644 (file)
index 27ef1a5..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 1993, 1994
- *     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. 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.
- *
- *     @(#)tcp_var.h   8.3 (Berkeley) 4/10/94
- * tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp
- */
-
-#ifndef TCP_VAR_H
-#define TCP_VAR_H
-
-#include "tcpip.h"
-#include "tcp_timer.h"
-
-/*
- * Tcp control block, one per tcp; fields:
- */
-struct tcpcb {
-       struct tcpiphdr *seg_next;      /* sequencing queue */
-       struct tcpiphdr *seg_prev;
-       short   t_state;                /* state of this connection */
-       short   t_timer[TCPT_NTIMERS];  /* tcp timers */
-       short   t_rxtshift;             /* log(2) of rexmt exp. backoff */
-       short   t_rxtcur;               /* current retransmit value */
-       short   t_dupacks;              /* consecutive dup acks recd */
-       uint16_t        t_maxseg;               /* maximum segment size */
-       uint8_t t_force;                /* 1 if forcing out a byte */
-       uint16_t        t_flags;
-#define        TF_ACKNOW       0x0001          /* ack peer immediately */
-#define        TF_DELACK       0x0002          /* ack, but try to delay it */
-#define        TF_NODELAY      0x0004          /* don't delay packets to coalesce */
-#define        TF_NOOPT        0x0008          /* don't use tcp options */
-#define        TF_SENTFIN      0x0010          /* have sent FIN */
-#define        TF_REQ_SCALE    0x0020          /* have/will request window scaling */
-#define        TF_RCVD_SCALE   0x0040          /* other side has requested scaling */
-#define        TF_REQ_TSTMP    0x0080          /* have/will request timestamps */
-#define        TF_RCVD_TSTMP   0x0100          /* a timestamp was received in SYN */
-#define        TF_SACK_PERMIT  0x0200          /* other side said I could SACK */
-
-       struct  tcpiphdr t_template;    /* static skeletal packet for xmit */
-
-       struct  socket *t_socket;               /* back pointer to socket */
-/*
- * The following fields are used as in the protocol specification.
- * See RFC783, Dec. 1981, page 21.
- */
-/* send sequence variables */
-       tcp_seq snd_una;                /* send unacknowledged */
-       tcp_seq snd_nxt;                /* send next */
-       tcp_seq snd_up;                 /* send urgent pointer */
-       tcp_seq snd_wl1;                /* window update seg seq number */
-       tcp_seq snd_wl2;                /* window update seg ack number */
-       tcp_seq iss;                    /* initial send sequence number */
-       uint32_t snd_wnd;               /* send window */
-/* receive sequence variables */
-       uint32_t rcv_wnd;               /* receive window */
-       tcp_seq rcv_nxt;                /* receive next */
-       tcp_seq rcv_up;                 /* receive urgent pointer */
-       tcp_seq irs;                    /* initial receive sequence number */
-/*
- * Additional variables for this implementation.
- */
-/* receive variables */
-       tcp_seq rcv_adv;                /* advertised window */
-/* retransmit variables */
-       tcp_seq snd_max;                /* highest sequence number sent;
-                                        * used to recognize retransmits
-                                        */
-/* congestion control (for slow start, source quench, retransmit after loss) */
-       uint32_t snd_cwnd;              /* congestion-controlled window */
-       uint32_t snd_ssthresh;          /* snd_cwnd size threshold for
-                                        * for slow start exponential to
-                                        * linear switch
-                                        */
-/*
- * transmit timing stuff.  See below for scale of srtt and rttvar.
- * "Variance" is actually smoothed difference.
- */
-       short   t_idle;                 /* inactivity time */
-       short   t_rtt;                  /* round trip time */
-       tcp_seq t_rtseq;                /* sequence number being timed */
-       short   t_srtt;                 /* smoothed round-trip time */
-       short   t_rttvar;               /* variance in round-trip time */
-       uint16_t        t_rttmin;               /* minimum rtt allowed */
-       uint32_t max_sndwnd;            /* largest window peer has offered */
-
-/* out-of-band data */
-       uint8_t t_oobflags;             /* have some */
-       uint8_t t_iobc;                 /* input character */
-#define        TCPOOB_HAVEDATA 0x01
-#define        TCPOOB_HADDATA  0x02
-       short   t_softerror;            /* possible error not yet reported */
-
-/* RFC 1323 variables */
-       uint8_t snd_scale;              /* window scaling for send window */
-       uint8_t rcv_scale;              /* window scaling for recv window */
-       uint8_t request_r_scale;        /* pending window scaling */
-       uint8_t requested_s_scale;
-       uint32_t        ts_recent;              /* timestamp echo data */
-       uint32_t        ts_recent_age;          /* when last updated */
-       tcp_seq last_ack_sent;
-
-};
-
-#define        sototcpcb(so)   ((so)->so_tcpcb)
-
-/*
- * The smoothed round-trip time and estimated variance
- * are stored as fixed point numbers scaled by the values below.
- * For convenience, these scales are also used in smoothing the average
- * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed).
- * With these scales, srtt has 3 bits to the right of the binary point,
- * and thus an "ALPHA" of 0.875.  rttvar has 2 bits to the right of the
- * binary point, and is smoothed with an ALPHA of 0.75.
- */
-#define        TCP_RTT_SCALE           8       /* multiplier for srtt; 3 bits frac. */
-#define        TCP_RTT_SHIFT           3       /* shift for srtt; 3 bits frac. */
-#define        TCP_RTTVAR_SCALE        4       /* multiplier for rttvar; 2 bits */
-#define        TCP_RTTVAR_SHIFT        2       /* multiplier for rttvar; 2 bits */
-
-/*
- * The initial retransmission should happen at rtt + 4 * rttvar.
- * Because of the way we do the smoothing, srtt and rttvar
- * will each average +1/2 tick of bias.  When we compute
- * the retransmit timer, we want 1/2 tick of rounding and
- * 1 extra tick because of +-1/2 tick uncertainty in the
- * firing of the timer.  The bias will give us exactly the
- * 1.5 tick we need.  But, because the bias is
- * statistical, we have to test that we don't drop below
- * the minimum feasible timer (which is 2 ticks).
- * This macro assumes that the value of TCP_RTTVAR_SCALE
- * is the same as the multiplier for rttvar.
- */
-#define        TCP_REXMTVAL(tp) \
-       (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar)
-
-#endif
diff --git a/slirp/tcpip.h b/slirp/tcpip.h
deleted file mode 100644 (file)
index 07dbf2c..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 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. 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.
- *
- *     @(#)tcpip.h     8.1 (Berkeley) 6/10/93
- * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp
- */
-
-#ifndef TCPIP_H
-#define TCPIP_H
-
-/*
- * Tcp+ip header, after ip options removed.
- */
-struct tcpiphdr {
-    struct mbuf_ptr ih_mbuf;   /* backpointer to mbuf */
-    union {
-        struct {
-            struct  in_addr ih_src; /* source internet address */
-            struct  in_addr ih_dst; /* destination internet address */
-            uint8_t ih_x1;          /* (unused) */
-            uint8_t ih_pr;          /* protocol */
-        } ti_i4;
-        struct {
-            struct  in6_addr ih_src;
-            struct  in6_addr ih_dst;
-            uint8_t ih_x1;
-            uint8_t ih_nh;
-        } ti_i6;
-    } ti;
-    uint16_t    ti_x0;
-    uint16_t    ti_len;             /* protocol length */
-    struct      tcphdr ti_t;        /* tcp header */
-};
-#define        ti_mbuf         ih_mbuf.mptr
-#define        ti_pr           ti.ti_i4.ih_pr
-#define        ti_src          ti.ti_i4.ih_src
-#define        ti_dst          ti.ti_i4.ih_dst
-#define        ti_src6         ti.ti_i6.ih_src
-#define        ti_dst6         ti.ti_i6.ih_dst
-#define        ti_nh6          ti.ti_i6.ih_nh
-#define        ti_sport        ti_t.th_sport
-#define        ti_dport        ti_t.th_dport
-#define        ti_seq          ti_t.th_seq
-#define        ti_ack          ti_t.th_ack
-#define        ti_x2           ti_t.th_x2
-#define        ti_off          ti_t.th_off
-#define        ti_flags        ti_t.th_flags
-#define        ti_win          ti_t.th_win
-#define        ti_sum          ti_t.th_sum
-#define        ti_urp          ti_t.th_urp
-
-#define tcpiphdr2qlink(T) ((struct qlink*)(((char*)(T)) - sizeof(struct qlink)))
-#define qlink2tcpiphdr(Q) ((struct tcpiphdr*)(((char*)(Q)) + sizeof(struct qlink)))
-#define tcpiphdr_next(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->next)
-#define tcpiphdr_prev(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->prev)
-#define tcpfrag_list_first(T) qlink2tcpiphdr((T)->seg_next)
-#define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink*)(T))
-#define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr*)(T))
-
-/* This is the difference between the size of a tcpiphdr structure, and the
- * size of actual ip+tcp headers, rounded up since we need to align data.  */
-#define TCPIPHDR_DELTA\
-    (MAX(0,\
-         (sizeof(struct tcpiphdr)\
-          - sizeof(struct ip) - sizeof(struct tcphdr) + 3) & ~3))
-
-/*
- * Just a clean way to get to the first byte
- * of the packet
- */
-struct tcpiphdr_2 {
-       struct tcpiphdr dummy;
-       char first_char;
-};
-
-#endif
diff --git a/slirp/tftp.c b/slirp/tftp.c
deleted file mode 100644 (file)
index 2d8f978..0000000
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * tftp.c - a simple, read-only tftp server for qemu
- *
- * Copyright (c) 2004 Magnus Damm <damm@opensource.se>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "slirp.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-static inline int tftp_session_in_use(struct tftp_session *spt)
-{
-    return (spt->slirp != NULL);
-}
-
-static inline void tftp_session_update(struct tftp_session *spt)
-{
-    spt->timestamp = curtime;
-}
-
-static void tftp_session_terminate(struct tftp_session *spt)
-{
-    if (spt->fd >= 0) {
-        close(spt->fd);
-        spt->fd = -1;
-    }
-    g_free(spt->filename);
-    spt->slirp = NULL;
-}
-
-static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage *srcsas,
-                                 struct tftp_t *tp)
-{
-  struct tftp_session *spt;
-  int k;
-
-  for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
-    spt = &slirp->tftp_sessions[k];
-
-    if (!tftp_session_in_use(spt))
-        goto found;
-
-    /* sessions time out after 5 inactive seconds */
-    if ((int)(curtime - spt->timestamp) > 5000) {
-        tftp_session_terminate(spt);
-        goto found;
-    }
-  }
-
-  return -1;
-
- found:
-  memset(spt, 0, sizeof(*spt));
-  memcpy(&spt->client_addr, srcsas, sockaddr_size(srcsas));
-  spt->fd = -1;
-  spt->block_size = 512;
-  spt->client_port = tp->udp.uh_sport;
-  spt->slirp = slirp;
-
-  tftp_session_update(spt);
-
-  return k;
-}
-
-static int tftp_session_find(Slirp *slirp, struct sockaddr_storage *srcsas,
-                             struct tftp_t *tp)
-{
-  struct tftp_session *spt;
-  int k;
-
-  for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
-    spt = &slirp->tftp_sessions[k];
-
-    if (tftp_session_in_use(spt)) {
-      if (sockaddr_equal(&spt->client_addr, srcsas)) {
-       if (spt->client_port == tp->udp.uh_sport) {
-         return k;
-       }
-      }
-    }
-  }
-
-  return -1;
-}
-
-static int tftp_read_data(struct tftp_session *spt, uint32_t block_nr,
-                          uint8_t *buf, int len)
-{
-    int bytes_read = 0;
-
-    if (spt->fd < 0) {
-        spt->fd = open(spt->filename, O_RDONLY | O_BINARY);
-    }
-
-    if (spt->fd < 0) {
-        return -1;
-    }
-
-    if (len) {
-        lseek(spt->fd, block_nr * spt->block_size, SEEK_SET);
-
-        bytes_read = read(spt->fd, buf, len);
-    }
-
-    return bytes_read;
-}
-
-static struct tftp_t *tftp_prep_mbuf_data(struct tftp_session *spt,
-                                          struct mbuf *m)
-{
-    struct tftp_t *tp;
-
-    memset(m->m_data, 0, m->m_size);
-
-    m->m_data += IF_MAXLINKHDR;
-    if (spt->client_addr.ss_family == AF_INET6) {
-        m->m_data += sizeof(struct ip6);
-    } else {
-        m->m_data += sizeof(struct ip);
-    }
-    tp = (void *)m->m_data;
-    m->m_data += sizeof(struct udphdr);
-
-    return tp;
-}
-
-static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m,
-                            struct tftp_t *recv_tp)
-{
-    if (spt->client_addr.ss_family == AF_INET6) {
-        struct sockaddr_in6 sa6, da6;
-
-        sa6.sin6_addr = spt->slirp->vhost_addr6;
-        sa6.sin6_port = recv_tp->udp.uh_dport;
-        da6.sin6_addr = ((struct sockaddr_in6 *)&spt->client_addr)->sin6_addr;
-        da6.sin6_port = spt->client_port;
-
-        udp6_output(NULL, m, &sa6, &da6);
-    } else {
-        struct sockaddr_in sa4, da4;
-
-        sa4.sin_addr = spt->slirp->vhost_addr;
-        sa4.sin_port = recv_tp->udp.uh_dport;
-        da4.sin_addr = ((struct sockaddr_in *)&spt->client_addr)->sin_addr;
-        da4.sin_port = spt->client_port;
-
-        udp_output(NULL, m, &sa4, &da4, IPTOS_LOWDELAY);
-    }
-}
-
-static int tftp_send_oack(struct tftp_session *spt,
-                          const char *keys[], uint32_t values[], int nb,
-                          struct tftp_t *recv_tp)
-{
-    struct mbuf *m;
-    struct tftp_t *tp;
-    int i, n = 0;
-
-    m = m_get(spt->slirp);
-
-    if (!m)
-        return -1;
-
-    tp = tftp_prep_mbuf_data(spt, m);
-
-    tp->tp_op = htons(TFTP_OACK);
-    for (i = 0; i < nb; i++) {
-        n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
-                      keys[i]) + 1;
-        n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
-                      values[i]) + 1;
-    }
-
-    m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + n
-               - sizeof(struct udphdr);
-    tftp_udp_output(spt, m, recv_tp);
-
-    return 0;
-}
-
-static void tftp_send_error(struct tftp_session *spt,
-                            uint16_t errorcode, const char *msg,
-                            struct tftp_t *recv_tp)
-{
-  struct mbuf *m;
-  struct tftp_t *tp;
-
-  DEBUG_TFTP("tftp error msg: %s", msg);
-
-  m = m_get(spt->slirp);
-
-  if (!m) {
-    goto out;
-  }
-
-  tp = tftp_prep_mbuf_data(spt, m);
-
-  tp->tp_op = htons(TFTP_ERROR);
-  tp->x.tp_error.tp_error_code = htons(errorcode);
-  slirp_pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg);
-
-  m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + 3 + strlen(msg)
-             - sizeof(struct udphdr);
-  tftp_udp_output(spt, m, recv_tp);
-
-out:
-  tftp_session_terminate(spt);
-}
-
-static void tftp_send_next_block(struct tftp_session *spt,
-                                 struct tftp_t *recv_tp)
-{
-  struct mbuf *m;
-  struct tftp_t *tp;
-  int nobytes;
-
-  m = m_get(spt->slirp);
-
-  if (!m) {
-    return;
-  }
-
-  tp = tftp_prep_mbuf_data(spt, m);
-
-  tp->tp_op = htons(TFTP_DATA);
-  tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff);
-
-  nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf,
-                           spt->block_size);
-
-  if (nobytes < 0) {
-    m_free(m);
-
-    /* send "file not found" error back */
-
-    tftp_send_error(spt, 1, "File not found", tp);
-
-    return;
-  }
-
-  m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX - nobytes)
-             - sizeof(struct udphdr);
-  tftp_udp_output(spt, m, recv_tp);
-
-  if (nobytes == spt->block_size) {
-    tftp_session_update(spt);
-  }
-  else {
-    tftp_session_terminate(spt);
-  }
-
-  spt->block_nr++;
-}
-
-static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
-                            struct tftp_t *tp, int pktlen)
-{
-  struct tftp_session *spt;
-  int s, k;
-  size_t prefix_len;
-  char *req_fname;
-  const char *option_name[2];
-  uint32_t option_value[2];
-  int nb_options = 0;
-
-  /* check if a session already exists and if so terminate it */
-  s = tftp_session_find(slirp, srcsas, tp);
-  if (s >= 0) {
-    tftp_session_terminate(&slirp->tftp_sessions[s]);
-  }
-
-  s = tftp_session_allocate(slirp, srcsas, tp);
-
-  if (s < 0) {
-    return;
-  }
-
-  spt = &slirp->tftp_sessions[s];
-
-  /* unspecified prefix means service disabled */
-  if (!slirp->tftp_prefix) {
-      tftp_send_error(spt, 2, "Access violation", tp);
-      return;
-  }
-
-  /* skip header fields */
-  k = 0;
-  pktlen -= offsetof(struct tftp_t, x.tp_buf);
-
-  /* prepend tftp_prefix */
-  prefix_len = strlen(slirp->tftp_prefix);
-  spt->filename = g_malloc(prefix_len + TFTP_FILENAME_MAX + 2);
-  memcpy(spt->filename, slirp->tftp_prefix, prefix_len);
-  spt->filename[prefix_len] = '/';
-
-  /* get name */
-  req_fname = spt->filename + prefix_len + 1;
-
-  while (1) {
-    if (k >= TFTP_FILENAME_MAX || k >= pktlen) {
-      tftp_send_error(spt, 2, "Access violation", tp);
-      return;
-    }
-    req_fname[k] = tp->x.tp_buf[k];
-    if (req_fname[k++] == '\0') {
-      break;
-    }
-  }
-
-  DEBUG_TFTP("tftp rrq file: %s", req_fname);
-
-  /* check mode */
-  if ((pktlen - k) < 6) {
-    tftp_send_error(spt, 2, "Access violation", tp);
-    return;
-  }
-
-  if (strcasecmp(&tp->x.tp_buf[k], "octet") != 0) {
-      tftp_send_error(spt, 4, "Unsupported transfer mode", tp);
-      return;
-  }
-
-  k += 6; /* skipping octet */
-
-  /* do sanity checks on the filename */
-  if (!strncmp(req_fname, "../", 3) ||
-      req_fname[strlen(req_fname) - 1] == '/' ||
-      strstr(req_fname, "/../")) {
-      tftp_send_error(spt, 2, "Access violation", tp);
-      return;
-  }
-
-  /* check if the file exists */
-  if (tftp_read_data(spt, 0, NULL, 0) < 0) {
-      tftp_send_error(spt, 1, "File not found", tp);
-      return;
-  }
-
-  if (tp->x.tp_buf[pktlen - 1] != 0) {
-      tftp_send_error(spt, 2, "Access violation", tp);
-      return;
-  }
-
-  while (k < pktlen && nb_options < G_N_ELEMENTS(option_name)) {
-      const char *key, *value;
-
-      key = &tp->x.tp_buf[k];
-      k += strlen(key) + 1;
-
-      if (k >= pktlen) {
-         tftp_send_error(spt, 2, "Access violation", tp);
-         return;
-      }
-
-      value = &tp->x.tp_buf[k];
-      k += strlen(value) + 1;
-
-      if (strcasecmp(key, "tsize") == 0) {
-         int tsize = atoi(value);
-         struct stat stat_p;
-
-         if (tsize == 0) {
-             if (stat(spt->filename, &stat_p) == 0)
-                 tsize = stat_p.st_size;
-             else {
-                 tftp_send_error(spt, 1, "File not found", tp);
-                 return;
-             }
-         }
-
-          option_name[nb_options] = "tsize";
-          option_value[nb_options] = tsize;
-          nb_options++;
-      } else if (strcasecmp(key, "blksize") == 0) {
-          int blksize = atoi(value);
-
-          /* Accept blksize up to our maximum size */
-          if (blksize > 0) {
-              spt->block_size = MIN(blksize, TFTP_BLOCKSIZE_MAX);
-              option_name[nb_options] = "blksize";
-              option_value[nb_options] = spt->block_size;
-              nb_options++;
-          }
-      }
-  }
-
-  if (nb_options > 0) {
-      assert(nb_options <= G_N_ELEMENTS(option_name));
-      tftp_send_oack(spt, option_name, option_value, nb_options, tp);
-      return;
-  }
-
-  spt->block_nr = 0;
-  tftp_send_next_block(spt, tp);
-}
-
-static void tftp_handle_ack(Slirp *slirp, struct sockaddr_storage *srcsas,
-                            struct tftp_t *tp, int pktlen)
-{
-  int s;
-
-  s = tftp_session_find(slirp, srcsas, tp);
-
-  if (s < 0) {
-    return;
-  }
-
-  tftp_send_next_block(&slirp->tftp_sessions[s], tp);
-}
-
-static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas,
-                              struct tftp_t *tp, int pktlen)
-{
-  int s;
-
-  s = tftp_session_find(slirp, srcsas, tp);
-
-  if (s < 0) {
-    return;
-  }
-
-  tftp_session_terminate(&slirp->tftp_sessions[s]);
-}
-
-void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m)
-{
-  struct tftp_t *tp = (struct tftp_t *)m->m_data;
-
-  switch(ntohs(tp->tp_op)) {
-  case TFTP_RRQ:
-    tftp_handle_rrq(m->slirp, srcsas, tp, m->m_len);
-    break;
-
-  case TFTP_ACK:
-    tftp_handle_ack(m->slirp, srcsas, tp, m->m_len);
-    break;
-
-  case TFTP_ERROR:
-    tftp_handle_error(m->slirp, srcsas, tp, m->m_len);
-    break;
-  }
-}
diff --git a/slirp/tftp.h b/slirp/tftp.h
deleted file mode 100644 (file)
index a4c4a64..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* tftp defines */
-
-#ifndef SLIRP_TFTP_H
-#define SLIRP_TFTP_H
-
-#define TFTP_SESSIONS_MAX 20
-
-#define TFTP_SERVER    69
-
-#define TFTP_RRQ    1
-#define TFTP_WRQ    2
-#define TFTP_DATA   3
-#define TFTP_ACK    4
-#define TFTP_ERROR  5
-#define TFTP_OACK   6
-
-#define TFTP_FILENAME_MAX 512
-#define TFTP_BLOCKSIZE_MAX 1428
-
-struct tftp_t {
-  struct udphdr udp;
-  uint16_t tp_op;
-  union {
-    struct {
-      uint16_t tp_block_nr;
-      uint8_t tp_buf[TFTP_BLOCKSIZE_MAX];
-    } tp_data;
-    struct {
-      uint16_t tp_error_code;
-      uint8_t tp_msg[TFTP_BLOCKSIZE_MAX];
-    } tp_error;
-    char tp_buf[TFTP_BLOCKSIZE_MAX + 2];
-  } x;
-} __attribute__((packed));
-
-struct tftp_session {
-    Slirp *slirp;
-    char *filename;
-    int fd;
-    uint16_t block_size;
-
-    struct sockaddr_storage client_addr;
-    uint16_t client_port;
-    uint32_t block_nr;
-
-    int timestamp;
-};
-
-void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m);
-
-#endif
diff --git a/slirp/udp.c b/slirp/udp.c
deleted file mode 100644 (file)
index 3d9a19b..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 1988, 1990, 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. 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.
- *
- *     @(#)udp_usrreq.c        8.4 (Berkeley) 1/21/94
- * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp
- */
-
-/*
- * Changes and additions relating to SLiRP
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#include "slirp.h"
-#include "ip_icmp.h"
-
-static uint8_t udp_tos(struct socket *so);
-
-void
-udp_init(Slirp *slirp)
-{
-    slirp->udb.so_next = slirp->udb.so_prev = &slirp->udb;
-    slirp->udp_last_so = &slirp->udb;
-}
-
-void udp_cleanup(Slirp *slirp)
-{
-    while (slirp->udb.so_next != &slirp->udb) {
-        udp_detach(slirp->udb.so_next);
-    }
-}
-
-/* m->m_data  points at ip packet header
- * m->m_len   length ip packet
- * ip->ip_len length data (IPDU)
- */
-void
-udp_input(register struct mbuf *m, int iphlen)
-{
-       Slirp *slirp = m->slirp;
-       register struct ip *ip;
-       register struct udphdr *uh;
-       int len;
-       struct ip save_ip;
-       struct socket *so;
-       struct sockaddr_storage lhost;
-       struct sockaddr_in *lhost4;
-
-       DEBUG_CALL("udp_input");
-       DEBUG_ARG("m = %p", m);
-       DEBUG_ARG("iphlen = %d", iphlen);
-
-       /*
-        * Strip IP options, if any; should skip this,
-        * make available to user, and use on returned packets,
-        * but we don't yet have a way to check the checksum
-        * with options still present.
-        */
-       if(iphlen > sizeof(struct ip)) {
-               ip_stripoptions(m, (struct mbuf *)0);
-               iphlen = sizeof(struct ip);
-       }
-
-       /*
-        * Get IP and UDP header together in first mbuf.
-        */
-       ip = mtod(m, struct ip *);
-       uh = (struct udphdr *)((char *)ip + iphlen);
-
-       /*
-        * Make mbuf data length reflect UDP length.
-        * If not enough data to reflect UDP length, drop.
-        */
-       len = ntohs((uint16_t)uh->uh_ulen);
-
-       if (ip->ip_len != len) {
-               if (len > ip->ip_len) {
-                       goto bad;
-               }
-               m_adj(m, len - ip->ip_len);
-               ip->ip_len = len;
-       }
-
-       /*
-        * Save a copy of the IP header in case we want restore it
-        * for sending an ICMP error message in response.
-        */
-       save_ip = *ip;
-       save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */
-
-       /*
-        * Checksum extended UDP header and data.
-        */
-       if (uh->uh_sum) {
-      memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
-         ((struct ipovly *)ip)->ih_x1 = 0;
-         ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
-         if(cksum(m, len + sizeof(struct ip))) {
-           goto bad;
-         }
-       }
-
-       lhost.ss_family = AF_INET;
-       lhost4 = (struct sockaddr_in *) &lhost;
-       lhost4->sin_addr = ip->ip_src;
-       lhost4->sin_port = uh->uh_sport;
-
-        /*
-         *  handle DHCP/BOOTP
-         */
-        if (ntohs(uh->uh_dport) == BOOTP_SERVER &&
-            (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
-             ip->ip_dst.s_addr == 0xffffffff)) {
-                bootp_input(m);
-                goto bad;
-            }
-
-        /*
-         *  handle TFTP
-         */
-        if (ntohs(uh->uh_dport) == TFTP_SERVER &&
-            ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
-            m->m_data += iphlen;
-            m->m_len -= iphlen;
-            tftp_input(&lhost, m);
-            m->m_data -= iphlen;
-            m->m_len += iphlen;
-            goto bad;
-        }
-
-        if (slirp->restricted) {
-            goto bad;
-        }
-
-       /*
-        * Locate pcb for datagram.
-        */
-       so = solookup(&slirp->udp_last_so, &slirp->udb, &lhost, NULL);
-
-       if (so == NULL) {
-         /*
-          * If there's no socket for this packet,
-          * create one
-          */
-         so = socreate(slirp);
-         if (udp_attach(so, AF_INET) == -1) {
-           DEBUG_MISC(" udp_attach errno = %d-%s", errno, strerror(errno));
-           sofree(so);
-           goto bad;
-         }
-
-         /*
-          * Setup fields
-          */
-         so->so_lfamily = AF_INET;
-         so->so_laddr = ip->ip_src;
-         so->so_lport = uh->uh_sport;
-
-         if ((so->so_iptos = udp_tos(so)) == 0)
-           so->so_iptos = ip->ip_tos;
-
-         /*
-          * XXXXX Here, check if it's in udpexec_list,
-          * and if it is, do the fork_exec() etc.
-          */
-       }
-
-        so->so_ffamily = AF_INET;
-        so->so_faddr = ip->ip_dst; /* XXX */
-        so->so_fport = uh->uh_dport; /* XXX */
-
-       iphlen += sizeof(struct udphdr);
-       m->m_len -= iphlen;
-       m->m_data += iphlen;
-
-       /*
-        * Now we sendto() the packet.
-        */
-       if(sosendto(so,m) == -1) {
-         m->m_len += iphlen;
-         m->m_data -= iphlen;
-         *ip=save_ip;
-         DEBUG_MISC("udp tx errno = %d-%s", errno, strerror(errno));
-         icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0,
-                         strerror(errno));
-         goto bad;
-       }
-
-       m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
-
-       /* restore the orig mbuf packet */
-       m->m_len += iphlen;
-       m->m_data -= iphlen;
-       *ip=save_ip;
-       so->so_m=m;         /* ICMP backup */
-
-       return;
-bad:
-       m_free(m);
-}
-
-int udp_output(struct socket *so, struct mbuf *m,
-                struct sockaddr_in *saddr, struct sockaddr_in *daddr,
-                int iptos)
-{
-       register struct udpiphdr *ui;
-       int error = 0;
-
-       DEBUG_CALL("udp_output");
-       DEBUG_ARG("so = %p", so);
-       DEBUG_ARG("m = %p", m);
-       DEBUG_ARG("saddr = %s", inet_ntoa(saddr->sin_addr));
-       DEBUG_ARG("daddr = %s", inet_ntoa(daddr->sin_addr));
-
-       /*
-        * Adjust for header
-        */
-       m->m_data -= sizeof(struct udpiphdr);
-       m->m_len += sizeof(struct udpiphdr);
-
-       /*
-        * Fill in mbuf with extended UDP header
-        * and addresses and length put into network format.
-        */
-       ui = mtod(m, struct udpiphdr *);
-    memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
-       ui->ui_x1 = 0;
-       ui->ui_pr = IPPROTO_UDP;
-       ui->ui_len = htons(m->m_len - sizeof(struct ip));
-       /* XXXXX Check for from-one-location sockets, or from-any-location sockets */
-        ui->ui_src = saddr->sin_addr;
-       ui->ui_dst = daddr->sin_addr;
-       ui->ui_sport = saddr->sin_port;
-       ui->ui_dport = daddr->sin_port;
-       ui->ui_ulen = ui->ui_len;
-
-       /*
-        * Stuff checksum and output datagram.
-        */
-       ui->ui_sum = 0;
-       if ((ui->ui_sum = cksum(m, m->m_len)) == 0)
-               ui->ui_sum = 0xffff;
-       ((struct ip *)ui)->ip_len = m->m_len;
-
-       ((struct ip *)ui)->ip_ttl = IPDEFTTL;
-       ((struct ip *)ui)->ip_tos = iptos;
-
-       error = ip_output(so, m);
-
-       return (error);
-}
-
-int
-udp_attach(struct socket *so, unsigned short af)
-{
-  so->s = slirp_socket(af, SOCK_DGRAM, 0);
-  if (so->s != -1) {
-    so->so_expire = curtime + SO_EXPIRE;
-    insque(so, &so->slirp->udb);
-  }
-  return(so->s);
-}
-
-void
-udp_detach(struct socket *so)
-{
-       so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
-       closesocket(so->s);
-       sofree(so);
-}
-
-static const struct tos_t udptos[] = {
-       {0, 53, IPTOS_LOWDELAY, 0},                     /* DNS */
-       {0, 0, 0, 0}
-};
-
-static uint8_t
-udp_tos(struct socket *so)
-{
-       int i = 0;
-
-       while(udptos[i].tos) {
-               if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
-                   (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
-                       so->so_emu = udptos[i].emu;
-                       return udptos[i].tos;
-               }
-               i++;
-       }
-
-       return 0;
-}
-
-struct socket *
-udp_listen(Slirp *slirp, uint32_t haddr, unsigned hport, uint32_t laddr,
-           unsigned lport, int flags)
-{
-       struct sockaddr_in addr;
-       struct socket *so;
-       socklen_t addrlen = sizeof(struct sockaddr_in);
-
-       so = socreate(slirp);
-       so->s = slirp_socket(AF_INET,SOCK_DGRAM,0);
-        if (so->s < 0) {
-            sofree(so);
-            return NULL;
-        }
-       so->so_expire = curtime + SO_EXPIRE;
-       insque(so, &slirp->udb);
-
-       addr.sin_family = AF_INET;
-       addr.sin_addr.s_addr = haddr;
-       addr.sin_port = hport;
-
-       if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
-               udp_detach(so);
-               return NULL;
-       }
-       slirp_socket_set_fast_reuse(so->s);
-
-       getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
-       so->fhost.sin = addr;
-       sotranslate_accept(so);
-       so->so_lfamily = AF_INET;
-       so->so_lport = lport;
-       so->so_laddr.s_addr = laddr;
-       if (flags != SS_FACCEPTONCE)
-          so->so_expire = 0;
-
-       so->so_state &= SS_PERSISTENT_MASK;
-       so->so_state |= SS_ISFCONNECTED | flags;
-
-       return so;
-}
diff --git a/slirp/udp.h b/slirp/udp.h
deleted file mode 100644 (file)
index 3d29504..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 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. 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.
- *
- *     @(#)udp.h       8.1 (Berkeley) 6/10/93
- * udp.h,v 1.3 1994/08/21 05:27:41 paul Exp
- */
-
-#ifndef UDP_H
-#define UDP_H
-
-#define UDP_TTL 0x60
-#define UDP_UDPDATALEN 16192
-
-/*
- * Udp protocol header.
- * Per RFC 768, September, 1981.
- */
-struct udphdr {
-    uint16_t uh_sport;          /* source port */
-    uint16_t uh_dport;          /* destination port */
-    int16_t  uh_ulen;           /* udp length */
-    uint16_t uh_sum;            /* udp checksum */
-};
-
-/*
- * UDP kernel structures and variables.
- */
-struct udpiphdr {
-               struct  ipovly ui_i;            /* overlaid ip structure */
-               struct  udphdr ui_u;            /* udp header */
-};
-#define ui_mbuf         ui_i.ih_mbuf.mptr
-#define ui_x1           ui_i.ih_x1
-#define ui_pr           ui_i.ih_pr
-#define ui_len          ui_i.ih_len
-#define ui_src          ui_i.ih_src
-#define ui_dst          ui_i.ih_dst
-#define ui_sport        ui_u.uh_sport
-#define ui_dport        ui_u.uh_dport
-#define ui_ulen         ui_u.uh_ulen
-#define ui_sum          ui_u.uh_sum
-
-/*
- * Names for UDP sysctl objects
- */
-#define UDPCTL_CHECKSUM         1       /* checksum UDP packets */
-#define UDPCTL_MAXID            2
-
-struct mbuf;
-
-void udp_init(Slirp *);
-void udp_cleanup(Slirp *);
-void udp_input(register struct mbuf *, int);
-int udp_attach(struct socket *, unsigned short af);
-void udp_detach(struct socket *);
-struct socket * udp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned,
-                           int);
-int udp_output(struct socket *so, struct mbuf *m,
-                struct sockaddr_in *saddr, struct sockaddr_in *daddr,
-                int iptos);
-
-void udp6_input(register struct mbuf *);
-int udp6_output(struct socket *so, struct mbuf *m,
-                struct sockaddr_in6 *saddr, struct sockaddr_in6 *daddr);
-
-#endif
diff --git a/slirp/udp6.c b/slirp/udp6.c
deleted file mode 100644 (file)
index be5cba1..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2013
- * Guillaume Subiron
- */
-
-#include "slirp.h"
-#include "udp.h"
-#include "dhcpv6.h"
-
-void udp6_input(struct mbuf *m)
-{
-    Slirp *slirp = m->slirp;
-    struct ip6 *ip, save_ip;
-    struct udphdr *uh;
-    int iphlen = sizeof(struct ip6);
-    int len;
-    struct socket *so;
-    struct sockaddr_in6 lhost;
-
-    DEBUG_CALL("udp6_input");
-    DEBUG_ARG("m = %p", m);
-
-    if (slirp->restricted) {
-        goto bad;
-    }
-
-    ip = mtod(m, struct ip6 *);
-    m->m_len -= iphlen;
-    m->m_data += iphlen;
-    uh = mtod(m, struct udphdr *);
-    m->m_len += iphlen;
-    m->m_data -= iphlen;
-
-    if (ip6_cksum(m)) {
-        goto bad;
-    }
-
-    len = ntohs((uint16_t)uh->uh_ulen);
-
-    /*
-     * Make mbuf data length reflect UDP length.
-     * If not enough data to reflect UDP length, drop.
-     */
-    if (ntohs(ip->ip_pl) != len) {
-        if (len > ntohs(ip->ip_pl)) {
-            goto bad;
-        }
-        m_adj(m, len - ntohs(ip->ip_pl));
-        ip->ip_pl = htons(len);
-    }
-
-    /*
-     * Save a copy of the IP header in case we want restore it
-     * for sending an ICMP error message in response.
-     */
-    save_ip = *ip;
-
-    /* Locate pcb for datagram. */
-    lhost.sin6_family = AF_INET6;
-    lhost.sin6_addr = ip->ip_src;
-    lhost.sin6_port = uh->uh_sport;
-
-    /* handle DHCPv6 */
-    if (ntohs(uh->uh_dport) == DHCPV6_SERVER_PORT &&
-        (in6_equal(&ip->ip_dst, &slirp->vhost_addr6) ||
-         in6_dhcp_multicast(&ip->ip_dst))) {
-        m->m_data += iphlen;
-        m->m_len -= iphlen;
-        dhcpv6_input(&lhost, m);
-        m->m_data -= iphlen;
-        m->m_len += iphlen;
-        goto bad;
-    }
-
-    /* handle TFTP */
-    if (ntohs(uh->uh_dport) == TFTP_SERVER &&
-        !memcmp(ip->ip_dst.s6_addr, slirp->vhost_addr6.s6_addr, 16)) {
-        m->m_data += iphlen;
-        m->m_len -= iphlen;
-        tftp_input((struct sockaddr_storage *)&lhost, m);
-        m->m_data -= iphlen;
-        m->m_len += iphlen;
-        goto bad;
-    }
-
-    so = solookup(&slirp->udp_last_so, &slirp->udb,
-                  (struct sockaddr_storage *) &lhost, NULL);
-
-    if (so == NULL) {
-        /* If there's no socket for this packet, create one. */
-        so = socreate(slirp);
-        if (udp_attach(so, AF_INET6) == -1) {
-            DEBUG_MISC(" udp6_attach errno = %d-%s", errno, strerror(errno));
-            sofree(so);
-            goto bad;
-        }
-
-        /* Setup fields */
-        so->so_lfamily = AF_INET6;
-        so->so_laddr6 = ip->ip_src;
-        so->so_lport6 = uh->uh_sport;
-    }
-
-    so->so_ffamily = AF_INET6;
-    so->so_faddr6 = ip->ip_dst; /* XXX */
-    so->so_fport6 = uh->uh_dport; /* XXX */
-
-    iphlen += sizeof(struct udphdr);
-    m->m_len -= iphlen;
-    m->m_data += iphlen;
-
-    /*
-     * Now we sendto() the packet.
-     */
-    if (sosendto(so, m) == -1) {
-        m->m_len += iphlen;
-        m->m_data -= iphlen;
-        *ip = save_ip;
-        DEBUG_MISC("udp tx errno = %d-%s", errno, strerror(errno));
-        icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
-        goto bad;
-    }
-
-    m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
-
-    /* restore the orig mbuf packet */
-    m->m_len += iphlen;
-    m->m_data -= iphlen;
-    *ip = save_ip;
-    so->so_m = m;
-
-    return;
-bad:
-    m_free(m);
-}
-
-int udp6_output(struct socket *so, struct mbuf *m,
-        struct sockaddr_in6 *saddr, struct sockaddr_in6 *daddr)
-{
-    struct ip6 *ip;
-    struct udphdr *uh;
-
-    DEBUG_CALL("udp6_output");
-    DEBUG_ARG("so = %p", so);
-    DEBUG_ARG("m = %p", m);
-
-    /* adjust for header */
-    m->m_data -= sizeof(struct udphdr);
-    m->m_len += sizeof(struct udphdr);
-    uh = mtod(m, struct udphdr *);
-    m->m_data -= sizeof(struct ip6);
-    m->m_len += sizeof(struct ip6);
-    ip = mtod(m, struct ip6 *);
-
-    /* Build IP header */
-    ip->ip_pl = htons(m->m_len - sizeof(struct ip6));
-    ip->ip_nh = IPPROTO_UDP;
-    ip->ip_src = saddr->sin6_addr;
-    ip->ip_dst = daddr->sin6_addr;
-
-    /* Build UDP header */
-    uh->uh_sport = saddr->sin6_port;
-    uh->uh_dport = daddr->sin6_port;
-    uh->uh_ulen = ip->ip_pl;
-    uh->uh_sum = 0;
-    uh->uh_sum = ip6_cksum(m);
-    if (uh->uh_sum == 0) {
-        uh->uh_sum = 0xffff;
-    }
-
-    return ip6_output(so, m, 0);
-}
diff --git a/slirp/util.c b/slirp/util.c
deleted file mode 100644 (file)
index 1cbaa26..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * util.c (mostly based on QEMU os-win32.c)
- *
- * Copyright (c) 2003-2008 Fabrice Bellard
- * Copyright (c) 2010-2016 Red Hat, Inc.
- *
- * QEMU library functions for win32 which are shared between QEMU and
- * the QEMU tools.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "util.h"
-
-#include <glib.h>
-#include <fcntl.h>
-#include <stdint.h>
-
-#if defined(_WIN32) && !defined(WITH_QEMU)
-int inet_aton(const char *cp, struct in_addr *ia)
-{
-    uint32_t addr = inet_addr(cp);
-    if (addr == 0xffffffff) {
-        return 0;
-    }
-    ia->s_addr = addr;
-    return 1;
-}
-#endif
-
-void slirp_set_nonblock(int fd)
-{
-#ifndef _WIN32
-    int f;
-    f = fcntl(fd, F_GETFL);
-    assert(f != -1);
-    f = fcntl(fd, F_SETFL, f | O_NONBLOCK);
-    assert(f != -1);
-#else
-    unsigned long opt = 1;
-    ioctlsocket(fd, FIONBIO, &opt);
-#endif
-}
-
-static void slirp_set_cloexec(int fd)
-{
-#ifndef _WIN32
-    int f;
-    f = fcntl(fd, F_GETFD);
-    assert(f != -1);
-    f = fcntl(fd, F_SETFD, f | FD_CLOEXEC);
-    assert(f != -1);
-#endif
-}
-
-/*
- * Opens a socket with FD_CLOEXEC set
- */
-int slirp_socket(int domain, int type, int protocol)
-{
-    int ret;
-
-#ifdef SOCK_CLOEXEC
-    ret = socket(domain, type | SOCK_CLOEXEC, protocol);
-    if (ret != -1 || errno != EINVAL) {
-        return ret;
-    }
-#endif
-    ret = socket(domain, type, protocol);
-    if (ret >= 0) {
-        slirp_set_cloexec(ret);
-    }
-
-    return ret;
-}
-
-#ifdef _WIN32
-static int socket_error(void)
-{
-    switch (WSAGetLastError()) {
-    case 0:
-        return 0;
-    case WSAEINTR:
-        return EINTR;
-    case WSAEINVAL:
-        return EINVAL;
-    case WSA_INVALID_HANDLE:
-        return EBADF;
-    case WSA_NOT_ENOUGH_MEMORY:
-        return ENOMEM;
-    case WSA_INVALID_PARAMETER:
-        return EINVAL;
-    case WSAENAMETOOLONG:
-        return ENAMETOOLONG;
-    case WSAENOTEMPTY:
-        return ENOTEMPTY;
-    case WSAEWOULDBLOCK:
-         /* not using EWOULDBLOCK as we don't want code to have
-          * to check both EWOULDBLOCK and EAGAIN */
-        return EAGAIN;
-    case WSAEINPROGRESS:
-        return EINPROGRESS;
-    case WSAEALREADY:
-        return EALREADY;
-    case WSAENOTSOCK:
-        return ENOTSOCK;
-    case WSAEDESTADDRREQ:
-        return EDESTADDRREQ;
-    case WSAEMSGSIZE:
-        return EMSGSIZE;
-    case WSAEPROTOTYPE:
-        return EPROTOTYPE;
-    case WSAENOPROTOOPT:
-        return ENOPROTOOPT;
-    case WSAEPROTONOSUPPORT:
-        return EPROTONOSUPPORT;
-    case WSAEOPNOTSUPP:
-        return EOPNOTSUPP;
-    case WSAEAFNOSUPPORT:
-        return EAFNOSUPPORT;
-    case WSAEADDRINUSE:
-        return EADDRINUSE;
-    case WSAEADDRNOTAVAIL:
-        return EADDRNOTAVAIL;
-    case WSAENETDOWN:
-        return ENETDOWN;
-    case WSAENETUNREACH:
-        return ENETUNREACH;
-    case WSAENETRESET:
-        return ENETRESET;
-    case WSAECONNABORTED:
-        return ECONNABORTED;
-    case WSAECONNRESET:
-        return ECONNRESET;
-    case WSAENOBUFS:
-        return ENOBUFS;
-    case WSAEISCONN:
-        return EISCONN;
-    case WSAENOTCONN:
-        return ENOTCONN;
-    case WSAETIMEDOUT:
-        return ETIMEDOUT;
-    case WSAECONNREFUSED:
-        return ECONNREFUSED;
-    case WSAELOOP:
-        return ELOOP;
-    case WSAEHOSTUNREACH:
-        return EHOSTUNREACH;
-    default:
-        return EIO;
-    }
-}
-
-#undef ioctlsocket
-int slirp_ioctlsocket_wrap(int fd, int req, void *val)
-{
-    int ret;
-    ret = ioctlsocket(fd, req, val);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-
-#undef closesocket
-int slirp_closesocket_wrap(int fd)
-{
-    int ret;
-    ret = closesocket(fd);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-
-#undef connect
-int slirp_connect_wrap(int sockfd, const struct sockaddr *addr, int addrlen)
-{
-    int ret;
-    ret = connect(sockfd, addr, addrlen);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-
-#undef listen
-int slirp_listen_wrap(int sockfd, int backlog)
-{
-    int ret;
-    ret = listen(sockfd, backlog);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-
-#undef bind
-int slirp_bind_wrap(int sockfd, const struct sockaddr *addr, int addrlen)
-{
-    int ret;
-    ret = bind(sockfd, addr, addrlen);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-
-#undef socket
-int slirp_socket_wrap(int domain, int type, int protocol)
-{
-    int ret;
-    ret = socket(domain, type, protocol);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-
-#undef accept
-int slirp_accept_wrap(int sockfd, struct sockaddr *addr, int *addrlen)
-{
-    int ret;
-    ret = accept(sockfd, addr, addrlen);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-
-#undef shutdown
-int slirp_shutdown_wrap(int sockfd, int how)
-{
-    int ret;
-    ret = shutdown(sockfd, how);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-
-#undef getsockopt
-int slirp_getsockopt_wrap(int sockfd, int level, int optname,
-                          void *optval, int *optlen)
-{
-    int ret;
-    ret = getsockopt(sockfd, level, optname, optval, optlen);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-
-#undef setsockopt
-int slirp_setsockopt_wrap(int sockfd, int level, int optname,
-                          const void *optval, int optlen)
-{
-    int ret;
-    ret = setsockopt(sockfd, level, optname, optval, optlen);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-
-#undef getpeername
-int slirp_getpeername_wrap(int sockfd, struct sockaddr *addr,
-                           int *addrlen)
-{
-    int ret;
-    ret = getpeername(sockfd, addr, addrlen);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-
-#undef getsockname
-int slirp_getsockname_wrap(int sockfd, struct sockaddr *addr,
-                           int *addrlen)
-{
-    int ret;
-    ret = getsockname(sockfd, addr, addrlen);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-
-#undef send
-ssize_t slirp_send_wrap(int sockfd, const void *buf, size_t len, int flags)
-{
-    int ret;
-    ret = send(sockfd, buf, len, flags);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-
-#undef sendto
-ssize_t slirp_sendto_wrap(int sockfd, const void *buf, size_t len, int flags,
-                     const struct sockaddr *addr, int addrlen)
-{
-    int ret;
-    ret = sendto(sockfd, buf, len, flags, addr, addrlen);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-
-#undef recv
-ssize_t slirp_recv_wrap(int sockfd, void *buf, size_t len, int flags)
-{
-    int ret;
-    ret = recv(sockfd, buf, len, flags);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-
-#undef recvfrom
-ssize_t slirp_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags,
-                            struct sockaddr *addr, int *addrlen)
-{
-    int ret;
-    ret = recvfrom(sockfd, buf, len, flags, addr, addrlen);
-    if (ret < 0) {
-        errno = socket_error();
-    }
-    return ret;
-}
-#endif /* WIN32 */
-
-void slirp_pstrcpy(char *buf, int buf_size, const char *str)
-{
-    int c;
-    char *q = buf;
-
-    if (buf_size <= 0)
-        return;
-
-    for(;;) {
-        c = *str++;
-        if (c == 0 || q >= buf + buf_size - 1)
-            break;
-        *q++ = c;
-    }
-    *q = '\0';
-}
diff --git a/slirp/util.h b/slirp/util.h
deleted file mode 100644 (file)
index c4207a4..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (c) 2003-2008 Fabrice Bellard
- * Copyright (c) 2010-2019 Red Hat, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#ifndef UTIL_H_
-#define UTIL_H_
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <inttypes.h>
-
-#ifdef _WIN32
-#include <winsock2.h>
-#include <windows.h>
-#else
-#include <sys/socket.h>
-#include <netinet/tcp.h>
-#include <netinet/in.h>
-#endif
-
-#if defined(_WIN32)
-# define SLIRP_PACKED __attribute__((gcc_struct, packed))
-#else
-# define SLIRP_PACKED __attribute__((packed))
-#endif
-
-#ifndef DIV_ROUND_UP
-#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
-#endif
-
-#ifndef container_of
-#define container_of(ptr, type, member) __extension__ ({    \
-    void *__mptr = (void *)(ptr);               \
-    ((type *)(__mptr - offsetof(type, member))); })
-#endif
-
-#if defined(_WIN32) /* CONFIG_IOVEC */
-# if !defined(IOV_MAX) /* XXX: to avoid duplicate with QEMU osdep.h */
-struct iovec {
-    void *iov_base;
-    size_t iov_len;
-};
-# endif
-#else
-#include <sys/uio.h>
-#endif
-
-#define SCALE_MS 1000000
-
-#define ETH_ALEN    6
-#define ETH_HLEN    14
-#define ETH_P_IP                  (0x0800)      /* Internet Protocol packet  */
-#define ETH_P_ARP                 (0x0806)      /* Address Resolution packet */
-#define ETH_P_IPV6                (0x86dd)
-#define ETH_P_VLAN                (0x8100)
-#define ETH_P_DVLAN               (0x88a8)
-#define ETH_P_NCSI                (0x88f8)
-#define ETH_P_UNKNOWN             (0xffff)
-
-/* FIXME: remove me when made standalone */
-#ifdef _WIN32
-#undef accept
-#undef bind
-#undef closesocket
-#undef connect
-#undef getpeername
-#undef getsockname
-#undef getsockopt
-#undef ioctlsocket
-#undef listen
-#undef recv
-#undef recvfrom
-#undef send
-#undef sendto
-#undef setsockopt
-#undef shutdown
-#undef socket
-#endif
-
-#ifdef _WIN32
-#define connect slirp_connect_wrap
-int slirp_connect_wrap(int fd, const struct sockaddr *addr, int addrlen);
-#define listen slirp_listen_wrap
-int slirp_listen_wrap(int fd, int backlog);
-#define bind slirp_bind_wrap
-int slirp_bind_wrap(int fd, const struct sockaddr *addr, int addrlen);
-#define socket slirp_socket_wrap
-int slirp_socket_wrap(int domain, int type, int protocol);
-#define accept slirp_accept_wrap
-int slirp_accept_wrap(int fd, struct sockaddr *addr, int *addrlen);
-#define shutdown slirp_shutdown_wrap
-int slirp_shutdown_wrap(int fd, int how);
-#define getpeername slirp_getpeername_wrap
-int slirp_getpeername_wrap(int fd, struct sockaddr *addr, int *addrlen);
-#define getsockname slirp_getsockname_wrap
-int slirp_getsockname_wrap(int fd, struct sockaddr *addr, int *addrlen);
-#define send slirp_send_wrap
-ssize_t slirp_send_wrap(int fd, const void *buf, size_t len, int flags);
-#define sendto slirp_sendto_wrap
-ssize_t slirp_sendto_wrap(int fd, const void *buf, size_t len, int flags,
-                          const struct sockaddr *dest_addr, int addrlen);
-#define recv slirp_recv_wrap
-ssize_t slirp_recv_wrap(int fd, void *buf, size_t len, int flags);
-#define recvfrom slirp_recvfrom_wrap
-ssize_t slirp_recvfrom_wrap(int fd, void *buf, size_t len, int flags,
-                            struct sockaddr *src_addr, int *addrlen);
-#define closesocket slirp_closesocket_wrap
-int slirp_closesocket_wrap(int fd);
-#define ioctlsocket slirp_ioctlsocket_wrap
-int slirp_ioctlsocket_wrap(int fd, int req, void *val);
-#define getsockopt slirp_getsockopt_wrap
-int slirp_getsockopt_wrap(int sockfd, int level, int optname,
-                     void *optval, int *optlen);
-#define setsockopt slirp_setsockopt_wrap
-int slirp_setsockopt_wrap(int sockfd, int level, int optname,
-                          const void *optval, int optlen);
-
-int inet_aton(const char *cp, struct in_addr *ia);
-#else
-#define closesocket(s) close(s)
-#define ioctlsocket(s, r, v) ioctl(s, r, v)
-#endif
-
-int slirp_socket(int domain, int type, int protocol);
-void slirp_set_nonblock(int fd);
-
-static inline int slirp_socket_set_nodelay(int fd)
-{
-    int v = 1;
-    return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
-}
-
-static inline int slirp_socket_set_fast_reuse(int fd)
-{
-#ifndef _WIN32
-    int v = 1;
-    return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v));
-#else
-    /* Enabling the reuse of an endpoint that was used by a socket still in
-     * TIME_WAIT state is usually performed by setting SO_REUSEADDR. On Windows
-     * fast reuse is the default and SO_REUSEADDR does strange things. So we
-     * don't have to do anything here. More info can be found at:
-     * http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621.aspx */
-    return 0;
-#endif
-}
-
-void slirp_pstrcpy(char *buf, int buf_size, const char *str);
-
-#endif
index 1e54fd59329895ef41ccdc02765b3bab6cd43adf..a66ec72daa06c06e3d853e6f4160ae199b99fbbe 100644 (file)
 
 import os
 import sys
+import uuid
 
 import avocado
 
-SRC_ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
-SRC_ROOT_DIR = os.path.abspath(os.path.dirname(SRC_ROOT_DIR))
-sys.path.append(os.path.join(SRC_ROOT_DIR, 'scripts'))
+SRC_ROOT_DIR = os.path.join(os.path.dirname(__file__), '..', '..', '..')
+sys.path.append(os.path.join(SRC_ROOT_DIR, 'python'))
 
 from qemu import QEMUMachine
 
@@ -42,13 +42,29 @@ def pick_default_qemu_bin():
 
 class Test(avocado.Test):
     def setUp(self):
-        self.vm = None
+        self._vms = {}
         self.qemu_bin = self.params.get('qemu_bin',
                                         default=pick_default_qemu_bin())
         if self.qemu_bin is None:
             self.cancel("No QEMU binary defined or found in the source tree")
-        self.vm = QEMUMachine(self.qemu_bin)
+
+    def _new_vm(self, *args):
+        vm = QEMUMachine(self.qemu_bin)
+        if args:
+            vm.add_args(*args)
+        return vm
+
+    @property
+    def vm(self):
+        return self.get_vm(name='default')
+
+    def get_vm(self, *args, name=None):
+        if not name:
+            name = str(uuid.uuid4())
+        if self._vms.get(name) is None:
+            self._vms[name] = self._new_vm(*args)
+        return self._vms[name]
 
     def tearDown(self):
-        if self.vm is not None:
-            self.vm.shutdown()
+        for vm in self._vms.values():
+            vm.shutdown()
index 98324f7591299b439f7a5a931305a2c4d4228232..beeb1e59e8e20441e262d66c916686f4c6f68cbd 100644 (file)
@@ -18,7 +18,6 @@ class BootLinuxConsole(Test):
     Boots a x86_64 Linux kernel and checks that the console is operational
     and the kernel command line is properly passed from QEMU to the kernel
 
-    :avocado: enable
     :avocado: tags=x86_64
     """
 
index 737355c2ef028350fb7d7926c569446cb633b637..fbdb48e43fbd909defe41c2e8c6d8fdc8414d693 100644 (file)
@@ -8,6 +8,7 @@
 # This work is licensed under the terms of the GNU GPL, version 2 or
 # later.  See the COPYING file in the top-level directory.
 
+import logging
 import tempfile
 from avocado.utils.process import run
 
@@ -18,20 +19,21 @@ class LinuxInitrd(Test):
     """
     Checks QEMU evaluates correctly the initrd file passed as -initrd option.
 
-    :avocado: enable
     :avocado: tags=x86_64
     """
 
-    timeout = 60
+    timeout = 300
 
-    def test_with_2gib_file_should_exit_error_msg(self):
+    def test_with_2gib_file_should_exit_error_msg_with_linux_v3_6(self):
         """
         Pretends to boot QEMU with an initrd file with size of 2GiB
         and expect it exits with error message.
+        Fedora-18 shipped with linux-3.6 which have not supported xloadflags
+        cannot support more than 2GiB initrd.
         """
-        kernel_url = ('https://mirrors.kernel.org/fedora/releases/28/'
-                      'Everything/x86_64/os/images/pxeboot/vmlinuz')
-        kernel_hash = '238e083e114c48200f80d889f7e32eeb2793e02a'
+        kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora/li'
+                      'nux/releases/18/Fedora/x86_64/os/images/pxeboot/vmlinuz')
+        kernel_hash = '41464f68efe42b9991250bed86c7081d2ccdbb21'
         kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
         max_size = 2 * (1024 ** 3) - 1
 
@@ -39,10 +41,44 @@ class LinuxInitrd(Test):
             initrd.seek(max_size)
             initrd.write(b'\0')
             initrd.flush()
-            cmd = "%s -kernel %s -initrd %s" % (self.qemu_bin, kernel_path,
-                                                initrd.name)
+            cmd = "%s -kernel %s -initrd %s -m 4096" % (
+                  self.qemu_bin, kernel_path, initrd.name)
             res = run(cmd, ignore_status=True)
             self.assertEqual(res.exit_status, 1)
             expected_msg = r'.*initrd is too large.*max: \d+, need %s.*' % (
                 max_size + 1)
             self.assertRegex(res.stderr_text, expected_msg)
+
+    def test_with_2gib_file_should_work_with_linux_v4_16(self):
+        """
+        QEMU has supported up to 4 GiB initrd for recent kernel
+        Expect guest can reach 'Unpacking initramfs...'
+        """
+        kernel_url = ('https://mirrors.kernel.org/fedora/releases/28/'
+                      'Everything/x86_64/os/images/pxeboot/vmlinuz')
+        kernel_hash = '238e083e114c48200f80d889f7e32eeb2793e02a'
+        kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+        max_size = 2 * (1024 ** 3) + 1
+
+        with tempfile.NamedTemporaryFile() as initrd:
+            initrd.seek(max_size)
+            initrd.write(b'\0')
+            initrd.flush()
+
+            self.vm.set_machine('pc')
+            self.vm.set_console()
+            kernel_command_line = 'console=ttyS0'
+            self.vm.add_args('-kernel', kernel_path,
+                             '-append', kernel_command_line,
+                             '-initrd', initrd.name,
+                             '-m', '5120')
+            self.vm.launch()
+            console = self.vm.console_socket.makefile()
+            console_logger = logging.getLogger('console')
+            while True:
+                msg = console.readline()
+                console_logger.debug(msg.strip())
+                if 'Unpacking initramfs...' in msg:
+                    break
+                if 'Kernel panic - not syncing' in msg:
+                    self.fail("Kernel panic reached")
diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py
new file mode 100644 (file)
index 0000000..6115cf6
--- /dev/null
@@ -0,0 +1,53 @@
+# Migration test
+#
+# Copyright (c) 2019 Red Hat, Inc.
+#
+# Authors:
+#  Cleber Rosa <crosa@redhat.com>
+#  Caio Carrara <ccarrara@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later.  See the COPYING file in the top-level directory.
+
+
+from avocado_qemu import Test
+
+from avocado.utils import network
+from avocado.utils import wait
+
+
+class Migration(Test):
+    """
+    :avocado: enable
+    """
+
+    timeout = 10
+
+    @staticmethod
+    def migration_finished(vm):
+        return vm.command('query-migrate')['status'] in ('completed', 'failed')
+
+    def _get_free_port(self):
+        port = network.find_free_port()
+        if port is None:
+            self.cancel('Failed to find a free port')
+        return port
+
+
+    def test_migration_with_tcp_localhost(self):
+        source_vm = self.get_vm()
+        dest_uri = 'tcp:localhost:%u' % self._get_free_port()
+        dest_vm = self.get_vm('-incoming', dest_uri)
+        dest_vm.launch()
+        source_vm.launch()
+        source_vm.qmp('migrate', uri=dest_uri)
+        wait.wait_for(
+            self.migration_finished,
+            timeout=self.timeout,
+            step=0.1,
+            args=(source_vm,)
+        )
+        self.assertEqual(dest_vm.command('query-migrate')['status'], 'completed')
+        self.assertEqual(source_vm.command('query-migrate')['status'], 'completed')
+        self.assertEqual(dest_vm.command('query-status')['status'], 'running')
+        self.assertEqual(source_vm.command('query-status')['status'], 'postmigrate')
index 13b0a7440dfb70c467601b90639b63d6854bc91c..67c2192c9320aba1f0b4001436b24e1cb47c9c1e 100644 (file)
@@ -14,7 +14,6 @@ from avocado_qemu import Test
 
 class Version(Test):
     """
-    :avocado: enable
     :avocado: tags=quick
     """
     def test_qmp_human_info_version(self):
index ce990250d828e0851d8af841bac6813d15f99fc1..37fc01ea187c708b8126d6c78edb05295bf9998f 100644 (file)
@@ -11,7 +11,7 @@ Check compatibility of virtio device types
 import sys
 import os
 
-sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "scripts"))
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
 from qemu import QEMUMachine
 from avocado_qemu import Test
 
@@ -61,7 +61,6 @@ class VirtioVersionCheck(Test):
     same device tree created by `disable-modern` and
     `disable-legacy`.
 
-    :avocado: enable
     :avocado: tags=x86_64
     """
 
index b1ef9d71b17ed3f18579e589d727464d4a4cffcd..064ceabcc1e2ba84bd7d1f83e6c28b72a99273cd 100644 (file)
@@ -13,7 +13,6 @@ from avocado_qemu import Test
 
 class Vnc(Test):
     """
-    :avocado: enable
     :avocado: tags=vnc,quick
     """
     def test_no_vnc(self):
index 398e3f27066551bc231276eb6c38dc23390c3abb..0e304660b864057adac92e9ae1d07a330850a13e 100644 (file)
@@ -24,13 +24,14 @@ import re
 import sys
 import time
 
-sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'scripts'))
-import qemu
-import qmp.qmp
 from guestperf.progress import Progress, ProgressStats
 from guestperf.report import Report
 from guestperf.timings import TimingRecord, Timings
 
+sys.path.append(os.path.join(os.path.dirname(__file__),
+                             '..', '..', '..', 'python'))
+import qemu
+
 
 class Engine(object):
 
index d6edd97ab4f47a4711e22e211fd87cc962aca94c..75c203b30c7dfe07e8a8e473db6faddced3ce547 100755 (executable)
@@ -23,7 +23,7 @@ import os
 import iotests
 from iotests import qemu_img_create, qemu_io, file_path, log
 
-sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts'))
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
 
 from qemu import QEMUMachine
 
index f81ee1112f7a08dfb5550150bc2a5489f04d77e2..688abc9acb44ba267f30399e6541d91adf7cd3c9 100755 (executable)
@@ -23,7 +23,7 @@ import os
 import iotests
 from iotests import log
 
-sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts'))
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
 
 from qemu import QEMUMachine
 
index 4910fb200517a7115919efd6d9284d2ac4013bd1..3d15571688e0916830ae9fcb1217df461fe6bec3 100644 (file)
@@ -32,8 +32,8 @@ import atexit
 import io
 from collections import OrderedDict
 
-sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts'))
-import qtest
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu import qtest
 
 
 # This will not work if arguments contain spaces but is necessary if we
index 64c6e27a9408a3d3d77daacafb686d92b5fc0cbd..002ded6a22571d249c660d63d8f971cec8dbb251 100644 (file)
@@ -1,4 +1,4 @@
 # Add Python module requirements, one per line, to be installed
 # in the tests/venv Python virtual environment. For more info,
 # refer to: https://pip.pypa.io/en/stable/user_guide/#id1
-avocado-framework==65.0
+avocado-framework==68.0
index bdca6cb2fc5677cea3c37cd9f2ec30a07f17d178..0556bdcf9e9ffb12cdcf59ff968cee14906d84a3 100755 (executable)
@@ -17,7 +17,7 @@ import sys
 import logging
 import time
 import datetime
-sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "scripts"))
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
 from qemu import QEMUMachine, kvm_available
 import subprocess
 import hashlib
index 0808575e3ed2ca6920a434fff8def2658bd7919d..835fcd69e2c97564eaced8642cdb117a7bdb225b 100644 (file)
@@ -3,6 +3,7 @@ util-obj-y += bufferiszero.o
 util-obj-y += lockcnt.o
 util-obj-y += aiocb.o async.o aio-wait.o thread-pool.o qemu-timer.o
 util-obj-y += main-loop.o iohandler.o
+main-loop.o-cflags := $(SLIRP_CFLAGS)
 util-obj-$(call lnot,$(CONFIG_ATOMIC64)) += atomic64.o
 util-obj-$(CONFIG_POSIX) += aio-posix.o
 util-obj-$(CONFIG_POSIX) += compatfd.o
index d4a521caeb201e33c68c7f17a73d86d3fe1bf06d..e1e349ca5c4c232b50c891fa10d1c80077f72a6e 100644 (file)
 #include "qapi/error.h"
 #include "qemu/cutils.h"
 #include "qemu/timer.h"
-#include "qemu/sockets.h"      // struct in_addr needed for libslirp.h
 #include "sysemu/qtest.h"
 #include "sysemu/cpus.h"
 #include "sysemu/replay.h"
-#include "slirp/libslirp.h"
 #include "qemu/main-loop.h"
 #include "block/aio.h"
 #include "qemu/error-report.h"
diff --git a/vl.c b/vl.c
index 4c5cc0d8ad91fd6bc665d32afc9312edf7ab6129..4a350de5cd19a9ae0018774dd9af58f6c604c875 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -106,9 +106,6 @@ int main(int argc, char **argv)
 
 #include "disas/disas.h"
 
-
-#include "slirp/libslirp.h"
-
 #include "trace-root.h"
 #include "trace/control.h"
 #include "qemu/queue.h"