summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReinhard Tartler <siretart@tauware.de>2019-08-14 07:25:13 -0400
committerReinhard Tartler <siretart@tauware.de>2019-08-14 07:25:13 -0400
commit4e0d4a48ac2f323abc1e01520582c39ff1e98f8f (patch)
treedd298a3a2a1c77e239e701140702fb03fe6f94d5
parentc8b43eee2d4982826d293781d37aebd5a385c8de (diff)
New upstream version 0.3.2
-rw-r--r--Makefile.am141
-rw-r--r--README.md3
-rw-r--r--api.c4
-rw-r--r--configure.ac2
-rw-r--r--parson/README.md3
-rw-r--r--qemu/COPYING339
-rw-r--r--qemu/COPYING.LIB502
-rw-r--r--qemu/LICENSE21
-rw-r--r--qemu/README.md13
-rw-r--r--qemu/slirp/src/bootp.h129
-rw-r--r--qemu/slirp/src/debug.h46
-rw-r--r--qemu/slirp/src/if.c218
-rw-r--r--qemu/slirp/src/ip.h242
-rw-r--r--qemu/slirp/src/ip6.h160
-rw-r--r--qemu/slirp/src/ip6_icmp.h232
-rw-r--r--qemu/slirp/src/ip_icmp.c474
-rw-r--r--qemu/slirp/src/ip_icmp.h166
-rw-r--r--qemu/slirp/src/ip_input.c469
-rw-r--r--qemu/slirp/src/ip_output.c170
-rw-r--r--qemu/slirp/src/mbuf.c235
-rw-r--r--qemu/slirp/src/ncsi-pkt.h445
-rw-r--r--qemu/slirp/src/qtailq.h194
-rw-r--r--qemu/slirp/src/sbuf.c186
-rw-r--r--qemu/slirp/src/socket.c952
-rw-r--r--qemu/slirp/src/socket.h160
-rw-r--r--qemu/slirp/src/tcp_input.c1554
-rw-r--r--qemu/slirp/src/tcp_output.c522
-rw-r--r--qemu/slirp/src/tcp_subr.c989
-rw-r--r--qemu/slirp/src/tcp_timer.c294
-rw-r--r--qemu/slirp/src/tcp_var.h162
-rw-r--r--qemu/slirp/src/tftp.c463
-rw-r--r--qemu/slirp/src/udp.c363
-rw-r--r--qemu_patches/0001-slirp-add-slirp_initx-SlirpConfig-SlirpCb-void.patch179
-rw-r--r--qemu_patches/0002-slirp-allow-custom-MTU.patch292
-rw-r--r--qemu_patches/0003-slirp-add-disable_host_loopback-prohibit-connections.patch209
-rw-r--r--qemu_patches/README.md30
-rwxr-xr-xqemu_patches/sync.sh50
-rw-r--r--slirp4netns.c5
-rw-r--r--vendor.md27
-rwxr-xr-xvendor.sh74
-rw-r--r--vendor/README.md9
-rw-r--r--vendor/libslirp/.clang-format58
-rw-r--r--vendor/libslirp/COPYRIGHT (renamed from qemu/slirp/COPYRIGHT)0
-rw-r--r--vendor/libslirp/README.md60
-rw-r--r--vendor/libslirp/src/arp_table.c (renamed from qemu/slirp/src/arp_table.c)13
-rw-r--r--vendor/libslirp/src/bootp.c (renamed from qemu/slirp/src/bootp.c)31
-rw-r--r--vendor/libslirp/src/bootp.h129
-rw-r--r--vendor/libslirp/src/cksum.c (renamed from qemu/slirp/src/cksum.c)194
-rw-r--r--vendor/libslirp/src/debug.h51
-rw-r--r--vendor/libslirp/src/dhcpv6.c (renamed from qemu/slirp/src/dhcpv6.c)47
-rw-r--r--vendor/libslirp/src/dhcpv6.h (renamed from qemu/slirp/src/dhcpv6.h)29
-rw-r--r--vendor/libslirp/src/dnssearch.c (renamed from qemu/slirp/src/dnssearch.c)14
-rw-r--r--vendor/libslirp/src/if.c213
-rw-r--r--vendor/libslirp/src/if.h (renamed from qemu/slirp/src/if.h)12
-rw-r--r--vendor/libslirp/src/ip.h242
-rw-r--r--vendor/libslirp/src/ip6.h214
-rw-r--r--vendor/libslirp/src/ip6_icmp.c (renamed from qemu/slirp/src/ip6_icmp.c)60
-rw-r--r--vendor/libslirp/src/ip6_icmp.h219
-rw-r--r--vendor/libslirp/src/ip6_input.c (renamed from qemu/slirp/src/ip6_input.c)0
-rw-r--r--vendor/libslirp/src/ip6_output.c (renamed from qemu/slirp/src/ip6_output.c)0
-rw-r--r--vendor/libslirp/src/ip_icmp.c482
-rw-r--r--vendor/libslirp/src/ip_icmp.h166
-rw-r--r--vendor/libslirp/src/ip_input.c461
-rw-r--r--vendor/libslirp/src/ip_output.c169
-rw-r--r--vendor/libslirp/src/libslirp-version.h23
-rw-r--r--vendor/libslirp/src/libslirp.h (renamed from qemu/slirp/src/libslirp.h)62
-rw-r--r--vendor/libslirp/src/main.h (renamed from qemu/slirp/src/main.h)0
-rw-r--r--vendor/libslirp/src/mbuf.c224
-rw-r--r--vendor/libslirp/src/mbuf.h (renamed from qemu/slirp/src/mbuf.h)58
-rw-r--r--vendor/libslirp/src/misc.c (renamed from qemu/slirp/src/misc.c)141
-rw-r--r--vendor/libslirp/src/misc.h (renamed from qemu/slirp/src/misc.h)25
-rw-r--r--vendor/libslirp/src/ncsi-pkt.h445
-rw-r--r--vendor/libslirp/src/ncsi.c (renamed from qemu/slirp/src/ncsi.c)102
-rw-r--r--vendor/libslirp/src/ndp_table.c (renamed from qemu/slirp/src/ndp_table.c)16
-rw-r--r--vendor/libslirp/src/sbuf.c186
-rw-r--r--vendor/libslirp/src/sbuf.h (renamed from qemu/slirp/src/sbuf.h)14
-rw-r--r--vendor/libslirp/src/slirp.c (renamed from qemu/slirp/src/slirp.c)184
-rw-r--r--vendor/libslirp/src/slirp.h (renamed from qemu/slirp/src/slirp.h)76
-rw-r--r--vendor/libslirp/src/socket.c945
-rw-r--r--vendor/libslirp/src/socket.h164
-rw-r--r--vendor/libslirp/src/state.c (renamed from qemu/slirp/src/state.c)235
-rw-r--r--vendor/libslirp/src/stream.c (renamed from qemu/slirp/src/stream.c)2
-rw-r--r--vendor/libslirp/src/stream.h (renamed from qemu/slirp/src/stream.h)0
-rw-r--r--vendor/libslirp/src/tcp.h (renamed from qemu/slirp/src/tcp.h)124
-rw-r--r--vendor/libslirp/src/tcp_input.c1542
-rw-r--r--vendor/libslirp/src/tcp_output.c516
-rw-r--r--vendor/libslirp/src/tcp_subr.c971
-rw-r--r--vendor/libslirp/src/tcp_timer.c286
-rw-r--r--vendor/libslirp/src/tcp_timer.h (renamed from qemu/slirp/src/tcp_timer.h)54
-rw-r--r--vendor/libslirp/src/tcp_var.h161
-rw-r--r--vendor/libslirp/src/tcpip.h (renamed from qemu/slirp/src/tcpip.h)76
-rw-r--r--vendor/libslirp/src/tftp.c462
-rw-r--r--vendor/libslirp/src/tftp.h (renamed from qemu/slirp/src/tftp.h)40
-rw-r--r--vendor/libslirp/src/udp.c355
-rw-r--r--vendor/libslirp/src/udp.h (renamed from qemu/slirp/src/udp.h)48
-rw-r--r--vendor/libslirp/src/udp6.c (renamed from qemu/slirp/src/udp6.c)8
-rw-r--r--vendor/libslirp/src/util.c (renamed from qemu/slirp/src/util.c)18
-rw-r--r--vendor/libslirp/src/util.h (renamed from qemu/slirp/src/util.h)45
-rw-r--r--vendor/libslirp/src/version.c11
-rw-r--r--vendor/libslirp/src/vmstate.c (renamed from qemu/slirp/src/vmstate.c)96
-rw-r--r--vendor/libslirp/src/vmstate.h (renamed from qemu/slirp/src/vmstate.h)268
-rw-r--r--vendor/parson/LICENSE (renamed from parson/LICENSE)2
-rw-r--r--vendor/parson/README.md149
-rw-r--r--vendor/parson/parson.c (renamed from parson/parson.c)18
-rw-r--r--vendor/parson/parson.h (renamed from parson/parson.h)8
105 files changed, 10162 insertions, 11590 deletions
diff --git a/Makefile.am b/Makefile.am
index 6a4ae11..2430c54 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,7 @@ bin_PROGRAMS = slirp4netns
AM_CFLAGS = @GLIB_CFLAGS@
-noinst_LIBRARIES = libqemu_slirp.a libparson.a
+noinst_LIBRARIES = libslirp.a libparson.a
AM_TESTS_ENVIRONMENT = PATH="$(abs_top_builddir):$(PATH)"
TESTS = tests/test-slirp4netns.sh tests/test-slirp4netns-configure.sh tests/test-slirp4netns-exit-fd.sh tests/test-slirp4netns-ready-fd.sh tests/test-slirp4netns-api-socket.sh tests/test-slirp4netns-disable-host-loopback.sh tests/test-slirp4netns-cidr.sh
@@ -14,80 +14,85 @@ EXTRA_DIST = \
tests/common.sh \
slirp4netns.h \
api.h \
- qemu/slirp/src/bootp.h \
- qemu/slirp/src/debug.h \
- qemu/slirp/src/dhcpv6.h \
- qemu/slirp/src/if.h \
- qemu/slirp/src/ip6.h \
- qemu/slirp/src/ip6_icmp.h \
- qemu/slirp/src/ip.h \
- qemu/slirp/src/ip_icmp.h \
- qemu/slirp/src/libslirp.h \
- qemu/slirp/src/main.h \
- qemu/slirp/src/mbuf.h \
- qemu/slirp/src/misc.h \
- qemu/slirp/src/ncsi-pkt.h \
- qemu/slirp/src/qtailq.h \
- qemu/slirp/src/sbuf.h \
- qemu/slirp/src/slirp.h \
- qemu/slirp/src/socket.h \
- qemu/slirp/src/stream.h \
- qemu/slirp/src/tftp.h \
- qemu/slirp/src/tcp.h \
- qemu/slirp/src/tcpip.h \
- qemu/slirp/src/tcp_timer.h \
- qemu/slirp/src/tcp_var.h \
- qemu/slirp/src/udp.h \
- qemu/slirp/src/util.h \
- qemu/slirp/src/vmstate.h \
- parson/parson.h
-
-libqemu_slirp_a_SOURCES = \
- qemu/slirp/src/arp_table.c \
- qemu/slirp/src/bootp.c \
- qemu/slirp/src/cksum.c \
- qemu/slirp/src/dhcpv6.c \
- qemu/slirp/src/dnssearch.c \
- qemu/slirp/src/if.c \
- qemu/slirp/src/ip6_icmp.c \
- qemu/slirp/src/ip6_input.c \
- qemu/slirp/src/ip6_output.c \
- qemu/slirp/src/ip_icmp.c \
- qemu/slirp/src/ip_input.c \
- qemu/slirp/src/ip_output.c \
- qemu/slirp/src/mbuf.c \
- qemu/slirp/src/misc.c \
- qemu/slirp/src/ncsi.c \
- qemu/slirp/src/ndp_table.c \
- qemu/slirp/src/sbuf.c \
- qemu/slirp/src/slirp.c \
- qemu/slirp/src/socket.c \
- qemu/slirp/src/state.c \
- qemu/slirp/src/stream.c \
- qemu/slirp/src/tcp_input.c \
- qemu/slirp/src/tcp_output.c \
- qemu/slirp/src/tcp_subr.c \
- qemu/slirp/src/tcp_timer.c \
- qemu/slirp/src/tftp.c \
- qemu/slirp/src/udp6.c \
- qemu/slirp/src/udp.c \
- qemu/slirp/src/util.c \
- qemu/slirp/src/vmstate.c
+ vendor/libslirp/COPYRIGHT \
+ vendor/libslirp/README.md \
+ vendor/libslirp/src/bootp.h \
+ vendor/libslirp/src/debug.h \
+ vendor/libslirp/src/dhcpv6.h \
+ vendor/libslirp/src/if.h \
+ vendor/libslirp/src/ip6.h \
+ vendor/libslirp/src/ip6_icmp.h \
+ vendor/libslirp/src/ip.h \
+ vendor/libslirp/src/ip_icmp.h \
+ vendor/libslirp/src/libslirp.h \
+ vendor/libslirp/src/libslirp-version.h \
+ vendor/libslirp/src/main.h \
+ vendor/libslirp/src/mbuf.h \
+ vendor/libslirp/src/misc.h \
+ vendor/libslirp/src/ncsi-pkt.h \
+ vendor/libslirp/src/sbuf.h \
+ vendor/libslirp/src/slirp.h \
+ vendor/libslirp/src/socket.h \
+ vendor/libslirp/src/stream.h \
+ vendor/libslirp/src/tftp.h \
+ vendor/libslirp/src/tcp.h \
+ vendor/libslirp/src/tcpip.h \
+ vendor/libslirp/src/tcp_timer.h \
+ vendor/libslirp/src/tcp_var.h \
+ vendor/libslirp/src/udp.h \
+ vendor/libslirp/src/util.h \
+ vendor/libslirp/src/vmstate.h \
+ vendor/parson/LICENSE \
+ vendor/parson/README.md \
+ vendor/parson/parson.h
+
+libslirp_a_SOURCES = \
+ vendor/libslirp/src/arp_table.c \
+ vendor/libslirp/src/bootp.c \
+ vendor/libslirp/src/cksum.c \
+ vendor/libslirp/src/dhcpv6.c \
+ vendor/libslirp/src/dnssearch.c \
+ vendor/libslirp/src/if.c \
+ vendor/libslirp/src/ip6_icmp.c \
+ vendor/libslirp/src/ip6_input.c \
+ vendor/libslirp/src/ip6_output.c \
+ vendor/libslirp/src/ip_icmp.c \
+ vendor/libslirp/src/ip_input.c \
+ vendor/libslirp/src/ip_output.c \
+ vendor/libslirp/src/mbuf.c \
+ vendor/libslirp/src/misc.c \
+ vendor/libslirp/src/ncsi.c \
+ vendor/libslirp/src/ndp_table.c \
+ vendor/libslirp/src/sbuf.c \
+ vendor/libslirp/src/slirp.c \
+ vendor/libslirp/src/socket.c \
+ vendor/libslirp/src/state.c \
+ vendor/libslirp/src/stream.c \
+ vendor/libslirp/src/tcp_input.c \
+ vendor/libslirp/src/tcp_output.c \
+ vendor/libslirp/src/tcp_subr.c \
+ vendor/libslirp/src/tcp_timer.c \
+ vendor/libslirp/src/tftp.c \
+ vendor/libslirp/src/udp6.c \
+ vendor/libslirp/src/udp.c \
+ vendor/libslirp/src/util.c \
+ vendor/libslirp/src/version.c \
+ vendor/libslirp/src/vmstate.c
# define specific commit if git available or it was replaced during git-archive creation
-COMMIT := $(shell V=93b55fa52a25ad507ae0346da98a5d8641f44310 ; \
+COMMIT := $(shell V=5e1639783df9bd7abbc46abc084a53c1093342d8 ; \
expr match "$$V" ormat: >/dev/null \
&& (cd "$$abs_srcdir" && [ -d .git ] && git describe --always --abbrev=0 --dirty --exclude=\* || echo unknown) \
|| echo "$$V" )
DEFINE_COMMIT = -DCOMMIT="\"$(COMMIT)\""
slirp4netns_CFLAGS = $(AM_CFLAGS) $(DEFINE_COMMIT)
-libqemu_slirp_a_CFLAGS = $(AM_CFLAGS) -I$(abs_top_builddir)/qemu/slirp/src
-libparson_a_CFLAGS = $(AM_CFLAGS) -I$(abs_top_builddir)/parson
-libparson_a_SOURCES = parson/parson.c
+libslirp_a_CFLAGS = $(AM_CFLAGS) -I$(abs_top_builddir)/vendor/libslirp/src
+libparson_a_CFLAGS = $(AM_CFLAGS) -I$(abs_top_builddir)/vendor/parson
+libparson_a_SOURCES = vendor/parson/parson.c
slirp4netns_SOURCES = main.c slirp4netns.c api.c
-slirp4netns_LDADD = libqemu_slirp.a libparson.a @GLIB_LIBS@ -lpthread
+slirp4netns_LDADD = libslirp.a libparson.a @GLIB_LIBS@ -lpthread
man1_MANS = slirp4netns.1
generate-man:
@@ -99,7 +104,7 @@ lint:
$(CLANGTIDY) $(slirp4netns_SOURCES) -- $(AM_CFLAGS)
lint-full:
- $(CLANGTIDY) $(slirp4netns_SOURCES) $(libqemu_slirp_a_SOURCES) $(libparson_a_SOURCES) -- $(AM_CFLAGS)
+ $(CLANGTIDY) $(slirp4netns_SOURCES) $(libslirp_a_SOURCES) $(libparson_a_SOURCES) -- $(AM_CFLAGS)
indent:
# indent(1): "You must use the ‘-T’ option to tell indent the name of all the typenames in your program that are defined by typedef."
@@ -120,8 +125,8 @@ benchmark:
ci:
$(MAKE) indent
test -z "$(git diff)"
-# TODO: make sure ./qemu is synced with ./qemu_patches/sync.sh
-# (hard to verify during `make`, because sync.sh removes ./qemu/slirp/src/.deps)
+# TODO: make sure ./vendor is synced with ./vendor.sh
+# (hard to verify during `make`, because sync.sh removes ./vendor/libslirp/src/.deps)
$(MAKE) lint
$(MAKE) -j $(shell nproc) distcheck || ( find . -name test-suite.log | xargs cat; exit 1 )
PATH=$(shell pwd):$$PATH $(MAKE) benchmark MTU=1500
diff --git a/README.md b/README.md
index 1ef8b3b..e943c42 100644
--- a/README.md
+++ b/README.md
@@ -172,5 +172,4 @@ The latest revision of slirp4netns is regularly benchmarked (`make benchmark`) o
## Acknowledgement
-* The files under [`qemu`](./qemu) directory were forked from [QEMU](https://github.com/qemu/qemu) with the patches under [`qemu_patches`](./qemu_patches) directory.
-* The files under [`parson`](./parson) directory were copied from [kgabis/parson](https://github.com/kgabis/parson/commit/0a1896939faff5f69e179637fc49f678ff0128ba) without any modification.
+See [`vendor/README.md`](./vendor/README.md).
diff --git a/api.c b/api.c
index 7468b78..fc034f7 100644
--- a/api.c
+++ b/api.c
@@ -4,8 +4,8 @@
#include <unistd.h>
#include <sys/un.h>
#include <glib.h>
-#include "parson/parson.h"
-#include "qemu/slirp/src/libslirp.h"
+#include "vendor/parson/parson.h"
+#include "vendor/libslirp/src/libslirp.h"
#include "api.h"
#include "slirp4netns.h"
diff --git a/configure.ac b/configure.ac
index a784454..8d0c609 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ([2.69])
-AC_INIT([slirp4netns], [0.3.1], [https://github.com/rootless-containers/slirp4netns/issues])
+AC_INIT([slirp4netns], [0.3.2], [https://github.com/rootless-containers/slirp4netns/issues])
AC_CONFIG_SRCDIR([main.c])
AC_CONFIG_HEADERS([config.h])
diff --git a/parson/README.md b/parson/README.md
deleted file mode 100644
index ac393e5..0000000
--- a/parson/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# slirp4netns/parson
-
-The files under this directory are copied from kgabis/parson: https://github.com/kgabis/parson/commit/0a1896939faff5f69e179637fc49f678ff0128ba without any modification.
diff --git a/qemu/COPYING b/qemu/COPYING
deleted file mode 100644
index 00ccfbb..0000000
--- a/qemu/COPYING
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/qemu/COPYING.LIB b/qemu/COPYING.LIB
deleted file mode 100644
index 4362b49..0000000
--- a/qemu/COPYING.LIB
+++ /dev/null
@@ -1,502 +0,0 @@
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the Lesser GPL. It also counts
- as the successor of the GNU Library Public License, version 2, hence
- the version number 2.1.]
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
- This license, the Lesser General Public License, applies to some
-specially designated software packages--typically libraries--of the
-Free Software Foundation and other authors who decide to use it. You
-can use it too, but we suggest you first think carefully about whether
-this license or the ordinary General Public License is the better
-strategy to use in any particular case, based on the explanations below.
-
- When we speak of free software, we are referring to freedom of use,
-not price. Our General Public Licenses are designed to make sure that
-you have the freedom to distribute copies of free software (and charge
-for this service if you wish); that you receive source code or can get
-it if you want it; that you can change the software and use pieces of
-it in new free programs; and that you are informed that you can do
-these things.
-
- To protect your rights, we need to make restrictions that forbid
-distributors to deny you these rights or to ask you to surrender these
-rights. These restrictions translate to certain responsibilities for
-you if you distribute copies of the library or if you modify it.
-
- For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you. You must make sure that they, too, receive or can get the source
-code. If you link other code with the library, you must provide
-complete object files to the recipients, so that they can relink them
-with the library after making changes to the library and recompiling
-it. And you must show them these terms so they know their rights.
-
- We protect your rights with a two-step method: (1) we copyright the
-library, and (2) we offer you this license, which gives you legal
-permission to copy, distribute and/or modify the library.
-
- To protect each distributor, we want to make it very clear that
-there is no warranty for the free library. Also, if the library is
-modified by someone else and passed on, the recipients should know
-that what they have is not the original version, so that the original
-author's reputation will not be affected by problems that might be
-introduced by others.
-
- Finally, software patents pose a constant threat to the existence of
-any free program. We wish to make sure that a company cannot
-effectively restrict the users of a free program by obtaining a
-restrictive license from a patent holder. Therefore, we insist that
-any patent license obtained for a version of the library must be
-consistent with the full freedom of use specified in this license.
-
- Most GNU software, including some libraries, is covered by the
-ordinary GNU General Public License. This license, the GNU Lesser
-General Public License, applies to certain designated libraries, and
-is quite different from the ordinary General Public License. We use
-this license for certain libraries in order to permit linking those
-libraries into non-free programs.
-
- When a program is linked with a library, whether statically or using
-a shared library, the combination of the two is legally speaking a
-combined work, a derivative of the original library. The ordinary
-General Public License therefore permits such linking only if the
-entire combination fits its criteria of freedom. The Lesser General
-Public License permits more lax criteria for linking other code with
-the library.
-
- We call this license the "Lesser" General Public License because it
-does Less to protect the user's freedom than the ordinary General
-Public License. It also provides other free software developers Less
-of an advantage over competing non-free programs. These disadvantages
-are the reason we use the ordinary General Public License for many
-libraries. However, the Lesser license provides advantages in certain
-special circumstances.
-
- For example, on rare occasions, there may be a special need to
-encourage the widest possible use of a certain library, so that it becomes
-a de-facto standard. To achieve this, non-free programs must be
-allowed to use the library. A more frequent case is that a free
-library does the same job as widely used non-free libraries. In this
-case, there is little to gain by limiting the free library to free
-software only, so we use the Lesser General Public License.
-
- In other cases, permission to use a particular library in non-free
-programs enables a greater number of people to use a large body of
-free software. For example, permission to use the GNU C Library in
-non-free programs enables many more people to use the whole GNU
-operating system, as well as its variant, the GNU/Linux operating
-system.
-
- Although the Lesser General Public License is Less protective of the
-users' freedom, it does ensure that the user of a program that is
-linked with the Library has the freedom and the wherewithal to run
-that program using a modified version of the Library.
-
- The precise terms and conditions for copying, distribution and
-modification follow. Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library". The
-former contains code derived from the library, whereas the latter must
-be combined with the library in order to run.
-
- GNU LESSER GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License Agreement applies to any software library or other
-program which contains a notice placed by the copyright holder or
-other authorized party saying it may be distributed under the terms of
-this Lesser General Public License (also called "this License").
-Each licensee is addressed as "you".
-
- A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
- The "Library", below, refers to any such software library or work
-which has been distributed under these terms. A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language. (Hereinafter, translation is
-included without limitation in the term "modification".)
-
- "Source code" for a work means the preferred form of the work for
-making modifications to it. For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
- Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it). Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
- 1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
- You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-
- 2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) The modified work must itself be a software library.
-
- b) You must cause the files modified to carry prominent notices
- stating that you changed the files and the date of any change.
-
- c) You must cause the whole of the work to be licensed at no
- charge to all third parties under the terms of this License.
-
- d) If a facility in the modified Library refers to a function or a
- table of data to be supplied by an application program that uses
- the facility, other than as an argument passed when the facility
- is invoked, then you must make a good faith effort to ensure that,
- in the event an application does not supply such function or
- table, the facility still operates, and performs whatever part of
- its purpose remains meaningful.
-
- (For example, a function in a library to compute square roots has
- a purpose that is entirely well-defined independent of the
- application. Therefore, Subsection 2d requires that any
- application-supplied function or table used by this function must
- be optional: if the application does not supply it, the square
- root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library. To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License. (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.) Do not make any other change in
-these notices.
-
- Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
- This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
- 4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
- If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library". Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
- However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library". The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
- When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library. The
-threshold for this to be true is not precisely defined by law.
-
- If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work. (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
- Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-
- 6. As an exception to the Sections above, you may also combine or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
- You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License. You must supply a copy of this License. If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License. Also, you must do one
-of these things:
-
- a) Accompany the work with the complete corresponding
- machine-readable source code for the Library including whatever
- changes were used in the work (which must be distributed under
- Sections 1 and 2 above); and, if the work is an executable linked
- with the Library, with the complete machine-readable "work that
- uses the Library", as object code and/or source code, so that the
- user can modify the Library and then relink to produce a modified
- executable containing the modified Library. (It is understood
- that the user who changes the contents of definitions files in the
- Library will not necessarily be able to recompile the application
- to use the modified definitions.)
-
- b) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (1) uses at run time a
- copy of the library already present on the user's computer system,
- rather than copying library functions into the executable, and (2)
- will operate properly with a modified version of the library, if
- the user installs one, as long as the modified version is
- interface-compatible with the version that the work was made with.
-
- c) Accompany the work with a written offer, valid for at
- least three years, to give the same user the materials
- specified in Subsection 6a, above, for a charge no more
- than the cost of performing this distribution.
-
- d) If distribution of the work is made by offering access to copy
- from a designated place, offer equivalent access to copy the above
- specified materials from the same place.
-
- e) Verify that the user has already received a copy of these
- materials or that you have already sent this user a copy.
-
- For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it. However, as a special exception,
-the materials to be distributed need not include anything that is
-normally distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
- It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system. Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-
- 7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
- a) Accompany the combined library with a copy of the same work
- based on the Library, uncombined with any other library
- facilities. This must be distributed under the terms of the
- Sections above.
-
- b) Give prominent notice with the combined library of the fact
- that part of it is a work based on the Library, and explaining
- where to find the accompanying uncombined form of the same work.
-
- 8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License. Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License. However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
- 9. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Library or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
- 10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties with
-this License.
-
- 11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all. For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded. In such case, this License incorporates the limitation as if
-written in the body of this License.
-
- 13. The Free Software Foundation may publish revised and/or new
-versions of the Lesser General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-
- 14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission. For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this. Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
- NO WARRANTY
-
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Libraries
-
- If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change. You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
- To apply these terms, attach the following notices to the library. It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
- <one line to give the library's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
- <signature of Ty Coon>, 1 April 1990
- Ty Coon, President of Vice
-
-That's all there is to it!
diff --git a/qemu/LICENSE b/qemu/LICENSE
deleted file mode 100644
index 0e0b4b9..0000000
--- a/qemu/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The following points clarify the QEMU license:
-
-1) QEMU as a whole is released under the GNU General Public License,
-version 2.
-
-2) Parts of QEMU have specific licenses which are compatible with the
-GNU General Public License, version 2. Hence each source file contains
-its own licensing information. Source files with no licensing information
-are released under the GNU General Public License, version 2 or (at your
-option) any later version.
-
-As of July 2013, contributions under version 2 of the GNU General Public
-License (and no later version) are only accepted for the following files
-or directories: bsd-user/, linux-user/, hw/vfio/, hw/xen/xen_pt*.
-
-3) The Tiny Code Generator (TCG) is released under the BSD license
- (see license headers in files).
-
-4) QEMU is a trademark of Fabrice Bellard.
-
-Fabrice Bellard and the QEMU team
diff --git a/qemu/README.md b/qemu/README.md
deleted file mode 100644
index 9592b5b..0000000
--- a/qemu/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# DO NOT EDIT MANUALLY
-
-This directory was synced from QEMU `49fc899f8d673dd9e73f3db0d9e9ea60b77c331b` (`https://github.com/qemu/qemu.git`),
-with the following patches (sha256sum):
-```
-11dd49c9d594c1f3194e2e04d4a03e39d52d2f1cfc1478621fe439792b0135b8 0001-slirp-add-slirp_initx-SlirpConfig-SlirpCb-void.patch
-5e884ab4a471c1360e24c364379f069ace17d34b7cec6df084f8221d5a6a585f 0002-slirp-allow-custom-MTU.patch
-ff5b0fc69291aa7fe23337044245a5709f13e843ade734bf63c77a533f663a0b 0003-slirp-add-disable_host_loopback-prohibit-connections.patch
-```
-
-Please do not edit the contents under this directory manually.
-
-See also [`../qemu_patches/README.md`](../qemu_patches/README.md).
diff --git a/qemu/slirp/src/bootp.h b/qemu/slirp/src/bootp.h
deleted file mode 100644
index d881ad6..0000000
--- a/qemu/slirp/src/bootp.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/* 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/qemu/slirp/src/debug.h b/qemu/slirp/src/debug.h
deleted file mode 100644
index c95fd8f..0000000
--- a/qemu/slirp/src/debug.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- */
-
-#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/qemu/slirp/src/if.c b/qemu/slirp/src/if.c
deleted file mode 100644
index 6eaac72..0000000
--- a/qemu/slirp/src/if.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- */
-
-#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/qemu/slirp/src/ip.h b/qemu/slirp/src/ip.h
deleted file mode 100644
index 1484de1..0000000
--- a/qemu/slirp/src/ip.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * 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/qemu/slirp/src/ip6.h b/qemu/slirp/src/ip6.h
deleted file mode 100644
index 33683c8..0000000
--- a/qemu/slirp/src/ip6.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * 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/qemu/slirp/src/ip6_icmp.h b/qemu/slirp/src/ip6_icmp.h
deleted file mode 100644
index d8d13e3..0000000
--- a/qemu/slirp/src/ip6_icmp.h
+++ /dev/null
@@ -1,232 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * 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/qemu/slirp/src/ip_icmp.c b/qemu/slirp/src/ip_icmp.c
deleted file mode 100644
index b0f116d..0000000
--- a/qemu/slirp/src/ip_icmp.c
+++ /dev/null
@@ -1,474 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * 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;
- if (sotranslate_out(so, &addr) < 0) {
- icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
- udp_detach(so);
- return;
- }
-
- 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/qemu/slirp/src/ip_icmp.h b/qemu/slirp/src/ip_icmp.h
deleted file mode 100644
index 05d85c5..0000000
--- a/qemu/slirp/src/ip_icmp.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * 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/qemu/slirp/src/ip_input.c b/qemu/slirp/src/ip_input.c
deleted file mode 100644
index a714fec..0000000
--- a/qemu/slirp/src/ip_input.c
+++ /dev/null
@@ -1,469 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * 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.
- */
-
-#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/qemu/slirp/src/ip_output.c b/qemu/slirp/src/ip_output.c
deleted file mode 100644
index cd2ea7c..0000000
--- a/qemu/slirp/src/ip_output.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * 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.
- */
-
-#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 <= slirp->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 = (slirp->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/qemu/slirp/src/mbuf.c b/qemu/slirp/src/mbuf.c
deleted file mode 100644
index b1ac229..0000000
--- a/qemu/slirp/src/mbuf.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Copyright (c) 1995 Danny Gasparovski
- */
-
-/*
- * 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(mtu)\
- (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + (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->if_mtu));
- 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(slirp->if_mtu) - 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/qemu/slirp/src/ncsi-pkt.h b/qemu/slirp/src/ncsi-pkt.h
deleted file mode 100644
index 4c0be39..0000000
--- a/qemu/slirp/src/ncsi-pkt.h
+++ /dev/null
@@ -1,445 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Copyright Gavin Shan, IBM Corporation 2016.
- *
- * 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 copyright holder 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 COPYRIGHT HOLDERS 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
- * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef 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/qemu/slirp/src/qtailq.h b/qemu/slirp/src/qtailq.h
deleted file mode 100644
index d8aa0e1..0000000
--- a/qemu/slirp/src/qtailq.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/* $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/qemu/slirp/src/sbuf.c b/qemu/slirp/src/sbuf.c
deleted file mode 100644
index 9c0b31b..0000000
--- a/qemu/slirp/src/sbuf.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- */
-
-#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/qemu/slirp/src/socket.c b/qemu/slirp/src/socket.c
deleted file mode 100644
index be27e52..0000000
--- a/qemu/slirp/src/socket.c
+++ /dev/null
@@ -1,952 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- */
-
-#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)");
- if (sotranslate_out(so, &addr) < 0) {
- return -1;
- }
-
- /* 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
- */
-int sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
-{
- int rc = 0;
- 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) {
- goto ret;
- }
- }
- if (slirp->disable_host_loopback) {
- rc = -1;
- errno = EPERM;
- goto ret;
- } else {
- sin->sin_addr = loopback_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;
- goto ret;
- }
- }
- if (slirp->disable_host_loopback){
- rc = -1;
- errno = EPERM;
- goto ret;
- } else {
- sin6->sin6_addr = in6addr_loopback;
- }
- }
- break;
-
- default:
- break;
- }
-ret:
- return rc;
-}
-
-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/qemu/slirp/src/socket.h b/qemu/slirp/src/socket.h
deleted file mode 100644
index 791ae94..0000000
--- a/qemu/slirp/src/socket.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- */
-
-#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);
-
-int 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/qemu/slirp/src/tcp_input.c b/qemu/slirp/src/tcp_input.c
deleted file mode 100644
index 14a489e..0000000
--- a/qemu/slirp/src/tcp_input.c
+++ /dev/null
@@ -1,1554 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * 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.
- */
-
-#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(so->slirp->if_mtu, so->slirp->if_mru) - sizeof(struct tcphdr)
- - sizeof(struct ip);
- break;
- case AF_INET6:
- mss = MIN(so->slirp->if_mtu, so->slirp->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 = MIN(mss, TCP_MAXSEG_MAX);
-
- 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/qemu/slirp/src/tcp_output.c b/qemu/slirp/src/tcp_output.c
deleted file mode 100644
index 6bbaf6c..0000000
--- a/qemu/slirp/src/tcp_output.c
+++ /dev/null
@@ -1,522 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * 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.
- */
-
-#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/qemu/slirp/src/tcp_subr.c b/qemu/slirp/src/tcp_subr.c
deleted file mode 100644
index 4224213..0000000
--- a/qemu/slirp/src/tcp_subr.c
+++ /dev/null
@@ -1,989 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * 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.
- */
-
-#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 = MIN(so->slirp->if_mtu - ((so->so_ffamily == AF_INET) ? 40 : 60), TCP_MAXSEG_MAX);
-
- 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");
- if (sotranslate_out(so, &addr) < 0) {
- return -1;
- }
-
- /* 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/qemu/slirp/src/tcp_timer.c b/qemu/slirp/src/tcp_timer.c
deleted file mode 100644
index be361a1..0000000
--- a/qemu/slirp/src/tcp_timer.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * 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/qemu/slirp/src/tcp_var.h b/qemu/slirp/src/tcp_var.h
deleted file mode 100644
index 162be6e..0000000
--- a/qemu/slirp/src/tcp_var.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * 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/qemu/slirp/src/tftp.c b/qemu/slirp/src/tftp.c
deleted file mode 100644
index 2071dca..0000000
--- a/qemu/slirp/src/tftp.c
+++ /dev/null
@@ -1,463 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * 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/qemu/slirp/src/udp.c b/qemu/slirp/src/udp.c
deleted file mode 100644
index 27bb829..0000000
--- a/qemu/slirp/src/udp.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * 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/qemu_patches/0001-slirp-add-slirp_initx-SlirpConfig-SlirpCb-void.patch b/qemu_patches/0001-slirp-add-slirp_initx-SlirpConfig-SlirpCb-void.patch
deleted file mode 100644
index c748356..0000000
--- a/qemu_patches/0001-slirp-add-slirp_initx-SlirpConfig-SlirpCb-void.patch
+++ /dev/null
@@ -1,179 +0,0 @@
-From 084c852ecd296049c3167b07c6b2e3a6845fe868 Mon Sep 17 00:00:00 2001
-From: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
-Date: Wed, 6 Mar 2019 16:07:23 +0900
-Subject: [PATCH 1/3] slirp: add slirp_initx(SlirpConfig *, SlirpCb *, void *)
-
-Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
----
- slirp/src/libslirp.h | 24 ++++++++++-
- slirp/src/slirp.c | 97 ++++++++++++++++++++++++++++----------------
- 2 files changed, 86 insertions(+), 35 deletions(-)
-
-diff --git a/slirp/src/libslirp.h b/slirp/src/libslirp.h
-index 3b28764bec..bd141964ff 100644
---- a/slirp/src/libslirp.h
-+++ b/slirp/src/libslirp.h
-@@ -64,7 +64,29 @@ typedef struct SlirpCb {
- void (*notify)(void *opaque);
- } SlirpCb;
-
--
-+typedef struct SlirpConfig{
-+ 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;
-+} SlirpConfig;
-+
-+Slirp *slirp_initx(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaque);
-+/* slirp_init is deprecated in favor of slirp_initx */
- Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
- struct in_addr vnetmask, struct in_addr vhost,
- bool in6_enabled,
-diff --git a/slirp/src/slirp.c b/slirp/src/slirp.c
-index 169c85b906..ee5833e18b 100644
---- a/slirp/src/slirp.c
-+++ b/slirp/src/slirp.c
-@@ -270,30 +270,23 @@ static void slirp_init_once(void)
-
- }
-
--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_initx(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaque)
- {
-- Slirp *slirp = g_malloc0(sizeof(Slirp));
-+ Slirp *slirp;
-+ if (cfg == NULL) {
-+ return NULL;
-+ }
-+ slirp = g_malloc0(sizeof(Slirp));
-
- slirp_init_once();
-
- slirp->opaque = opaque;
- slirp->cb = callbacks;
- slirp->grand = g_rand_new();
-- slirp->restricted = restricted;
-+ slirp->restricted = cfg->restricted;
-
-- slirp->in_enabled = in_enabled;
-- slirp->in6_enabled = in6_enabled;
-+ slirp->in_enabled = cfg->in_enabled;
-+ slirp->in6_enabled = cfg->in6_enabled;
-
- if_init(slirp);
- ip_init(slirp);
-@@ -302,31 +295,67 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
- /* 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->vnetwork_addr = cfg->vnetwork;
-+ slirp->vnetwork_mask = cfg->vnetmask;
-+ slirp->vhost_addr = cfg->vhost;
-+ slirp->vprefix_addr6 = cfg->vprefix_addr6;
-+ slirp->vprefix_len = cfg->vprefix_len;
-+ slirp->vhost_addr6 = cfg->vhost6;
-+ if (cfg->vhostname) {
- slirp_pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
-- vhostname);
-+ cfg->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);
-+ slirp->tftp_prefix = g_strdup(cfg->tftp_path);
-+ slirp->bootp_filename = g_strdup(cfg->bootfile);
-+ slirp->vdomainname = g_strdup(cfg->vdomainname);
-+ slirp->vdhcp_startaddr = cfg->vdhcp_start;
-+ slirp->vnameserver_addr = cfg->vnameserver;
-+ slirp->vnameserver_addr6 = cfg->vnameserver6;
-+ slirp->tftp_server_name = g_strdup(cfg->tftp_server_name);
-+
-+ if (cfg->vdnssearch) {
-+ translate_dnssearch(slirp, cfg->vdnssearch);
- }
-
- return slirp;
- }
-
-+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)
-+{
-+ SlirpConfig cfg;
-+ memset(&cfg, 0, sizeof(cfg));
-+ cfg.restricted = restricted;
-+ cfg.in_enabled = in_enabled;
-+ cfg.vnetwork = vnetwork;
-+ cfg.vnetmask = vnetmask;
-+ cfg.vhost = vhost;
-+ cfg.in6_enabled = in6_enabled;
-+ cfg.vprefix_addr6 = vprefix_addr6;
-+ cfg.vprefix_len = vprefix_len;
-+ cfg.vhost6 = vhost6;
-+ cfg.vhostname = vhostname;
-+ cfg.tftp_server_name = tftp_server_name;
-+ cfg.tftp_path = tftp_path;
-+ cfg.bootfile = bootfile;
-+ cfg.vdhcp_start = vdhcp_start;
-+ cfg.vnameserver = vnameserver;
-+ cfg.vnameserver6 = vnameserver6;
-+ cfg.vdnssearch = vdnssearch;
-+ cfg.vdomainname = vdomainname;
-+ return slirp_initx(&cfg, callbacks, opaque);
-+}
-+
- void slirp_cleanup(Slirp *slirp)
- {
- struct gfwd_list *e, *next;
---
-2.20.1
-
diff --git a/qemu_patches/0002-slirp-allow-custom-MTU.patch b/qemu_patches/0002-slirp-allow-custom-MTU.patch
deleted file mode 100644
index c679238..0000000
--- a/qemu_patches/0002-slirp-allow-custom-MTU.patch
+++ /dev/null
@@ -1,292 +0,0 @@
-From a9af0f1d11b3ab12da9749d1f858dafb06c67bd8 Mon Sep 17 00:00:00 2001
-From: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
-Date: Wed, 6 Mar 2019 16:15:37 +0900
-Subject: [PATCH 2/3] slirp: allow custom MTU
-
-From slirp4netns project:
-* https://github.com/rootless-containers/slirp4netns/commit/ea630a7e945cf538184ff1b1b4bd7b8ddc01993e
-* https://github.com/rootless-containers/slirp4netns/commit/1508a66c93c223555f08651592dde3d2d708b166
-* https://github.com/rootless-containers/slirp4netns/commit/19f3f41df4066d6103e6f882500e24db7ea7d9e1
-* https://github.com/rootless-containers/slirp4netns/commit/a11abedafcc627ef0657999e63b211b0f26d4c02
-* https://github.com/rootless-containers/slirp4netns/commit/2adbd7c449944d3b837164c86eedd3dcabbba1a6
-
-Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
----
- slirp/src/dhcpv6.c | 2 +-
- slirp/src/if.h | 6 ++++--
- slirp/src/ip6_icmp.c | 4 ++--
- slirp/src/ip6_input.c | 2 +-
- slirp/src/ip_output.c | 4 ++--
- slirp/src/libslirp.h | 4 ++++
- slirp/src/mbuf.c | 8 ++++----
- slirp/src/slirp.c | 11 ++++++++++-
- slirp/src/slirp.h | 3 +++
- slirp/src/tcp.h | 18 +++---------------
- slirp/src/tcp_input.c | 6 +++---
- slirp/src/tcp_subr.c | 2 +-
- 12 files changed, 38 insertions(+), 32 deletions(-)
-
-diff --git a/slirp/src/dhcpv6.c b/slirp/src/dhcpv6.c
-index 3c8f420912..53bb90b541 100644
---- a/slirp/src/dhcpv6.c
-+++ b/slirp/src/dhcpv6.c
-@@ -177,7 +177,7 @@ static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas,
-
- *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);
-+ smaxlen = (uint8_t *)m->m_data + slirp->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",
-diff --git a/slirp/src/if.h b/slirp/src/if.h
-index b71c37d6ea..7a47a12ab2 100644
---- a/slirp/src/if.h
-+++ b/slirp/src/if.h
-@@ -11,8 +11,10 @@
- #define IF_AUTOCOMP 0x04 /* Autodetect (default) */
- #define IF_NOCIDCOMP 0x08 /* CID compression */
-
--#define IF_MTU 1500
--#define IF_MRU 1500
-+#define IF_MTU_DEFAULT 1500
-+#define IF_MTU_MAX 65521
-+#define IF_MRU_DEFAULT 1500
-+#define IF_MRU_MAX 65521
- #define IF_COMP IF_AUTOCOMP /* Flags for compression */
-
- /* 2 for alignment, 14 for ethernet */
-diff --git a/slirp/src/ip6_icmp.c b/slirp/src/ip6_icmp.c
-index 5642457fdd..dcace933a9 100644
---- a/slirp/src/ip6_icmp.c
-+++ b/slirp/src/ip6_icmp.c
-@@ -93,7 +93,7 @@ void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
-
- rip->ip_nh = IPPROTO_ICMPV6;
- const int error_data_len = MIN(m->m_len,
-- IF_MTU - (sizeof(struct ip6) + ICMP6_ERROR_MINLEN));
-+ slirp->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);
-
-@@ -110,7 +110,7 @@ void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
- ricmp->icmp6_err.unused = 0;
- break;
- case ICMP6_TOOBIG:
-- ricmp->icmp6_err.mtu = htonl(IF_MTU);
-+ ricmp->icmp6_err.mtu = htonl(slirp->if_mtu);
- break;
- case ICMP6_PARAMPROB:
- /* TODO: Handle this case */
-diff --git a/slirp/src/ip6_input.c b/slirp/src/ip6_input.c
-index d9d2b7e9cd..dfcbfd6a78 100644
---- a/slirp/src/ip6_input.c
-+++ b/slirp/src/ip6_input.c
-@@ -44,7 +44,7 @@ void ip6_input(struct mbuf *m)
- goto bad;
- }
-
-- if (ntohs(ip6->ip_pl) > IF_MTU) {
-+ if (ntohs(ip6->ip_pl) > slirp->if_mtu) {
- icmp6_send_error(m, ICMP6_TOOBIG, 0);
- goto bad;
- }
-diff --git a/slirp/src/ip_output.c b/slirp/src/ip_output.c
-index 8560197cf6..cd2ea7c72d 100644
---- a/slirp/src/ip_output.c
-+++ b/slirp/src/ip_output.c
-@@ -73,7 +73,7 @@ ip_output(struct socket *so, struct mbuf *m0)
- /*
- * If small enough for interface, can just send directly.
- */
-- if ((uint16_t)ip->ip_len <= IF_MTU) {
-+ if ((uint16_t)ip->ip_len <= slirp->if_mtu) {
- ip->ip_len = htons((uint16_t)ip->ip_len);
- ip->ip_off = htons((uint16_t)ip->ip_off);
- ip->ip_sum = 0;
-@@ -92,7 +92,7 @@ ip_output(struct socket *so, struct mbuf *m0)
- goto bad;
- }
-
-- len = (IF_MTU - hlen) &~ 7; /* ip databytes per packet */
-+ len = (slirp->if_mtu - hlen) &~ 7; /* ip databytes per packet */
- if (len < 8) {
- error = -1;
- goto bad;
-diff --git a/slirp/src/libslirp.h b/slirp/src/libslirp.h
-index bd141964ff..4e2d4ee6c7 100644
---- a/slirp/src/libslirp.h
-+++ b/slirp/src/libslirp.h
-@@ -83,6 +83,10 @@ typedef struct SlirpConfig{
- struct in6_addr vnameserver6;
- const char **vdnssearch;
- const char *vdomainname;
-+ /* Default: IF_MTU_DEFAULT */
-+ int if_mtu;
-+ /* Default: IF_MRU_DEFAULT */
-+ int if_mru;
- } SlirpConfig;
-
- Slirp *slirp_initx(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaque);
-diff --git a/slirp/src/mbuf.c b/slirp/src/mbuf.c
-index 800406ca9e..b1ac229b7b 100644
---- a/slirp/src/mbuf.c
-+++ b/slirp/src/mbuf.c
-@@ -20,8 +20,8 @@
- /*
- * Find a nice value for msize
- */
--#define SLIRP_MSIZE\
-- (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + IF_MTU)
-+#define SLIRP_MSIZE(mtu)\
-+ (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + (mtu))
-
- void
- m_init(Slirp *slirp)
-@@ -68,7 +68,7 @@ m_get(Slirp *slirp)
- DEBUG_CALL("m_get");
-
- if (slirp->m_freelist.qh_link == &slirp->m_freelist) {
-- m = g_malloc(SLIRP_MSIZE);
-+ m = g_malloc(SLIRP_MSIZE(slirp->if_mtu));
- slirp->mbuf_alloced++;
- if (slirp->mbuf_alloced > MBUF_THRESH)
- flags = M_DOFREE;
-@@ -83,7 +83,7 @@ m_get(Slirp *slirp)
- m->m_flags = (flags | M_USEDLIST);
-
- /* Initialise it */
-- m->m_size = SLIRP_MSIZE - offsetof(struct mbuf, m_dat);
-+ m->m_size = SLIRP_MSIZE(slirp->if_mtu) - offsetof(struct mbuf, m_dat);
- m->m_data = m->m_dat;
- m->m_len = 0;
- m->m_nextpkt = NULL;
-diff --git a/slirp/src/slirp.c b/slirp/src/slirp.c
-index ee5833e18b..8c02913769 100644
---- a/slirp/src/slirp.c
-+++ b/slirp/src/slirp.c
-@@ -276,6 +276,13 @@ Slirp *slirp_initx(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaqu
- if (cfg == NULL) {
- return NULL;
- }
-+ if (cfg->if_mtu > IF_MTU_MAX) {
-+ return NULL;
-+ }
-+ if (cfg->if_mru > IF_MRU_MAX) {
-+ return NULL;
-+ }
-+
- slirp = g_malloc0(sizeof(Slirp));
-
- slirp_init_once();
-@@ -316,6 +323,8 @@ Slirp *slirp_initx(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaqu
- if (cfg->vdnssearch) {
- translate_dnssearch(slirp, cfg->vdnssearch);
- }
-+ slirp->if_mtu = cfg->if_mtu == 0 ? IF_MTU_DEFAULT : cfg->if_mtu;
-+ slirp->if_mru = cfg->if_mru == 0 ? IF_MRU_DEFAULT : cfg->if_mru;
-
- return slirp;
- }
-@@ -924,7 +933,7 @@ static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
- */
- int if_encap(Slirp *slirp, struct mbuf *ifm)
- {
-- uint8_t buf[1600];
-+ uint8_t buf[IF_MTU_MAX+100];
- struct ethhdr *eh = (struct ethhdr *)buf;
- uint8_t ethaddr[ETH_ALEN];
- const struct ip *iph = (const struct ip *)ifm->m_data;
-diff --git a/slirp/src/slirp.h b/slirp/src/slirp.h
-index 39580934f3..1c485be36f 100644
---- a/slirp/src/slirp.h
-+++ b/slirp/src/slirp.h
-@@ -146,6 +146,9 @@ struct Slirp {
- int restricted;
- struct gfwd_list *guestfwd_list;
-
-+ int if_mtu;
-+ int if_mru;
-+
- /* mbuf states */
- struct quehead m_freelist;
- struct quehead m_usedlist;
-diff --git a/slirp/src/tcp.h b/slirp/src/tcp.h
-index 79d3251bb5..fca5c13db5 100644
---- a/slirp/src/tcp.h
-+++ b/slirp/src/tcp.h
-@@ -41,8 +41,9 @@ 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
-+#define TCP_SNDSPACE 1024*128
-+#define TCP_RCVSPACE 1024*128
-+#define TCP_MAXSEG_MAX 32768
-
- /*
- * TCP header.
-@@ -99,19 +100,6 @@ struct tcphdr {
- #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 */
-
-diff --git a/slirp/src/tcp_input.c b/slirp/src/tcp_input.c
-index 50a1145ec9..14a489e61a 100644
---- a/slirp/src/tcp_input.c
-+++ b/slirp/src/tcp_input.c
-@@ -1522,11 +1522,11 @@ tcp_mss(struct tcpcb *tp, unsigned offer)
-
- switch (so->so_ffamily) {
- case AF_INET:
-- mss = MIN(IF_MTU, IF_MRU) - sizeof(struct tcphdr)
-+ mss = MIN(so->slirp->if_mtu, so->slirp->if_mru) - sizeof(struct tcphdr)
- - sizeof(struct ip);
- break;
- case AF_INET6:
-- mss = MIN(IF_MTU, IF_MRU) - sizeof(struct tcphdr)
-+ mss = MIN(so->slirp->if_mtu, so->slirp->if_mru) - sizeof(struct tcphdr)
- - sizeof(struct ip6);
- break;
- default:
-@@ -1537,7 +1537,7 @@ tcp_mss(struct tcpcb *tp, unsigned offer)
- mss = MIN(mss, offer);
- mss = MAX(mss, 32);
- if (mss < tp->t_maxseg || offer != 0)
-- tp->t_maxseg = mss;
-+ tp->t_maxseg = MIN(mss, TCP_MAXSEG_MAX);
-
- tp->snd_cwnd = mss;
-
-diff --git a/slirp/src/tcp_subr.c b/slirp/src/tcp_subr.c
-index fde9207b0c..e88e51e39c 100644
---- a/slirp/src/tcp_subr.c
-+++ b/slirp/src/tcp_subr.c
-@@ -259,7 +259,7 @@ tcp_newtcpcb(struct socket *so)
-
- 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_maxseg = MIN(so->slirp->if_mtu - ((so->so_ffamily == AF_INET) ? 40 : 60), TCP_MAXSEG_MAX);
-
- tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
- tp->t_socket = so;
---
-2.20.1
-
diff --git a/qemu_patches/0003-slirp-add-disable_host_loopback-prohibit-connections.patch b/qemu_patches/0003-slirp-add-disable_host_loopback-prohibit-connections.patch
deleted file mode 100644
index 819edeb..0000000
--- a/qemu_patches/0003-slirp-add-disable_host_loopback-prohibit-connections.patch
+++ /dev/null
@@ -1,209 +0,0 @@
-From 3e8a2a9a3a467e7ab02cc28f99bdcd5d2e30d217 Mon Sep 17 00:00:00 2001
-From: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
-Date: Wed, 6 Mar 2019 17:04:14 +0900
-Subject: [PATCH 3/3] slirp: add disable_host_loopback (prohibit connections to
- 127.0.0.1)
-
-From slirp4netns project:
-* https://github.com/rootless-containers/slirp4netns/commit/6325473781bb344c225f54e2d28800fb0619d7ee
-* https://github.com/rootless-containers/slirp4netns/commit/13b24026867d4c30d5d1465ac82e3bb890bf4caa
-
-Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
-Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
----
- slirp/src/ip_icmp.c | 6 +++-
- slirp/src/libslirp.h | 2 ++
- slirp/src/slirp.c | 1 +
- slirp/src/slirp.h | 2 ++
- slirp/src/socket.c | 68 +++++++++++++++++++++++++-------------------
- slirp/src/socket.h | 2 +-
- slirp/src/tcp_subr.c | 4 ++-
- 7 files changed, 53 insertions(+), 32 deletions(-)
-
-diff --git a/slirp/src/ip_icmp.c b/slirp/src/ip_icmp.c
-index 1aea18afa7..b0f116dd22 100644
---- a/slirp/src/ip_icmp.c
-+++ b/slirp/src/ip_icmp.c
-@@ -189,7 +189,11 @@ icmp_input(struct mbuf *m, int hlen)
-
- /* Send the packet */
- addr = so->fhost.ss;
-- sotranslate_out(so, &addr);
-+ if (sotranslate_out(so, &addr) < 0) {
-+ icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
-+ udp_detach(so);
-+ return;
-+ }
-
- if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
- (struct sockaddr *)&addr, sockaddr_size(&addr)) == -1) {
-diff --git a/slirp/src/libslirp.h b/slirp/src/libslirp.h
-index 4e2d4ee6c7..d8e69828ba 100644
---- a/slirp/src/libslirp.h
-+++ b/slirp/src/libslirp.h
-@@ -87,6 +87,8 @@ typedef struct SlirpConfig{
- int if_mtu;
- /* Default: IF_MRU_DEFAULT */
- int if_mru;
-+ /* Prohibit connecting to 127.0.0.1:* */
-+ bool disable_host_loopback;
- } SlirpConfig;
-
- Slirp *slirp_initx(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaque);
-diff --git a/slirp/src/slirp.c b/slirp/src/slirp.c
-index 8c02913769..cc1215d2dd 100644
---- a/slirp/src/slirp.c
-+++ b/slirp/src/slirp.c
-@@ -325,6 +325,7 @@ Slirp *slirp_initx(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaqu
- }
- slirp->if_mtu = cfg->if_mtu == 0 ? IF_MTU_DEFAULT : cfg->if_mtu;
- slirp->if_mru = cfg->if_mru == 0 ? IF_MRU_DEFAULT : cfg->if_mru;
-+ slirp->disable_host_loopback = cfg->disable_host_loopback;
-
- return slirp;
- }
-diff --git a/slirp/src/slirp.h b/slirp/src/slirp.h
-index 1c485be36f..fce6583f8a 100644
---- a/slirp/src/slirp.h
-+++ b/slirp/src/slirp.h
-@@ -149,6 +149,8 @@ struct Slirp {
- int if_mtu;
- int if_mru;
-
-+ bool disable_host_loopback;
-+
- /* mbuf states */
- struct quehead m_freelist;
- struct quehead m_usedlist;
-diff --git a/slirp/src/socket.c b/slirp/src/socket.c
-index 4a3c935e25..be27e523e6 100644
---- a/slirp/src/socket.c
-+++ b/slirp/src/socket.c
-@@ -659,7 +659,9 @@ sosendto(struct socket *so, struct mbuf *m)
-
- addr = so->fhost.ss;
- DEBUG_CALL(" sendto()ing)");
-- sotranslate_out(so, &addr);
-+ if (sotranslate_out(so, &addr) < 0) {
-+ return -1;
-+ }
-
- /* Don't care what port we get */
- ret = sendto(so->s, m->m_data, m->m_len, 0,
-@@ -825,49 +827,57 @@ sofwdrain(struct socket *so)
- /*
- * Translate addr in host addr when it is a virtual address
- */
--void sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
-+int sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
- {
-+ int rc = 0;
- 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) {
-+ 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) {
-+ goto ret;
-+ }
-+ }
-+ if (slirp->disable_host_loopback) {
-+ rc = -1;
-+ errno = EPERM;
-+ goto ret;
-+ } else {
- 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;
-+ 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;
-+ goto ret;
-+ }
-+ }
-+ if (slirp->disable_host_loopback){
-+ rc = -1;
-+ errno = EPERM;
-+ goto ret;
- } else {
- sin6->sin6_addr = in6addr_loopback;
- }
-- } else {
-- sin6->sin6_addr = in6addr_loopback;
- }
-- }
-- break;
-+ break;
-
-- default:
-- break;
-+ default:
-+ break;
- }
-+ret:
-+ return rc;
- }
-
- void sotranslate_in(struct socket *so, struct sockaddr_storage *addr)
-diff --git a/slirp/src/socket.h b/slirp/src/socket.h
-index 25403898cd..791ae9482c 100644
---- a/slirp/src/socket.h
-+++ b/slirp/src/socket.h
-@@ -151,7 +151,7 @@ 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 *);
-+int 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);
-diff --git a/slirp/src/tcp_subr.c b/slirp/src/tcp_subr.c
-index e88e51e39c..4224213c14 100644
---- a/slirp/src/tcp_subr.c
-+++ b/slirp/src/tcp_subr.c
-@@ -420,7 +420,9 @@ int tcp_fconnect(struct socket *so, unsigned short af)
-
- addr = so->fhost.ss;
- DEBUG_CALL(" connect()ing");
-- sotranslate_out(so, &addr);
-+ if (sotranslate_out(so, &addr) < 0) {
-+ return -1;
-+ }
-
- /* We don't care what port we get */
- ret = connect(s, (struct sockaddr *)&addr, sockaddr_size(&addr));
---
-2.20.1
-
diff --git a/qemu_patches/README.md b/qemu_patches/README.md
deleted file mode 100644
index 1b4d26e..0000000
--- a/qemu_patches/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# `qemu_patches`
-
-This directory contains the slirp4netns patch set for QEMU slirp.
-We will propose our patch set to the QEMU slirp upstream later.
-
-The `*.patch` files in this directory are applied to [`../qemu`](../qemu) via [`sync.sh`](./sync.sh).
-Please DO NOT edit the contents under [`../qemu`](../qemu) manually.
-
-## Update `QEMU_COMMIT`
-
-Steps:
-* Update `QEMU_COMMIT` specified in [`sync.sh`](./sync.sh).
-* Rebase `*.patch` if needed (see below).
-* Run [`sync.sh`](./sync.sh).
-
-## Modify `*.patch`
-
-Please feel free to replace/add/remove `*.patch` files in this directory!
-
-Steps:
-* Clone the upstream QEMU (`git clone https://github.com/qemu/qemu.git`)
-* Checkout `QEMU_COMMIT` specified in [`sync.sh`](./sync.sh)
-* Apply patches in this directory (`git am *.patch`).
-* Commit your own change with `Signed-off-by` line (`git commit -a -s`). See [`https://wiki.qemu.org/Contribute/SubmitAPatch#Patch_emails_must_include_a_Signed-off-by:_line`](https://wiki.qemu.org/Contribute/SubmitAPatch#Patch_emails_must_include_a_Signed-off-by:_line).
-* Consider melding your change into existing patches if your change is trivial (`git rebase -i ...`).
-* Run `git format-patch upstream/master` and put the new patch set into this directory.
-* Run [`sync.sh`](./sync.sh).
-* Open a PR to the slirp4netns repo.
-
-Note: We may squash your patch to another patch but we will keep your `Signed-off-by` line.
diff --git a/qemu_patches/sync.sh b/qemu_patches/sync.sh
deleted file mode 100755
index 85af03e..0000000
--- a/qemu_patches/sync.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/bash
-set -eux -o pipefail
-QEMU_REPO=https://github.com/qemu/qemu.git
-# v4.0.0-rc1 (March 2019)
-QEMU_COMMIT=49fc899f8d673dd9e73f3db0d9e9ea60b77c331b
-cd $(dirname $0)/..
-slirp4netns_dir=$(pwd)
-slirp4netns_qemu_dir=$slirp4netns_dir/qemu
-if ! [ -w $HOME ]; then
- echo "HOME needs to be set and writable"
- exit 1
-fi
-qemu_dir=$HOME/.cache/slirp4netns-qemu
-
-fetch_qemu() {
- (
- cd $qemu_dir
- # TODO: cache
- rm -rf .git *
- git init
- git remote add origin $QEMU_REPO
- git fetch --depth 1 origin $QEMU_COMMIT
- git checkout FETCH_HEAD
- )
-}
-
-mkdir -p $qemu_dir
-(
- cd $qemu_dir
- git checkout $QEMU_COMMIT || fetch_qemu
- git am $slirp4netns_dir/qemu_patches/*.patch
-)
-
-rm -rf $slirp4netns_qemu_dir
-mkdir -p $slirp4netns_qemu_dir
-cp -a $qemu_dir/{COPYING*,LICENSE*,slirp} $slirp4netns_qemu_dir
-rm -f $slirp4netns_qemu_dir/slirp/src/Makefile
-cat << EOF > $slirp4netns_qemu_dir/README.md
-# DO NOT EDIT MANUALLY
-
-This directory was synced from QEMU \`${QEMU_COMMIT}\` (\`${QEMU_REPO}\`),
-with the following patches (sha256sum):
-\`\`\`
-$(cd $slirp4netns_dir/qemu_patches; sha256sum *.patch)
-\`\`\`
-
-Please do not edit the contents under this directory manually.
-
-See also [\`../qemu_patches/README.md\`](../qemu_patches/README.md).
-EOF
diff --git a/slirp4netns.c b/slirp4netns.c
index b4d580a..24fbbd2 100644
--- a/slirp4netns.c
+++ b/slirp4netns.c
@@ -7,7 +7,7 @@
#include <glib.h>
-#include "qemu/slirp/src/libslirp.h"
+#include "vendor/libslirp/src/libslirp.h"
#include "api.h"
#include "slirp4netns.h"
@@ -238,6 +238,7 @@ Slirp *create_slirp(void *opaque, struct slirp4netns_config *s4nn)
Slirp *slirp = NULL;
SlirpConfig cfg;
memset(&cfg, 0, sizeof(cfg));
+ cfg.version = 1;
cfg.restricted = 0;
cfg.in_enabled = 1;
cfg.vnetwork = s4nn->vnetwork;
@@ -259,7 +260,7 @@ Slirp *create_slirp(void *opaque, struct slirp4netns_config *s4nn)
cfg.if_mtu = s4nn->mtu;
cfg.if_mru = s4nn->mtu;
cfg.disable_host_loopback = s4nn->disable_host_loopback;
- slirp = slirp_initx(&cfg, &libslirp_cb, opaque);
+ slirp = slirp_new(&cfg, &libslirp_cb, opaque);
if (slirp == NULL) {
fprintf(stderr, "slirp_initx failed\n");
}
diff --git a/vendor.md b/vendor.md
new file mode 100644
index 0000000..a826d8b
--- /dev/null
+++ b/vendor.md
@@ -0,0 +1,27 @@
+# Vendor
+
+The `*.patch` files in `vendor_patches` directory (if exists) are applied to `vendor` via [`vendor.sh`](./vendor.sh).
+Please DO NOT edit files under `vendor`.
+
+## Update vendor
+
+Steps:
+* Update commits specified in [`vendor.sh`](./vendor.sh).
+* Rebase `*.patch` under `vendor_patches` if needed (see below).
+* Run [`vendor.sh`](./vendor.sh).
+
+## Modify `*.patch`
+
+Please feel free to replace/add/remove `*.patch` files in `vendor_patches` directory.
+
+Steps:
+* Clone the upstream [libslirp](https://gitlab.freedesktop.org/slirp/libslirp) repo.
+* Checkout `LIBSLIRP_COMMIT` specified in [`vendor.sh`](./vendor.sh)
+* Apply patches in this directory (`git am *.patch`).
+* Commit your own change with `Signed-off-by` line (`git commit -a -s`). See [`https://wiki.qemu.org/Contribute/SubmitAPatch#Patch_emails_must_include_a_Signed-off-by:_line`](https://wiki.qemu.org/Contribute/SubmitAPatch#Patch_emails_must_include_a_Signed-off-by:_line).
+* Consider melding your change into existing patches if your change is trivial (`git rebase -i ...`).
+* Run `git format-patch upstream/master` and put the new patch set into this directory.
+* Run [`vendor.sh`](./vendor.sh).
+* Open a PR to the slirp4netns repo.
+
+Note: We may squash your patch to another patch but we will keep your `Signed-off-by` line.
diff --git a/vendor.sh b/vendor.sh
new file mode 100755
index 0000000..ef3051f
--- /dev/null
+++ b/vendor.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+set -eux -o pipefail
+# Aug 2, 2019
+LIBSLIRP_COMMIT=76462e2f16c6fce6856fb914cbef6207d0be4bc5
+LIBSLIRP_REPO=https://gitlab.freedesktop.org/slirp/libslirp.git
+
+# Jul 12, 2019
+PARSON_COMMIT=c5bb9557fe98367aa8e041c65863909f12ee76b2
+PARSON_REPO=https://github.com/kgabis/parson.git
+
+# prepare
+slirp4netns_root=$(realpath $(dirname $0))
+tmp=$(mktemp -d /tmp/slirp4netns-vendor.XXXXXXXXXX)
+tmp_git=$tmp/git
+tmp_vendor=$tmp/vendor
+mkdir -p $tmp_git $tmp_vendor
+
+# vendor libslirp
+git clone $LIBSLIRP_REPO $tmp_git/libslirp
+(
+ cd $tmp_git/libslirp
+ git checkout $LIBSLIRP_COMMIT
+ if ls $slirp4netns_root/vendor_patches/libslirp/*.patch >/dev/null; then
+ git am $slirp4netns_root/vendor_patches/libslirp/*.patch
+ fi
+ # run make to generate src/libslirp-version.h
+ make
+ mkdir -p $tmp_vendor/libslirp/src
+ cp -a .clang-format COPYRIGHT README.md $tmp_vendor/libslirp
+ cp -a src/{*.c,*.h} $tmp_vendor/libslirp/src
+)
+
+# vendor parson
+git clone $PARSON_REPO $tmp_git/parson
+(
+ cd $tmp_git/parson
+ git checkout $PARSON_COMMIT
+ mkdir -p $tmp_vendor/parson
+ cp -a LICENSE README.md parson.c parson.h $tmp_vendor/parson
+)
+
+# write vendor/README.md
+cat <<EOF >$tmp_vendor/README.md
+# DO NOT EDIT MANUALLY
+
+Vendored components:
+* libslirp: $LIBSLIRP_REPO (\`$LIBSLIRP_COMMIT\`)
+* parson: $PARSON_REPO (\`$PARSON_COMMIT\`)
+
+EOF
+
+if ls $slirp4netns_root/vendor_patches/libslirp/*.patch >/dev/null; then
+ cat <<EOF >>$tmp_vendor/README.md
+Applied patches (sha256sum):
+\`\`\`
+$(
+ cd $slirp4netns_root
+ sha256sum vendor_patches/*/*
+ )
+\`\`\`
+
+EOF
+fi
+
+cat <<EOF >>$tmp_vendor/README.md
+Please do not edit the contents under this directory manually.
+
+See also [\`../vendor.md\`](../vendor.md).
+EOF
+
+# fix up
+rm -rf $slirp4netns_root/vendor
+mv $tmp_vendor $slirp4netns_root/vendor
+rm -rf $tmp
diff --git a/vendor/README.md b/vendor/README.md
new file mode 100644
index 0000000..fa24251
--- /dev/null
+++ b/vendor/README.md
@@ -0,0 +1,9 @@
+# DO NOT EDIT MANUALLY
+
+Vendored components:
+* libslirp: https://gitlab.freedesktop.org/slirp/libslirp.git (`76462e2f16c6fce6856fb914cbef6207d0be4bc5`)
+* parson: https://github.com/kgabis/parson.git (`c5bb9557fe98367aa8e041c65863909f12ee76b2`)
+
+Please do not edit the contents under this directory manually.
+
+See also [`../vendor.md`](../vendor.md).
diff --git a/vendor/libslirp/.clang-format b/vendor/libslirp/.clang-format
new file mode 100644
index 0000000..17fb49f
--- /dev/null
+++ b/vendor/libslirp/.clang-format
@@ -0,0 +1,58 @@
+# https://clang.llvm.org/docs/ClangFormat.html
+# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
+---
+Language: Cpp
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false # although we like it, it creates churn
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: true
+AlignOperands: true
+AlignTrailingComments: false # churn
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterReturnType: None # AlwaysBreakAfterDefinitionReturnType is taken into account
+AlwaysBreakBeforeMultilineStrings: false
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterControlStatement: false
+ AfterEnum: false
+ AfterFunction: true
+ AfterStruct: false
+ AfterUnion: false
+ BeforeElse: false
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: false
+BreakStringLiterals: true
+ColumnLimit: 80
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: false
+DerivePointerAlignment: false
+DisableFormat: false
+IndentCaseLabels: false
+IndentWidth: 4
+IndentWrappedFunctionNames: false
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: '.*_BEGIN$' # only PREC_BEGIN ?
+MacroBlockEnd: '.*_END$'
+MaxEmptyLinesToKeep: 2
+PointerAlignment: Right
+ReflowComments: true
+SortIncludes: false
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInContainerLiterals: true
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Auto
+UseTab: Never
+...
diff --git a/qemu/slirp/COPYRIGHT b/vendor/libslirp/COPYRIGHT
index ed49512..ed49512 100644
--- a/qemu/slirp/COPYRIGHT
+++ b/vendor/libslirp/COPYRIGHT
diff --git a/vendor/libslirp/README.md b/vendor/libslirp/README.md
new file mode 100644
index 0000000..dc11e5f
--- /dev/null
+++ b/vendor/libslirp/README.md
@@ -0,0 +1,60 @@
+# libslirp
+
+libslirp is a user-mode networking library used by virtual machines,
+containers or various tools.
+
+## Getting Started
+
+### Prerequisites
+
+A C compiler, make/meson and glib2 development libraries.
+
+(see also [.gitlab-ci.yml](.gitlab-ci.yml) DEPS variable for the list
+of dependencies on Fedora)
+
+### Building
+
+You may build and install the shared library with meson:
+
+``` sh
+meson build
+ninja -C build install
+```
+And configure QEMU with --enable-slirp=system to link against it.
+
+(QEMU may build with the submodule static library using --enable-slirp=git)
+
+### Testing
+
+Unfortunately, there are no automated tests available.
+
+You may run QEMU ``-net user`` linked with your development version.
+
+## Contributing
+
+Feel free to open issues on the [project
+issues](https://gitlab.freedesktop.org/slirp/libslirp/issues) page.
+
+You may clone the [gitlab
+project](https://gitlab.freedesktop.org/slirp/libslirp) and create a
+merge request.
+
+Contributing with gitlab allows gitlab workflow, tracking issues,
+running CI etc.
+
+Alternatively, you may send patches to slirp@lists.freedesktop.org
+mailing list.
+
+## Versioning
+
+We intend to use [libtool's
+versioning](https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html)
+for the shared libraries and use [SemVer](http://semver.org/) for
+project versions.
+
+For the versions available, see the [tags on this
+repository](https://gitlab.freedesktop.org/slirp/libslirp/releases).
+
+## License
+
+See the [COPYRIGHT](COPYRIGHT) file for details.
diff --git a/qemu/slirp/src/arp_table.c b/vendor/libslirp/src/arp_table.c
index 9d7a59e..022a52e 100644
--- a/qemu/slirp/src/arp_table.c
+++ b/vendor/libslirp/src/arp_table.c
@@ -35,10 +35,9 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
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]);
+ 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 */
@@ -56,7 +55,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
/* 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);
+ memcpy(arptbl->table[arptbl->next_victim].ar_sha, ethaddr, ETH_ALEN);
arptbl->next_victim = (arptbl->next_victim + 1) % ARP_TABLE_SIZE;
}
@@ -69,7 +68,7 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
int i;
DEBUG_CALL("arp_table_search");
- DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){.s_addr = ip_addr}));
+ DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){ .s_addr = ip_addr }));
/* If broadcast address */
if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
@@ -80,7 +79,7 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
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);
+ 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]);
diff --git a/qemu/slirp/src/bootp.c b/vendor/libslirp/src/bootp.c
index b208e3b..02ef944 100644
--- a/qemu/slirp/src/bootp.c
+++ b/vendor/libslirp/src/bootp.c
@@ -27,7 +27,7 @@
#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))
+#define ntohl(n) ((uint32_t)ntohl(n))
#endif
/* XXX: only DHCP is supported */
@@ -44,13 +44,13 @@ static BOOTPClient *get_new_addr(Slirp *slirp, struct in_addr *paddr,
BOOTPClient *bc;
int i;
- for(i = 0; i < NB_BOOTP_CLIENTS; 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:
+found:
bc = &slirp->bootp_clients[i];
bc->allocated = 1;
paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
@@ -64,8 +64,7 @@ static BOOTPClient *request_addr(Slirp *slirp, const struct in_addr *paddr,
uint32_t dhcp_addr = ntohl(slirp->vdhcp_startaddr.s_addr);
BOOTPClient *bc;
- if (req_addr >= dhcp_addr &&
- req_addr < (dhcp_addr + NB_BOOTP_CLIENTS)) {
+ 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;
@@ -81,12 +80,12 @@ static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr,
BOOTPClient *bc;
int i;
- for(i = 0; i < NB_BOOTP_CLIENTS; i++) {
+ for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
if (!memcmp(macaddr, slirp->bootp_clients[i].macaddr, 6))
goto found;
}
return NULL;
- found:
+found:
bc = &slirp->bootp_clients[i];
bc->allocated = 1;
paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
@@ -123,7 +122,7 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
}
DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
- switch(tag) {
+ switch (tag) {
case RFC2132_MSG_TYPE:
if (len >= 1)
*pmsg_type = p[0];
@@ -169,8 +168,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
if (dhcp_msg_type == 0)
dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
- if (dhcp_msg_type != DHCPDISCOVER &&
- dhcp_msg_type != DHCPREQUEST)
+ if (dhcp_msg_type != DHCPDISCOVER && dhcp_msg_type != DHCPREQUEST)
return;
/* Get client's hardware address from bootp request */
@@ -193,7 +191,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
}
}
if (!bc) {
- new_addr:
+ new_addr:
bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr);
if (!bc) {
DPRINTF("no address left\n");
@@ -292,7 +290,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
val = strlen(slirp->client_hostname);
if (q + val + 2 >= end) {
g_warning("DHCP packet size exceeded, "
- "omitting host name option.");
+ "omitting host name option.");
} else {
*q++ = RFC1533_HOSTNAME;
*q++ = val;
@@ -305,7 +303,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
val = strlen(slirp->vdomainname);
if (q + val + 2 >= end) {
g_warning("DHCP packet size exceeded, "
- "omitting domain name option.");
+ "omitting domain name option.");
} else {
*q++ = RFC1533_DOMAINNAME;
*q++ = val;
@@ -318,7 +316,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
val = strlen(slirp->tftp_server_name);
if (q + val + 2 >= end) {
g_warning("DHCP packet size exceeded, "
- "omitting tftp-server-name option.");
+ "omitting tftp-server-name option.");
} else {
*q++ = RFC2132_TFTP_SERVER_NAME;
*q++ = val;
@@ -331,7 +329,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
val = slirp->vdnssearch_len;
if (q + val >= end) {
g_warning("DHCP packet size exceeded, "
- "omitting domain-search option.");
+ "omitting domain-search option.");
} else {
memcpy(q, slirp->vdnssearch, val);
q += val;
@@ -356,8 +354,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
daddr.sin_addr.s_addr = 0xffffffffu;
- m->m_len = sizeof(struct bootp_t) -
- sizeof(struct ip) - sizeof(struct udphdr);
+ m->m_len = sizeof(struct bootp_t) - sizeof(struct ip) - sizeof(struct udphdr);
udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
}
diff --git a/vendor/libslirp/src/bootp.h b/vendor/libslirp/src/bootp.h
new file mode 100644
index 0000000..03ece9b
--- /dev/null
+++ b/vendor/libslirp/src/bootp.h
@@ -0,0 +1,129 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* 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/qemu/slirp/src/cksum.c b/vendor/libslirp/src/cksum.c
index 9599f6a..4d08380 100644
--- a/qemu/slirp/src/cksum.c
+++ b/vendor/libslirp/src/cksum.c
@@ -42,97 +42,116 @@
* 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);}
+#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;
+ 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);
+ 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)
@@ -152,8 +171,7 @@ int ip6_cksum(struct mbuf *m)
ih->ih_zero_lo = 0;
ih->ih_nh = save_ip.ip_nh;
- sum = cksum(m, ((int)sizeof(struct ip6_pseudohdr))
- + ntohl(ih->ih_pl));
+ sum = cksum(m, ((int)sizeof(struct ip6_pseudohdr)) + ntohl(ih->ih_pl));
*ip = save_ip;
diff --git a/vendor/libslirp/src/debug.h b/vendor/libslirp/src/debug.h
new file mode 100644
index 0000000..47712bd
--- /dev/null
+++ b/vendor/libslirp/src/debug.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ */
+
+#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/qemu/slirp/src/dhcpv6.c b/vendor/libslirp/src/dhcpv6.c
index 53bb90b..ce5f203 100644
--- a/qemu/slirp/src/dhcpv6.c
+++ b/vendor/libslirp/src/dhcpv6.c
@@ -42,15 +42,15 @@
#include "dhcpv6.h"
/* DHCPv6 message types */
-#define MSGTYPE_REPLY 7
+#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
+#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;
@@ -77,7 +77,8 @@ static int dhcpv6_parse_info_request(Slirp *slirp, uint8_t *odata, int olen,
int len = odata[2] << 8 | odata[3];
if (len + 4 > olen) {
- slirp->cb->guest_error("Guest sent bad DHCPv6 packet!", slirp->opaque);
+ slirp->cb->guest_error("Guest sent bad DHCPv6 packet!",
+ slirp->opaque);
return -E2BIG;
}
@@ -93,7 +94,7 @@ static int dhcpv6_parse_info_request(Slirp *slirp, uint8_t *odata, int olen,
ri->client_id = odata + 4;
ri->client_id_len = len;
break;
- case OPTION_ORO: /* Option request option */
+ case OPTION_ORO: /* Option request option */
if (len & 1) {
return -EINVAL;
}
@@ -114,8 +115,8 @@ static int dhcpv6_parse_info_request(Slirp *slirp, uint8_t *odata, int olen,
}
break;
default:
- DEBUG_MISC("dhcpv6 info req: Unsupported option %d, len=%d",
- option, len);
+ DEBUG_MISC("dhcpv6 info req: Unsupported option %d, len=%d", option,
+ len);
}
odata += len + 4;
@@ -156,18 +157,18 @@ static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas,
*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 */
+ *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 */
+ *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;
}
@@ -175,18 +176,18 @@ static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas,
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 */
+ *resp++ = OPTION_BOOTFILE_URL >> 8; /* option-code high byte */
+ *resp++ = OPTION_BOOTFILE_URL; /* option-code low byte */
smaxlen = (uint8_t *)m->m_data + slirp->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",
+ "%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 >> 8; /* option-len high byte */
+ *resp++ = slen; /* option-len low byte */
resp += slen;
}
diff --git a/qemu/slirp/src/dhcpv6.h b/vendor/libslirp/src/dhcpv6.h
index dc26a93..d12c49b 100644
--- a/qemu/slirp/src/dhcpv6.h
+++ b/vendor/libslirp/src/dhcpv6.h
@@ -39,14 +39,29 @@
#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 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)
+#define in6_dhcp_multicast(a) in6_equal(a, &(struct in6_addr)ALLDHCP_MULTICAST)
void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m);
diff --git a/qemu/slirp/src/dnssearch.c b/vendor/libslirp/src/dnssearch.c
index 12c4889..18a6122 100644
--- a/qemu/slirp/src/dnssearch.c
+++ b/vendor/libslirp/src/dnssearch.c
@@ -40,15 +40,16 @@ typedef struct compact_domain {
size_t common_octets;
} CompactDomain;
-static size_t
-domain_suffix_diffoff(const CompactDomain *a, const CompactDomain *b)
+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--;
+ da--;
+ db--;
if (*da != *db) {
break;
}
@@ -154,8 +155,8 @@ fail:
cd->len = 0;
}
-static void
-domain_mkxrefs(CompactDomain *doms, CompactDomain *last, size_t depth)
+static void domain_mkxrefs(CompactDomain *doms, CompactDomain *last,
+ size_t depth)
{
CompactDomain *i = doms, *target = doms;
@@ -214,8 +215,7 @@ static size_t domain_compactify(CompactDomain *domains, size_t n)
CompactDomain *rd = cd->refdom;
if (rd != NULL) {
- size_t moff = (rd->labels - start)
- + (rd->len - cd->common_octets);
+ 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;
diff --git a/vendor/libslirp/src/if.c b/vendor/libslirp/src/if.c
new file mode 100644
index 0000000..23190b5
--- /dev/null
+++ b/vendor/libslirp/src/if.c
@@ -0,0 +1,213 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ */
+
+#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/qemu/slirp/src/if.h b/vendor/libslirp/src/if.h
index 7a47a12..7cf9d27 100644
--- a/qemu/slirp/src/if.h
+++ b/vendor/libslirp/src/if.h
@@ -6,16 +6,18 @@
#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_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_DEFAULT 1500
+#define IF_MTU_MIN 68
#define IF_MTU_MAX 65521
#define IF_MRU_DEFAULT 1500
+#define IF_MRU_MIN 68
#define IF_MRU_MAX 65521
-#define IF_COMP IF_AUTOCOMP /* Flags for compression */
+#define IF_COMP IF_AUTOCOMP /* Flags for compression */
/* 2 for alignment, 14 for ethernet */
#define IF_MAXLINKHDR (2 + ETH_HLEN)
diff --git a/vendor/libslirp/src/ip.h b/vendor/libslirp/src/ip.h
new file mode 100644
index 0000000..e5d4aa8
--- /dev/null
+++ b/vendor/libslirp/src/ip.h
@@ -0,0 +1,242 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * 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/vendor/libslirp/src/ip6.h b/vendor/libslirp/src/ip6.h
new file mode 100644
index 0000000..0630309
--- /dev/null
+++ b/vendor/libslirp/src/ip6.h
@@ -0,0 +1,214 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * 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/qemu/slirp/src/ip6_icmp.c b/vendor/libslirp/src/ip6_icmp.c
index dcace93..28ec2be 100644
--- a/qemu/slirp/src/ip6_icmp.c
+++ b/vendor/libslirp/src/ip6_icmp.c
@@ -7,16 +7,17 @@
#include "slirp.h"
#include "ip6_icmp.h"
-#define NDP_Interval g_rand_int_range(slirp->grand, \
- NDP_MinRtrAdvInterval, NDP_MaxRtrAdvInterval)
+#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);
+ slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS +
+ NDP_Interval,
+ slirp->opaque);
ndp_send_ra(slirp);
}
@@ -26,10 +27,12 @@ void icmp6_init(Slirp *slirp)
return;
}
- slirp->ra_timer = slirp->cb->timer_new(ra_timer_handler, slirp, slirp->opaque);
+ 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);
+ slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS +
+ NDP_Interval,
+ slirp->opaque);
}
void icmp6_cleanup(Slirp *slirp)
@@ -42,7 +45,7 @@ void icmp6_cleanup(Slirp *slirp)
}
static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
- struct icmp6 *icmp)
+ struct icmp6 *icmp)
{
struct mbuf *t = m_get(slirp);
t->m_len = sizeof(struct ip6) + ntohs(ip->ip_pl);
@@ -76,8 +79,7 @@ void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
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)) {
+ if (IN6_IS_ADDR_MULTICAST(&ip->ip_src) || in6_zero(&ip->ip_src)) {
/* TODO icmp error? */
return;
}
@@ -92,8 +94,8 @@ void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
DEBUG_ARG("target = %s", addrstr);
rip->ip_nh = IPPROTO_ICMPV6;
- const int error_data_len = MIN(m->m_len,
- slirp->if_mtu - (sizeof(struct ip6) + ICMP6_ERROR_MINLEN));
+ const int error_data_len = MIN(
+ m->m_len, slirp->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);
@@ -275,8 +277,7 @@ static void ndp_send_na(Slirp *slirp, struct ip6 *ip, struct icmp6 *icmp)
rip->ip_dst = ip->ip_src;
}
rip->ip_nh = IPPROTO_ICMPV6;
- rip->ip_pl = htons(ICMP6_NDP_NA_MINLEN
- + NDPOPT_LINKLAYER_LEN);
+ rip->ip_pl = htons(ICMP6_NDP_NA_MINLEN + NDPOPT_LINKLAYER_LEN);
t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
/* Build ICMPv6 packet */
@@ -299,8 +300,7 @@ static void ndp_send_na(Slirp *slirp, struct ip6 *ip, struct icmp6 *icmp)
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);
+ in6_compute_ethaddr(ricmp->icmp6_nna.target, opt->ndpopt_linklayer);
/* ICMPv6 Checksum */
t->m_data -= ICMP6_NDP_NA_MINLEN;
@@ -314,7 +314,7 @@ static void ndp_send_na(Slirp *slirp, struct ip6 *ip, struct icmp6 *icmp)
* Process a NDP message
*/
static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
- struct icmp6 *icmp)
+ struct icmp6 *icmp)
{
m->m_len += ETH_HLEN;
m->m_data -= ETH_HLEN;
@@ -325,9 +325,8 @@ static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
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) {
+ 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);
@@ -343,12 +342,11 @@ static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
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 (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);
@@ -359,12 +357,10 @@ static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
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)) {
+ 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;
diff --git a/vendor/libslirp/src/ip6_icmp.h b/vendor/libslirp/src/ip6_icmp.h
new file mode 100644
index 0000000..c37e60f
--- /dev/null
+++ b/vendor/libslirp/src/ip6_icmp.h
@@ -0,0 +1,219 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * 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/qemu/slirp/src/ip6_input.c b/vendor/libslirp/src/ip6_input.c
index dfcbfd6..dfcbfd6 100644
--- a/qemu/slirp/src/ip6_input.c
+++ b/vendor/libslirp/src/ip6_input.c
diff --git a/qemu/slirp/src/ip6_output.c b/vendor/libslirp/src/ip6_output.c
index b861106..b861106 100644
--- a/qemu/slirp/src/ip6_output.c
+++ b/vendor/libslirp/src/ip6_output.c
diff --git a/vendor/libslirp/src/ip_icmp.c b/vendor/libslirp/src/ip_icmp.c
new file mode 100644
index 0000000..58e35a5
--- /dev/null
+++ b/vendor/libslirp/src/ip_icmp.c
@@ -0,0 +1,482 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * 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;
+ if (sotranslate_out(so, &addr) < 0) {
+ icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0,
+ strerror(errno));
+ udp_detach(so);
+ return;
+ }
+
+ 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/vendor/libslirp/src/ip_icmp.h b/vendor/libslirp/src/ip_icmp.h
new file mode 100644
index 0000000..84707db
--- /dev/null
+++ b/vendor/libslirp/src/ip_icmp.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * 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/vendor/libslirp/src/ip_input.c b/vendor/libslirp/src/ip_input.c
new file mode 100644
index 0000000..7364ce0
--- /dev/null
+++ b/vendor/libslirp/src/ip_input.c
@@ -0,0 +1,461 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * 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.
+ */
+
+#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);
+
+ int was_ext = m->m_flags & M_EXT;
+
+ 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 and the mbuf was not already using an m_ext buffer,
+ * then an 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 (!was_ext && 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/vendor/libslirp/src/ip_output.c b/vendor/libslirp/src/ip_output.c
new file mode 100644
index 0000000..22916a3
--- /dev/null
+++ b/vendor/libslirp/src/ip_output.c
@@ -0,0 +1,169 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * 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.
+ */
+
+#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 <= slirp->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 = (slirp->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/vendor/libslirp/src/libslirp-version.h b/vendor/libslirp/src/libslirp-version.h
new file mode 100644
index 0000000..29493c6
--- /dev/null
+++ b/vendor/libslirp/src/libslirp-version.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+#ifndef LIBSLIRP_VERSION_H_
+#define LIBSLIRP_VERSION_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SLIRP_MAJOR_VERSION 4
+#define SLIRP_MINOR_VERSION 0
+#define SLIRP_MICRO_VERSION 0
+
+#define SLIRP_CHECK_VERSION(major,minor,micro) \
+ (SLIRP_MAJOR_VERSION > (major) || \
+ (SLIRP_MAJOR_VERSION == (major) && SLIRP_MINOR_VERSION > (minor)) || \
+ (SLIRP_MAJOR_VERSION == (major) && SLIRP_MINOR_VERSION == (minor) && \
+ SLIRP_MICRO_VERSION >= (micro)))
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LIBSLIRP_VERSION_H_ */
diff --git a/qemu/slirp/src/libslirp.h b/vendor/libslirp/src/libslirp.h
index d8e6982..582c711 100644
--- a/qemu/slirp/src/libslirp.h
+++ b/vendor/libslirp/src/libslirp.h
@@ -14,6 +14,8 @@
#include <arpa/inet.h>
#endif
+#include "libslirp-version.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -21,7 +23,7 @@ extern "C" {
typedef struct Slirp Slirp;
enum {
- SLIRP_POLL_IN = 1 << 0,
+ SLIRP_POLL_IN = 1 << 0,
SLIRP_POLL_OUT = 1 << 1,
SLIRP_POLL_PRI = 1 << 2,
SLIRP_POLL_ERR = 1 << 3,
@@ -64,7 +66,15 @@ typedef struct SlirpCb {
void (*notify)(void *opaque);
} SlirpCb;
-typedef struct SlirpConfig{
+#define SLIRP_CONFIG_VERSION_MIN 1
+#define SLIRP_CONFIG_VERSION_MAX 1
+
+typedef struct SlirpConfig {
+ /* Version must be provided */
+ uint32_t version;
+ /*
+ * Fields introduced in SlirpConfig version 1 begin
+ */
int restricted;
bool in_enabled;
struct in_addr vnetwork;
@@ -84,26 +94,33 @@ typedef struct SlirpConfig{
const char **vdnssearch;
const char *vdomainname;
/* Default: IF_MTU_DEFAULT */
- int if_mtu;
+ size_t if_mtu;
/* Default: IF_MRU_DEFAULT */
- int if_mru;
+ size_t if_mru;
/* Prohibit connecting to 127.0.0.1:* */
bool disable_host_loopback;
+ /*
+ * Enable emulation code (*warning*: this code isn't safe, it is not
+ * recommended to enable it)
+ */
+ bool enable_emu;
+ /*
+ * Fields introduced in SlirpConfig version 2 begin
+ */
} SlirpConfig;
-Slirp *slirp_initx(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaque);
-/* slirp_init is deprecated in favor of slirp_initx */
+Slirp *slirp_new(const SlirpConfig *cfg, const SlirpCb *callbacks,
+ void *opaque);
+/* slirp_init is deprecated in favor of slirp_new */
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,
+ 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,
+ const char *vdomainname, const SlirpCb *callbacks,
void *opaque);
void slirp_cleanup(Slirp *slirp);
@@ -115,30 +132,31 @@ void slirp_pollfds_poll(Slirp *slirp, int select_error,
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_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);
+ 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);
+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_load(Slirp *s, int version_id, SlirpReadCb read_cb,
+ void *opaque);
int slirp_state_version(void);
+const char *slirp_version_string(void);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/qemu/slirp/src/main.h b/vendor/libslirp/src/main.h
index 3b3f883..3b3f883 100644
--- a/qemu/slirp/src/main.h
+++ b/vendor/libslirp/src/main.h
diff --git a/vendor/libslirp/src/mbuf.c b/vendor/libslirp/src/mbuf.c
new file mode 100644
index 0000000..54ec721
--- /dev/null
+++ b/vendor/libslirp/src/mbuf.c
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 1995 Danny Gasparovski
+ */
+
+/*
+ * 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(mtu) \
+ (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + (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->if_mtu));
+ 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(slirp->if_mtu) - 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/qemu/slirp/src/mbuf.h b/vendor/libslirp/src/mbuf.h
index 732c85c..546e785 100644
--- a/qemu/slirp/src/mbuf.h
+++ b/vendor/libslirp/src/mbuf.h
@@ -38,7 +38,7 @@
* Macros for type conversion
* mtod(m,t) - convert mbuf pointer to data pointer of correct type
*/
-#define mtod(m,t) ((t)(m)->m_data)
+#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.
@@ -64,10 +64,9 @@
/*
* 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))
+#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
@@ -75,26 +74,26 @@
#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 */
+ /* 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;
+ 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 */
+ 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[];
+ 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
@@ -103,21 +102,22 @@ struct mbuf {
#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 */
+#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 *);
+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 *);
+struct mbuf *dtom(Slirp *, void *);
static inline void ifs_init(struct mbuf *ifm)
{
diff --git a/qemu/slirp/src/misc.c b/vendor/libslirp/src/misc.c
index 7c5db0e..6675acc 100644
--- a/qemu/slirp/src/misc.c
+++ b/vendor/libslirp/src/misc.c
@@ -5,32 +5,28 @@
#include "slirp.h"
-inline void
-insque(void *a, void *b)
+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;
+ 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)
+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;
+ 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 *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);
@@ -44,9 +40,8 @@ add_guestfwd(struct gfwd_list **ex_ptr,
return f;
}
-struct gfwd_list *
-add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
- 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)
{
struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port);
@@ -55,8 +50,7 @@ add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
return f;
}
-static int
-slirp_socketpair_with_oob(int sv[2])
+static int slirp_socketpair_with_oob(int sv[2])
{
struct sockaddr_in addr = {
.sin_family = AF_INET,
@@ -111,8 +105,7 @@ err:
return -1;
}
-static void
-fork_exec_child_setup(gpointer data)
+static void fork_exec_child_setup(gpointer data)
{
#ifndef _WIN32
setsid();
@@ -131,8 +124,7 @@ typedef struct SlirpGSpawnFds {
gint stderr_fd;
} SlirpGSpawnFds;
-static inline void
-slirp_gspawn_fds_setup(gpointer user_data)
+static inline void slirp_gspawn_fds_setup(gpointer user_data)
{
SlirpGSpawnFds *q = (SlirpGSpawnFds *)user_data;
@@ -144,23 +136,16 @@ slirp_gspawn_fds_setup(gpointer 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)
+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);
+ child_setup, user_data, child_pid, stdin_fd,
+ stdout_fd, stderr_fd, error);
#else
SlirpGSpawnFds setup = {
.child_setup = child_setup,
@@ -171,8 +156,7 @@ g_spawn_async_with_fds_slirp(const gchar *working_directory,
};
return g_spawn_async(working_directory, argv, envp, flags,
- slirp_gspawn_fds_setup, &setup,
- child_pid, error);
+ slirp_gspawn_fds_setup, &setup, child_pid, error);
#endif
}
@@ -181,8 +165,7 @@ g_spawn_async_with_fds_slirp(const gchar *working_directory,
#pragma GCC diagnostic pop
-int
-fork_exec(struct socket *so, const char *ex)
+int fork_exec(struct socket *so, const char *ex)
{
GError *err = NULL;
char **argv;
@@ -197,14 +180,10 @@ fork_exec(struct socket *so, const char *ex)
}
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_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) {
@@ -228,18 +207,13 @@ fork_exec(struct socket *so, const char *ex)
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",
+ 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;
@@ -250,8 +224,8 @@ char *slirp_connection_info(Slirp *slirp)
char buf[20];
g_string_append_printf(str,
- " Protocol[State] FD Source Address Port "
- "Dest. Address Port RecvQ SendQ\n");
+ " Protocol[State] FD Source Address Port "
+ "Dest. Address Port RecvQ SendQ\n");
/* TODO: IPv6 */
@@ -276,11 +250,12 @@ char *slirp_connection_info(Slirp *slirp)
}
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);
+ 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) {
@@ -292,29 +267,31 @@ char *slirp_connection_info(Slirp *slirp)
dst_port = so->so_lport;
} else {
snprintf(buf, sizeof(buf), " UDP[%d sec]",
- (so->so_expire - curtime) / 1000);
+ (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);
+ 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);
+ (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) : "*");
+ 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);
+ so->so_rcv.sb_cc, so->so_snd.sb_cc);
}
return g_string_free(str, FALSE);
diff --git a/qemu/slirp/src/misc.h b/vendor/libslirp/src/misc.h
index 23b7490..ccf8cf0 100644
--- a/qemu/slirp/src/misc.h
+++ b/vendor/libslirp/src/misc.h
@@ -9,12 +9,12 @@
#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;
+ 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
@@ -28,7 +28,7 @@ struct gfwd_list {
#define EMU_RLOGIN 0x6
#define EMU_IDENT 0x7
-#define EMU_NOCONNECT 0x10 /* Don't connect */
+#define EMU_NOCONNECT 0x10 /* Don't connect */
struct tos_t {
uint16_t lport;
@@ -54,13 +54,10 @@ 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_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);
+struct gfwd_list *add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
+ struct in_addr addr, int port);
#endif
diff --git a/vendor/libslirp/src/ncsi-pkt.h b/vendor/libslirp/src/ncsi-pkt.h
new file mode 100644
index 0000000..7795ad8
--- /dev/null
+++ b/vendor/libslirp/src/ncsi-pkt.h
@@ -0,0 +1,445 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright Gavin Shan, IBM Corporation 2016.
+ *
+ * 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 copyright holder 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef 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/qemu/slirp/src/ncsi.c b/vendor/libslirp/src/ncsi.c
index 6d574ec..6864b73 100644
--- a/qemu/slirp/src/ncsi.c
+++ b/vendor/libslirp/src/ncsi.c
@@ -58,7 +58,7 @@ static uint32_t ncsi_calculate_checksum(uint16_t *data, int len)
/* 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;
+ struct ncsi_rsp_gc_pkt *rsp = (struct ncsi_rsp_gc_pkt *)rnh;
rsp->cap = htonl(~0);
rsp->bc_cap = htonl(~0);
@@ -73,7 +73,7 @@ static int ncsi_rsp_handler_gc(struct ncsi_rsp_pkt_hdr *rnh)
/* 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;
+ struct ncsi_rsp_gls_pkt *rsp = (struct ncsi_rsp_gls_pkt *)rnh;
rsp->status = htonl(0x1);
return 0;
@@ -82,7 +82,7 @@ static int ncsi_rsp_handler_gls(struct ncsi_rsp_pkt_hdr *rnh)
/* 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;
+ 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;
@@ -94,55 +94,53 @@ static int ncsi_rsp_handler_gp(struct ncsi_rsp_pkt_hdr *rnh)
}
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 }
-};
+ 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)
+#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);
+ 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);
@@ -162,16 +160,16 @@ void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
}
}
- 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;
+ 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);
+ rnh->code = htons(NCSI_PKT_RSP_C_COMPLETED);
+ rnh->reason = htons(NCSI_PKT_RSP_R_NO_ERROR);
if (handler->handler) {
/* TODO: handle errors */
@@ -180,13 +178,13 @@ void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
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);
+ 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);
+ 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;
diff --git a/qemu/slirp/src/ndp_table.c b/vendor/libslirp/src/ndp_table.c
index 7832487..110d6ea 100644
--- a/qemu/slirp/src/ndp_table.c
+++ b/vendor/libslirp/src/ndp_table.c
@@ -7,7 +7,7 @@
#include "slirp.h"
void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
- uint8_t ethaddr[ETH_ALEN])
+ uint8_t ethaddr[ETH_ALEN])
{
char addrstr[INET6_ADDRSTRLEN];
NdpTable *ndp_table = &slirp->ndp_table;
@@ -17,9 +17,8 @@ void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
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]);
+ 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 */
@@ -40,8 +39,8 @@ void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
/* 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);
+ 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;
}
@@ -61,7 +60,8 @@ bool ndp_table_search(Slirp *slirp, struct in6_addr 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[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];
@@ -74,7 +74,7 @@ bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
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);
+ 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]);
diff --git a/vendor/libslirp/src/sbuf.c b/vendor/libslirp/src/sbuf.c
new file mode 100644
index 0000000..abced48
--- /dev/null
+++ b/vendor/libslirp/src/sbuf.c
@@ -0,0 +1,186 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ */
+
+#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/qemu/slirp/src/sbuf.h b/vendor/libslirp/src/sbuf.h
index 337af1b..1eb9f9e 100644
--- a/qemu/slirp/src/sbuf.h
+++ b/vendor/libslirp/src/sbuf.h
@@ -9,13 +9,13 @@
#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 */
+ 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 *);
diff --git a/qemu/slirp/src/slirp.c b/vendor/libslirp/src/slirp.c
index cc1215d..911a7a6 100644
--- a/qemu/slirp/src/slirp.c
+++ b/vendor/libslirp/src/slirp.c
@@ -40,9 +40,8 @@ struct in_addr loopback_addr;
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
-};
+static const uint8_t special_ethaddr[ETH_ALEN] = { 0x52, 0x55, 0x00,
+ 0x00, 0x00, 0x00 };
unsigned curtime;
@@ -55,18 +54,18 @@ static unsigned dns_addr_time;
static unsigned dns6_addr_time;
#endif
-#define TIMEOUT_FAST 2 /* milliseconds */
-#define TIMEOUT_SLOW 499 /* milliseconds */
+#define TIMEOUT_FAST 2 /* milliseconds */
+#define TIMEOUT_SLOW 499 /* milliseconds */
/* for the aging of certain requests like DNS */
-#define TIMEOUT_DEFAULT 1000 /* milliseconds */
+#define TIMEOUT_DEFAULT 1000 /* milliseconds */
#ifdef _WIN32
int get_dns_addr(struct in_addr *pdns_addr)
{
- FIXED_INFO *FixedInfo=NULL;
- ULONG BufLen;
- DWORD ret;
+ FIXED_INFO *FixedInfo = NULL;
+ ULONG BufLen;
+ DWORD ret;
IP_ADDR_STRING *pIPAddr;
struct in_addr tmp_addr;
@@ -87,7 +86,7 @@ int get_dns_addr(struct in_addr *pdns_addr)
}
if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
- printf("GetNetworkParams failed. ret = %08x\n", (unsigned)ret );
+ printf("GetNetworkParams failed. ret = %08x\n", (unsigned)ret);
if (FixedInfo) {
GlobalFree(FixedInfo);
FixedInfo = NULL;
@@ -120,8 +119,8 @@ static void winsock_cleanup(void)
#else
static int get_dns_addr_cached(void *pdns_addr, void *cached_addr,
- socklen_t addrlen,
- struct stat *cached_stat, unsigned *cached_time)
+ socklen_t addrlen, struct stat *cached_stat,
+ unsigned *cached_time)
{
struct stat old_stat;
if (curtime - *cached_time < TIMEOUT_DEFAULT) {
@@ -132,10 +131,10 @@ static int get_dns_addr_cached(void *pdns_addr, void *cached_addr,
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) {
+ 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;
}
@@ -229,8 +228,8 @@ int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id)
}
}
return get_dns_addr_resolv_conf(AF_INET6, pdns6_addr, &dns6_addr,
- sizeof(dns6_addr),
- scope_id, &dns6_addr_time);
+ sizeof(dns6_addr), scope_id,
+ &dns6_addr_time);
}
#endif
@@ -249,7 +248,7 @@ static void slirp_init_once(void)
initialized = 1;
#ifdef _WIN32
- WSAStartup(MAKEWORD(2,0), &Data);
+ WSAStartup(MAKEWORD(2, 0), &Data);
atexit(winsock_cleanup);
#endif
@@ -266,22 +265,19 @@ static void slirp_init_once(void)
};
slirp_debug = g_parse_debug_string(debug, keys, G_N_ELEMENTS(keys));
}
-
-
}
-Slirp *slirp_initx(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaque)
+Slirp *slirp_new(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaque)
{
Slirp *slirp;
- if (cfg == NULL) {
- return NULL;
- }
- if (cfg->if_mtu > IF_MTU_MAX) {
- return NULL;
- }
- if (cfg->if_mru > IF_MRU_MAX) {
- return NULL;
- }
+
+ g_return_val_if_fail(cfg != NULL, NULL);
+ g_return_val_if_fail(cfg->version >= SLIRP_CONFIG_VERSION_MIN, NULL);
+ g_return_val_if_fail(cfg->version <= SLIRP_CONFIG_VERSION_MAX, NULL);
+ g_return_val_if_fail(cfg->if_mtu >= IF_MTU_MIN || cfg->if_mtu == 0, NULL);
+ g_return_val_if_fail(cfg->if_mtu <= IF_MTU_MAX, NULL);
+ g_return_val_if_fail(cfg->if_mru >= IF_MRU_MIN || cfg->if_mru == 0, NULL);
+ g_return_val_if_fail(cfg->if_mru <= IF_MRU_MAX, NULL);
slirp = g_malloc0(sizeof(Slirp));
@@ -299,7 +295,6 @@ Slirp *slirp_initx(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaqu
ip_init(slirp);
ip6_init(slirp);
- /* Initialise mbufs *after* setting the MTU */
m_init(slirp);
slirp->vnetwork_addr = cfg->vnetwork;
@@ -310,7 +305,7 @@ Slirp *slirp_initx(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaqu
slirp->vhost_addr6 = cfg->vhost6;
if (cfg->vhostname) {
slirp_pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
- cfg->vhostname);
+ cfg->vhostname);
}
slirp->tftp_prefix = g_strdup(cfg->tftp_path);
slirp->bootp_filename = g_strdup(cfg->bootfile);
@@ -326,25 +321,25 @@ Slirp *slirp_initx(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaqu
slirp->if_mtu = cfg->if_mtu == 0 ? IF_MTU_DEFAULT : cfg->if_mtu;
slirp->if_mru = cfg->if_mru == 0 ? IF_MRU_DEFAULT : cfg->if_mru;
slirp->disable_host_loopback = cfg->disable_host_loopback;
+ slirp->enable_emu = cfg->enable_emu;
return slirp;
}
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)
+ 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)
{
SlirpConfig cfg;
memset(&cfg, 0, sizeof(cfg));
+ cfg.version = 1;
cfg.restricted = restricted;
cfg.in_enabled = in_enabled;
cfg.vnetwork = vnetwork;
@@ -363,7 +358,7 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
cfg.vnameserver6 = vnameserver6;
cfg.vdnssearch = vdnssearch;
cfg.vdomainname = vdomainname;
- return slirp_initx(&cfg, callbacks, opaque);
+ return slirp_new(&cfg, callbacks, opaque);
}
void slirp_cleanup(Slirp *slirp)
@@ -389,8 +384,10 @@ void slirp_cleanup(Slirp *slirp)
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)
+#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)
{
@@ -441,8 +438,7 @@ void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
/*
* See if we need a tcp_fasttimo
*/
- if (slirp->time_fasttimo == 0 &&
- so->so_tcpcb->t_flags & TF_DELACK) {
+ if (slirp->time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) {
slirp->time_fasttimo = curtime; /* Flag when want a fasttimo */
}
@@ -458,8 +454,8 @@ void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
* 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);
+ so->pollfds_idx = add_poll(
+ so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
continue;
}
@@ -467,8 +463,8 @@ void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
* 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);
+ so->pollfds_idx =
+ add_poll(so->s, SLIRP_POLL_OUT | SLIRP_POLL_ERR, opaque);
continue;
}
@@ -485,9 +481,9 @@ void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
* 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;
+ (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) {
@@ -526,8 +522,8 @@ void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
* (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);
+ so->pollfds_idx = add_poll(
+ so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
}
}
@@ -552,8 +548,8 @@ void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
}
if (so->so_state & SS_ISFCONNECTED) {
- so->pollfds_idx = add_poll(so->s,
- SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
+ so->pollfds_idx = add_poll(
+ so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
}
}
@@ -590,8 +586,7 @@ void slirp_pollfds_poll(Slirp *slirp, int select_error,
/*
* Check TCP sockets
*/
- for (so = slirp->tcb.so_next; so != &slirp->tcb;
- so = so_next) {
+ for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) {
int revents;
so_next = so->so_next;
@@ -655,7 +650,7 @@ void slirp_pollfds_poll(Slirp *slirp, int select_error,
/* Connected */
so->so_state &= ~SS_ISFCONNECTING;
- ret = send(so->s, (const void *) &ret, 0, 0);
+ 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 ||
@@ -692,8 +687,7 @@ void slirp_pollfds_poll(Slirp *slirp, int select_error,
* 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) {
+ for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) {
int revents;
so_next = so->so_next;
@@ -712,8 +706,7 @@ void slirp_pollfds_poll(Slirp *slirp, int select_error,
/*
* Check incoming ICMP relies.
*/
- for (so = slirp->icmp.so_next; so != &slirp->icmp;
- so = so_next) {
+ for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) {
int revents;
so_next = so->so_next;
@@ -747,7 +740,7 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
}
ar_op = ntohs(ah->ar_op);
- switch(ar_op) {
+ switch (ar_op) {
case ARPOP_REQUEST:
if (ah->ar_tip == ah->ar_sip) {
/* Gratuitous ARP */
@@ -761,7 +754,8 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
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) {
+ 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;
}
@@ -805,8 +799,8 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
if (pkt_len < ETH_HLEN)
return;
- proto = (((uint16_t) pkt[12]) << 8) + pkt[13];
- switch(proto) {
+ proto = (((uint16_t)pkt[12]) << 8) + pkt[13];
+ switch (proto) {
case ETH_P_ARP:
arp_input(slirp, pkt, pkt_len);
break;
@@ -847,7 +841,7 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
* is ready to go.
*/
static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
- uint8_t ethaddr[ETH_ALEN])
+ uint8_t ethaddr[ETH_ALEN])
{
const struct ip *iph = (const struct ip *)ifm->m_data;
@@ -910,14 +904,15 @@ static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
* is ready to go.
*/
static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
- uint8_t ethaddr[ETH_ALEN])
+ 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;
+ ifm->expiration_date =
+ slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL;
}
return 0;
} else {
@@ -934,7 +929,7 @@ static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
*/
int if_encap(Slirp *slirp, struct mbuf *ifm)
{
- uint8_t buf[IF_MTU_MAX+100];
+ uint8_t buf[IF_MTU_MAX + 100];
struct ethhdr *eh = (struct ethhdr *)buf;
uint8_t ethaddr[ETH_ALEN];
const struct ip *iph = (const struct ip *)ifm->m_data;
@@ -965,12 +960,12 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
}
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]);
+ 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;
@@ -991,8 +986,7 @@ int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
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) {
+ 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);
@@ -1023,17 +1017,17 @@ int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
}
/* TODO: IPv6 */
-static bool
-check_guestfwd(Slirp *slirp, struct in_addr *guest_addr, int guest_port)
+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);
+ (htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
}
if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) !=
- slirp->vnetwork_addr.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;
@@ -1067,8 +1061,8 @@ int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
return -1;
}
- add_guestfwd(&slirp->guestfwd_list, write_cb, opaque,
- *guest_addr, htons(guest_port));
+ add_guestfwd(&slirp->guestfwd_list, write_cb, opaque, *guest_addr,
+ htons(guest_port));
return 0;
}
@@ -1095,8 +1089,8 @@ ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
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 *slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr,
+ int guest_port)
{
struct socket *so;
@@ -1122,7 +1116,7 @@ size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
return 0;
}
- if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2)) {
+ if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen / 2)) {
return 0;
}
@@ -1149,9 +1143,9 @@ 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);
+ 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);
+ DEBUG_ERROR("send_packet() didn't send all data: %ld < %lu", (long)ret,
+ (unsigned long)len);
}
}
diff --git a/qemu/slirp/src/slirp.h b/vendor/libslirp/src/slirp.h
index fce6583..5e68d9d 100644
--- a/qemu/slirp/src/slirp.h
+++ b/vendor/libslirp/src/slirp.h
@@ -13,16 +13,16 @@
#define WIN32_LEAN_AND_MEAN
#endif
-# include <winsock2.h>
-# include <windows.h>
-# include <ws2tcpip.h>
-# include <sys/timeb.h>
-# include <iphlpapi.h>
+#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
+#if !defined(__HAIKU__)
+#define O_BINARY 0
+#endif
#endif
#ifndef _WIN32
@@ -34,7 +34,7 @@
#endif
#ifdef __APPLE__
-# include <sys/filio.h>
+#include <sys/filio.h>
#endif
/* Avoid conflicting with the libc insque() and remque(), which
@@ -45,7 +45,6 @@
#include "debug.h"
#include "util.h"
-#include "qtailq.h"
#include "libslirp.h"
#include "ip.h"
@@ -67,29 +66,29 @@
#include "bootp.h"
#include "tftp.h"
-#define ARPOP_REQUEST 1 /* ARP request */
-#define ARPOP_REPLY 2 /* ARP reply */
+#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 */
+ 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) */
+ 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 */
+ uint32_t ar_sip; /* sender IP address */
unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
- uint32_t ar_tip; /* target IP address */
+ uint32_t ar_tip; /* target IP address */
} SLIRP_PACKED;
#define ARP_TABLE_SIZE 16
@@ -105,8 +104,8 @@ 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 */
+ unsigned char eth_addr[ETH_ALEN]; /* sender hardware address */
+ struct in6_addr ip_addr; /* sender IP address */
};
#define NDP_TABLE_SIZE 16
@@ -122,7 +121,6 @@ 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;
@@ -157,13 +155,13 @@ struct Slirp {
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 */
+ 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 */
+ struct ipq ipq; /* ip reass. queue */
+ uint16_t ip_id; /* ip packet ctr, for ids */
/* bootp/dhcp states */
BOOTPClient bootp_clients[NB_BOOTP_CLIENTS];
@@ -175,8 +173,8 @@ struct Slirp {
/* 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 */
+ tcp_seq tcp_iss; /* tcp initial send seq # */
+ uint32_t tcp_now; /* for RFC 1323 timestamps */
/* udp states */
struct socket udb;
@@ -197,6 +195,8 @@ struct Slirp {
GRand *grand;
void *ra_timer;
+ bool enable_emu;
+
const SlirpCb *cb;
void *opaque;
};
@@ -219,7 +219,7 @@ extern bool slirp_do_keepalive;
#define TCP_MAXIDLE (TCPTV_KEEPCNT * TCPTV_KEEPINTVL)
/* dnssearch.c */
-int translate_dnssearch(Slirp *s, const char ** names);
+int translate_dnssearch(Slirp *s, const char **names);
/* cksum.c */
int cksum(struct mbuf *m, int len);
@@ -260,9 +260,9 @@ 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 *);
+ 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 *);
@@ -272,8 +272,8 @@ 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);
+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);
diff --git a/vendor/libslirp/src/socket.c b/vendor/libslirp/src/socket.c
new file mode 100644
index 0000000..d96d8c4
--- /dev/null
+++ b/vendor/libslirp/src/socket.c
@@ -0,0 +1,945 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ */
+
+#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;
+ size_t buf_len;
+ 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
+ */
+ buf_len = sopreprbuf(so, iov, &n);
+ assert(buf_len != 0);
+
+ 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
+ */
+ assert(size > 0);
+ 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)");
+ if (sotranslate_out(so, &addr) < 0) {
+ return -1;
+ }
+
+ /* 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
+ */
+int sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
+{
+ int rc = 0;
+ 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) {
+ goto ret;
+ }
+ }
+ if (slirp->disable_host_loopback) {
+ rc = -1;
+ errno = EPERM;
+ goto ret;
+ } else {
+ sin->sin_addr = loopback_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;
+ goto ret;
+ }
+ }
+ if (slirp->disable_host_loopback) {
+ rc = -1;
+ errno = EPERM;
+ goto ret;
+ } else {
+ sin6->sin6_addr = in6addr_loopback;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ret:
+ return rc;
+}
+
+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/vendor/libslirp/src/socket.h b/vendor/libslirp/src/socket.h
new file mode 100644
index 0000000..a6a1e5e
--- /dev/null
+++ b/vendor/libslirp/src/socket.h
@@ -0,0 +1,164 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ */
+
+#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);
+
+int 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/qemu/slirp/src/state.c b/vendor/libslirp/src/state.c
index 09cea35..4a9824e 100644
--- a/qemu/slirp/src/state.c
+++ b/vendor/libslirp/src/state.c
@@ -37,49 +37,48 @@ 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()
- }
+ .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;
@@ -111,10 +110,9 @@ static int sbuf_tmp_post_load(void *opaque, int version)
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);
+ 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;
}
@@ -128,25 +126,23 @@ static int sbuf_tmp_post_load(void *opaque, int version)
static const VMStateDescription vmstate_slirp_sbuf_tmp = {
.name = "slirp-sbuf-tmp",
.post_load = sbuf_tmp_post_load,
- .pre_save = sbuf_tmp_pre_save,
+ .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()
- }
+ .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()
- }
+ .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)
@@ -176,8 +172,8 @@ static int slirp_socket_pre_load(void *opaque)
#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)
+#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
@@ -185,12 +181,12 @@ static int slirp_socket_pre_load(void *opaque)
* and the values it contains aren't fully portable.
*/
typedef struct SS_FamilyTmpStruct {
- union slirp_sockaddr *parent;
- uint16_t portable_family;
+ 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_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)
@@ -231,24 +227,24 @@ static int ss_family_post_load(void *opaque, int version_id)
static const VMStateDescription vmstate_slirp_ss_family = {
.name = "slirp-socket-addr/ss_family",
- .pre_save = ss_family_pre_save,
+ .pre_save = ss_family_pre_save,
.post_load = ss_family_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(portable_family, SS_FamilyTmpStruct),
- VMSTATE_END_OF_LIST()
- }
+ .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),
+ .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 */
@@ -262,61 +258,57 @@ static const VMStateDescription vmstate_slirp_socket_addr = {
slirp_family_inet6),
#endif
- VMSTATE_END_OF_LIST()
- }
+ 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()
- }
+ .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()
- }
+ .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()
- }
+ .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)
@@ -345,8 +337,8 @@ void slirp_state_save(Slirp *slirp, SlirpWriteCb write_cb, void *opaque)
}
-int slirp_state_load(Slirp *slirp, int version_id,
- SlirpReadCb read_cb, void *opaque)
+int slirp_state_load(Slirp *slirp, int version_id, SlirpReadCb read_cb,
+ void *opaque)
{
struct gfwd_list *ex_ptr;
SlirpIStream f = {
@@ -358,7 +350,8 @@ int slirp_state_load(Slirp *slirp, int version_id,
int ret;
struct socket *so = socreate(slirp);
- ret = slirp_vmstate_load_state(&f, &vmstate_slirp_socket, so, version_id);
+ ret =
+ slirp_vmstate_load_state(&f, &vmstate_slirp_socket, so, version_id);
if (ret < 0) {
return ret;
}
diff --git a/qemu/slirp/src/stream.c b/vendor/libslirp/src/stream.c
index 9c1764c..6cf326f 100644
--- a/qemu/slirp/src/stream.c
+++ b/vendor/libslirp/src/stream.c
@@ -64,7 +64,7 @@ uint16_t slirp_istream_read_u16(SlirpIStream *f)
bool slirp_ostream_write_u16(SlirpOStream *f, uint16_t b)
{
- b = GUINT16_TO_BE(b);
+ b = GUINT16_TO_BE(b);
return slirp_ostream_write(f, &b, sizeof(b));
}
diff --git a/qemu/slirp/src/stream.h b/vendor/libslirp/src/stream.h
index 08bb5b6..08bb5b6 100644
--- a/qemu/slirp/src/stream.h
+++ b/vendor/libslirp/src/stream.h
diff --git a/qemu/slirp/src/tcp.h b/vendor/libslirp/src/tcp.h
index fca5c13..70a9760 100644
--- a/qemu/slirp/src/tcp.h
+++ b/vendor/libslirp/src/tcp.h
@@ -36,13 +36,13 @@
#include <glib.h>
-typedef uint32_t tcp_seq;
+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 PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */
+#define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */
-#define TCP_SNDSPACE 1024*128
-#define TCP_RCVSPACE 1024*128
+#define TCP_SNDSPACE 1024 * 128
+#define TCP_RCVSPACE 1024 * 128
#define TCP_MAXSEG_MAX 32768
/*
@@ -51,60 +51,61 @@ typedef uint32_t tcp_seq;
*/
#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 */
+ 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) */
+ uint8_t th_off : 4, /* data offset */
+ th_x2 : 4; /* (unused) */
#else
- uint8_t th_x2:4, /* (unused) */
- th_off:4; /* data offset */
+ 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 */
+ 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
+#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)
+#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 */
+#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
#undef TCP_MAXWIN
-#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */
+#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */
#undef TCP_MAX_WINSHIFT
-#define TCP_MAX_WINSHIFT 14 /* maximum window shift */
+#define TCP_MAX_WINSHIFT 14 /* maximum window shift */
/*
* User-settable options (used with setsockopt).
@@ -114,7 +115,7 @@ struct tcphdr {
* so we undefine them.
*/
#undef TCP_NODELAY
-#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */
+#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */
#undef TCP_MAXSEG
/*
@@ -122,48 +123,47 @@ struct tcphdr {
* Per RFC793, September, 1981.
*/
-#define TCP_NSTATES 11
+#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 */
+#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 */
+#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 */
+#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_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_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED)
#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED)
-#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT)
+#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)
+#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_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 */
+#define TCP_ISSINCR (125 * 1024) /* increment for tcp_iss each second */
#endif
diff --git a/vendor/libslirp/src/tcp_input.c b/vendor/libslirp/src/tcp_input.c
new file mode 100644
index 0000000..30265d6
--- /dev/null
+++ b/vendor/libslirp/src/tcp_input.c
@@ -0,0 +1,1542 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * 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.
+ */
+
+#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(so->slirp->if_mtu, so->slirp->if_mru) -
+ sizeof(struct tcphdr) - sizeof(struct ip);
+ break;
+ case AF_INET6:
+ mss = MIN(so->slirp->if_mtu, so->slirp->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 = MIN(mss, TCP_MAXSEG_MAX);
+
+ 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/vendor/libslirp/src/tcp_output.c b/vendor/libslirp/src/tcp_output.c
new file mode 100644
index 0000000..383fe31
--- /dev/null
+++ b/vendor/libslirp/src/tcp_output.c
@@ -0,0 +1,516 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * 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.
+ */
+
+#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/vendor/libslirp/src/tcp_subr.c b/vendor/libslirp/src/tcp_subr.c
new file mode 100644
index 0000000..2e32cb6
--- /dev/null
+++ b/vendor/libslirp/src/tcp_subr.c
@@ -0,0 +1,971 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * 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.
+ */
+
+#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;
+ /*
+ * 40: length of IPv4 header (20) + TCP header (20)
+ * 60: length of IPv6 header (40) + TCP header (20)
+ */
+ tp->t_maxseg =
+ MIN(so->slirp->if_mtu - ((so->so_ffamily == AF_INET) ? 40 : 60),
+ TCP_MAXSEG_MAX);
+
+ 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");
+ if (sotranslate_out(so, &addr) < 0) {
+ return -1;
+ }
+
+ /* 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 }
+};
+
+/*
+ * Return TOS according to the above table
+ */
+uint8_t tcp_tos(struct socket *so)
+{
+ int i = 0;
+
+ 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))) {
+ if (so->slirp->enable_emu)
+ so->so_emu = tcptos[i].emu;
+ return tcptos[i].tos;
+ }
+ i++;
+ }
+ 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);
+ char *eol = g_strstr_len(m->m_data, m->m_len, "\r\n");
+
+ if (!eol) {
+ return 1;
+ }
+
+ *eol = '\0';
+ if (sscanf(m->m_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);
+ m_inc(m, snprintf(NULL, 0, "%d,%d\r\n", n1, n2) + 1);
+ m->m_len = snprintf(m->m_data, M_ROOM(m), "%d,%d\r\n", n1, n2);
+ assert(m->m_len < M_ROOM(m));
+ } else {
+ *eol = '\r';
+ }
+
+ return 1;
+ }
+
+ case EMU_FTP: /* ftp */
+ m_inc(m, m->m_len + 1);
+ *(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_inc(m, m->m_len + 1);
+ *(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/vendor/libslirp/src/tcp_timer.c b/vendor/libslirp/src/tcp_timer.c
new file mode 100644
index 0000000..102023e
--- /dev/null
+++ b/vendor/libslirp/src/tcp_timer.c
@@ -0,0 +1,286 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * 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/qemu/slirp/src/tcp_timer.h b/vendor/libslirp/src/tcp_timer.h
index 709f639..584a559 100644
--- a/qemu/slirp/src/tcp_timer.h
+++ b/vendor/libslirp/src/tcp_timer.h
@@ -38,12 +38,12 @@
* Definitions of the TCP timers. These timers are counted
* down PR_SLOWHZ times a second.
*/
-#define TCPT_NTIMERS 4
+#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 */
+#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.
@@ -84,38 +84,40 @@
/*
* Time constants.
*/
-#define TCPTV_MSL ( 5*PR_SLOWHZ) /* max seg lifetime (hah!) */
+#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_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_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_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 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_LINGERTIME 120 /* linger at most 2 minutes */
-#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */
+#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); \
-}
+#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[];
diff --git a/vendor/libslirp/src/tcp_var.h b/vendor/libslirp/src/tcp_var.h
new file mode 100644
index 0000000..c8da8cb
--- /dev/null
+++ b/vendor/libslirp/src/tcp_var.h
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * 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/qemu/slirp/src/tcpip.h b/vendor/libslirp/src/tcpip.h
index 560a864..d3df021 100644
--- a/qemu/slirp/src/tcpip.h
+++ b/vendor/libslirp/src/tcpip.h
@@ -38,65 +38,67 @@
* Tcp+ip header, after ip options removed.
*/
struct tcpiphdr {
- struct mbuf_ptr ih_mbuf; /* backpointer to mbuf */
+ 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 */
+ 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;
+ 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 */
+ 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 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 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))
+#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))
+#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;
+ struct tcpiphdr dummy;
+ char first_char;
};
#endif
diff --git a/vendor/libslirp/src/tftp.c b/vendor/libslirp/src/tftp.c
new file mode 100644
index 0000000..093c2e0
--- /dev/null
+++ b/vendor/libslirp/src/tftp.c
@@ -0,0 +1,462 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * 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/qemu/slirp/src/tftp.h b/vendor/libslirp/src/tftp.h
index 3fe3b70..c47bb43 100644
--- a/qemu/slirp/src/tftp.h
+++ b/vendor/libslirp/src/tftp.h
@@ -6,32 +6,32 @@
#define TFTP_SESSIONS_MAX 20
-#define TFTP_SERVER 69
+#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_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;
+ 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 {
diff --git a/vendor/libslirp/src/udp.c b/vendor/libslirp/src/udp.c
new file mode 100644
index 0000000..35218a9
--- /dev/null
+++ b/vendor/libslirp/src/udp.c
@@ -0,0 +1,355 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * 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)) {
+ if (so->slirp->enable_emu)
+ 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/qemu/slirp/src/udp.h b/vendor/libslirp/src/udp.h
index 29c0297..c3b83fd 100644
--- a/qemu/slirp/src/udp.h
+++ b/vendor/libslirp/src/udp.h
@@ -42,35 +42,35 @@
* 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 */
+ 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 */
+ 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
+#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
+#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */
+#define UDPCTL_MAXID 2
struct mbuf;
@@ -79,14 +79,12 @@ 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);
+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);
+int udp6_output(struct socket *so, struct mbuf *m, struct sockaddr_in6 *saddr,
+ struct sockaddr_in6 *daddr);
#endif
diff --git a/qemu/slirp/src/udp6.c b/vendor/libslirp/src/udp6.c
index bfcc7ec..6f9486b 100644
--- a/qemu/slirp/src/udp6.c
+++ b/vendor/libslirp/src/udp6.c
@@ -85,7 +85,7 @@ void udp6_input(struct mbuf *m)
}
so = solookup(&slirp->udp_last_so, &slirp->udb,
- (struct sockaddr_storage *) &lhost, NULL);
+ (struct sockaddr_storage *)&lhost, NULL);
if (so == NULL) {
/* If there's no socket for this packet, create one. */
@@ -122,7 +122,7 @@ void udp6_input(struct mbuf *m)
goto bad;
}
- m_free(so->so_m); /* used for ICMP if error on sorecvfrom */
+ m_free(so->so_m); /* used for ICMP if error on sorecvfrom */
/* restore the orig mbuf packet */
m->m_len += iphlen;
@@ -135,8 +135,8 @@ bad:
m_free(m);
}
-int udp6_output(struct socket *so, struct mbuf *m,
- struct sockaddr_in6 *saddr, struct sockaddr_in6 *daddr)
+int udp6_output(struct socket *so, struct mbuf *m, struct sockaddr_in6 *saddr,
+ struct sockaddr_in6 *daddr)
{
struct ip6 *ip;
struct udphdr *uh;
diff --git a/qemu/slirp/src/util.c b/vendor/libslirp/src/util.c
index 60bb200..e596087 100644
--- a/qemu/slirp/src/util.c
+++ b/vendor/libslirp/src/util.c
@@ -111,8 +111,8 @@ static int socket_error(void)
case WSAENOTEMPTY:
return ENOTEMPTY;
case WSAEWOULDBLOCK:
- /* not using EWOULDBLOCK as we don't want code to have
- * to check both EWOULDBLOCK and EAGAIN */
+ /* not using EWOULDBLOCK as we don't want code to have
+ * to check both EWOULDBLOCK and EAGAIN */
return EAGAIN;
case WSAEINPROGRESS:
return EINPROGRESS;
@@ -256,8 +256,8 @@ int slirp_shutdown_wrap(int sockfd, int how)
}
#undef getsockopt
-int slirp_getsockopt_wrap(int sockfd, int level, int optname,
- void *optval, int *optlen)
+int slirp_getsockopt_wrap(int sockfd, int level, int optname, void *optval,
+ int *optlen)
{
int ret;
ret = getsockopt(sockfd, level, optname, optval, optlen);
@@ -280,8 +280,7 @@ int slirp_setsockopt_wrap(int sockfd, int level, int optname,
}
#undef getpeername
-int slirp_getpeername_wrap(int sockfd, struct sockaddr *addr,
- int *addrlen)
+int slirp_getpeername_wrap(int sockfd, struct sockaddr *addr, int *addrlen)
{
int ret;
ret = getpeername(sockfd, addr, addrlen);
@@ -292,8 +291,7 @@ int slirp_getpeername_wrap(int sockfd, struct sockaddr *addr,
}
#undef getsockname
-int slirp_getsockname_wrap(int sockfd, struct sockaddr *addr,
- int *addrlen)
+int slirp_getsockname_wrap(int sockfd, struct sockaddr *addr, int *addrlen)
{
int ret;
ret = getsockname(sockfd, addr, addrlen);
@@ -316,7 +314,7 @@ ssize_t slirp_send_wrap(int sockfd, const void *buf, size_t len, int flags)
#undef sendto
ssize_t slirp_sendto_wrap(int sockfd, const void *buf, size_t len, int flags,
- const struct sockaddr *addr, int addrlen)
+ const struct sockaddr *addr, int addrlen)
{
int ret;
ret = sendto(sockfd, buf, len, flags, addr, addrlen);
@@ -358,7 +356,7 @@ void slirp_pstrcpy(char *buf, int buf_size, const char *str)
if (buf_size <= 0)
return;
- for(;;) {
+ for (;;) {
c = *str++;
if (c == 0 || q >= buf + buf_size - 1)
break;
diff --git a/qemu/slirp/src/util.h b/vendor/libslirp/src/util.h
index 01f1e0e..3c6223c 100644
--- a/qemu/slirp/src/util.h
+++ b/vendor/libslirp/src/util.h
@@ -43,44 +43,49 @@
#include <netinet/in.h>
#endif
-#if defined(_WIN32)
-# define SLIRP_PACKED __attribute__((gcc_struct, packed))
+#if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__))
+#define SLIRP_PACKED __attribute__((gcc_struct, packed))
#else
-# define SLIRP_PACKED __attribute__((packed))
+#define SLIRP_PACKED __attribute__((packed))
#endif
#ifndef DIV_ROUND_UP
-#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+#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))); })
+#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 */
+#if !defined(IOV_MAX) /* XXX: to avoid duplicate with QEMU osdep.h */
struct iovec {
void *iov_base;
size_t iov_len;
};
-# endif
+#endif
#else
#include <sys/uio.h>
#endif
+#define stringify(s) tostring(s)
+#define tostring(s) #s
+
#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)
+#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
@@ -134,8 +139,8 @@ 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);
+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);
diff --git a/vendor/libslirp/src/version.c b/vendor/libslirp/src/version.c
new file mode 100644
index 0000000..a837323
--- /dev/null
+++ b/vendor/libslirp/src/version.c
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+#include "libslirp.h"
+#include "util.h"
+
+const char *
+slirp_version_string(void)
+{
+ return stringify(SLIRP_MAJOR_VERSION) "."
+ stringify(SLIRP_MINOR_VERSION) "."
+ stringify(SLIRP_MICRO_VERSION);
+}
diff --git a/qemu/slirp/src/vmstate.c b/vendor/libslirp/src/vmstate.c
index 43bb3eb..8c544eb 100644
--- a/qemu/slirp/src/vmstate.c
+++ b/vendor/libslirp/src/vmstate.c
@@ -49,7 +49,7 @@ 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;
+ return 0;
}
g_warning("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
return -EINVAL;
@@ -69,20 +69,22 @@ static int put_nullptr(SlirpOStream *f, void *pv, size_t size,
const VMStateInfo slirp_vmstate_info_nullptr = {
.name = "uint64",
- .get = get_nullptr,
- .put = put_nullptr,
+ .get = get_nullptr,
+ .put = put_nullptr,
};
/* 8 bit unsigned int */
-static int get_uint8(SlirpIStream *f, void *pv, size_t size, const VMStateField *field)
+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)
+static int put_uint8(SlirpOStream *f, void *pv, size_t size,
+ const VMStateField *field)
{
uint8_t *v = pv;
slirp_ostream_write_u8(f, *v);
@@ -91,8 +93,8 @@ static int put_uint8(SlirpOStream *f, void *pv, size_t size, const VMStateField
const VMStateInfo slirp_vmstate_info_uint8 = {
.name = "uint8",
- .get = get_uint8,
- .put = put_uint8,
+ .get = get_uint8,
+ .put = put_uint8,
};
/* 16 bit unsigned int */
@@ -115,8 +117,8 @@ static int put_uint16(SlirpOStream *f, void *pv, size_t size,
const VMStateInfo slirp_vmstate_info_uint16 = {
.name = "uint16",
- .get = get_uint16,
- .put = put_uint16,
+ .get = get_uint16,
+ .put = put_uint16,
};
/* 32 bit unsigned int */
@@ -139,20 +141,22 @@ static int put_uint32(SlirpOStream *f, void *pv, size_t size,
const VMStateInfo slirp_vmstate_info_uint32 = {
.name = "uint32",
- .get = get_uint32,
- .put = put_uint32,
+ .get = get_uint32,
+ .put = put_uint32,
};
/* 16 bit int */
-static int get_int16(SlirpIStream *f, void *pv, size_t size, const VMStateField *field)
+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)
+static int put_int16(SlirpOStream *f, void *pv, size_t size,
+ const VMStateField *field)
{
int16_t *v = pv;
slirp_ostream_write_i16(f, *v);
@@ -161,20 +165,22 @@ static int put_int16(SlirpOStream *f, void *pv, size_t size, const VMStateField
const VMStateInfo slirp_vmstate_info_int16 = {
.name = "int16",
- .get = get_int16,
- .put = put_int16,
+ .get = get_int16,
+ .put = put_int16,
};
/* 32 bit int */
-static int get_int32(SlirpIStream *f, void *pv, size_t size, const VMStateField *field)
+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)
+static int put_int32(SlirpOStream *f, void *pv, size_t size,
+ const VMStateField *field)
{
int32_t *v = pv;
slirp_ostream_write_i32(f, *v);
@@ -183,8 +189,8 @@ static int put_int32(SlirpOStream *f, void *pv, size_t size, const VMStateField
const VMStateInfo slirp_vmstate_info_int32 = {
.name = "int32",
- .get = get_int32,
- .put = put_int32,
+ .get = get_int32,
+ .put = put_int32,
};
/* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
@@ -193,7 +199,8 @@ const VMStateInfo slirp_vmstate_info_int32 = {
* 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)
+static int get_tmp(SlirpIStream *f, void *pv, size_t size,
+ const VMStateField *field)
{
int ret;
const VMStateDescription *vmsd = field->vmsd;
@@ -207,7 +214,8 @@ static int get_tmp(SlirpIStream *f, void *pv, size_t size, const VMStateField *f
return ret;
}
-static int put_tmp(SlirpOStream *f, void *pv, size_t size, const VMStateField *field)
+static int put_tmp(SlirpOStream *f, void *pv, size_t size,
+ const VMStateField *field)
{
const VMStateDescription *vmsd = field->vmsd;
void *tmp = g_malloc(size);
@@ -245,8 +253,8 @@ static int put_buffer(SlirpOStream *f, void *pv, size_t size,
const VMStateInfo slirp_vmstate_info_buffer = {
.name = "buffer",
- .get = get_buffer,
- .put = put_buffer,
+ .get = get_buffer,
+ .put = put_buffer,
};
static int vmstate_n_elems(void *opaque, const VMStateField *field)
@@ -286,9 +294,8 @@ static int vmstate_size(void *opaque, const VMStateField *field)
return size;
}
-static int
-vmstate_save_state_v(SlirpOStream *f, const VMStateDescription *vmsd,
- void *opaque, int version_id)
+static int vmstate_save_state_v(SlirpOStream *f, const VMStateDescription *vmsd,
+ void *opaque, int version_id)
{
int ret = 0;
const VMStateField *field = vmsd->fields;
@@ -302,10 +309,8 @@ vmstate_save_state_v(SlirpOStream *f, const VMStateDescription *vmsd,
}
while (field->name) {
- if ((field->field_exists &&
- field->field_exists(opaque, version_id)) ||
- (!field->field_exists &&
- field->version_id <= version_id)) {
+ 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);
@@ -325,7 +330,8 @@ vmstate_save_state_v(SlirpOStream *f, const VMStateDescription *vmsd,
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);
+ 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) {
@@ -335,15 +341,15 @@ vmstate_save_state_v(SlirpOStream *f, const VMStateDescription *vmsd,
ret = field->info->put(f, curr_elem, size, field);
}
if (ret) {
- g_warning("Save of field %s/%s failed",
- vmsd->name, field->name);
+ 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);
+ g_warning("Output state validation failed: %s/%s", vmsd->name,
+ field->name);
assert(!(field->flags & VMS_MUST_EXIST));
}
}
@@ -389,10 +395,8 @@ int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd,
}
}
while (field->name) {
- if ((field->field_exists &&
- field->field_exists(opaque, version_id)) ||
- (!field->field_exists &&
- field->version_id <= version_id)) {
+ 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);
@@ -411,25 +415,25 @@ int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd,
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);
+ 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);
+ field->vmsd->version_id);
} else if (field->flags & VMS_VSTRUCT) {
ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem,
- field->struct_version_id);
+ 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);
+ 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);
+ g_warning("Input validation failed: %s/%s", vmsd->name,
+ field->name);
return -1;
}
field++;
diff --git a/qemu/slirp/src/vmstate.h b/vendor/libslirp/src/vmstate.h
index 44efea7..94c6a4b 100644
--- a/qemu/slirp/src/vmstate.h
+++ b/vendor/libslirp/src/vmstate.h
@@ -66,13 +66,15 @@ int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd,
*/
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);
+ 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,
+ VMS_SINGLE = 0x001,
/* The struct member at opaque + VMStateField.offset is a pointer
* to the actual field (e.g. struct a { uint8_t *b;
@@ -81,7 +83,7 @@ enum VMStateFlags {
* affect the meaning of VMStateField.num_offset or
* VMStateField.size_offset; see VMS_VARRAY* and VMS_VBUFFER for
* those. */
- VMS_POINTER = 0x002,
+ 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
@@ -91,23 +93,23 @@ enum VMStateFlags {
* (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,
+ 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,
+ 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,
+ VMS_VARRAY_INT32 = 0x010,
/* Ignored */
- VMS_BUFFER = 0x020,
+ 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
@@ -120,7 +122,7 @@ enum VMStateFlags {
* 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,
+ 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
@@ -128,38 +130,38 @@ enum VMStateFlags {
* 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,
+ 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,
+ 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,
+ 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,
+ VMS_VARRAY_UINT32 = 0x800,
/* Fail loading the serialised VM state if this field is missing
* from the input. */
- VMS_MUST_EXIST = 0x1000,
+ 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,
+ VMS_ALLOC = 0x2000,
/* Multiply the number of entries given by the integer at opaque +
* VMStateField.num_offset (see VMS_VARRAY*) with VMStateField.num
@@ -170,7 +172,7 @@ enum VMStateFlags {
/* 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,
+ VMS_VSTRUCT = 0x8000,
};
struct VMStateField {
@@ -212,25 +214,24 @@ 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 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 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_value(_state, _field, _type) \
+ (offsetof(_state, _field) + type_check(_type, typeof_field(_state, _field)))
-#define vmstate_offset_pointer(_state, _field, _type) \
- (offsetof(_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) + \
+#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, \
+#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
@@ -252,83 +253,71 @@ extern const VMStateInfo slirp_vmstate_info_tmp;
* 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 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 QEMU_BUILD_BUG_ON_ZERO(x) (sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)) - \
- sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)))
+#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
@@ -338,72 +327,65 @@ extern const VMStateInfo slirp_vmstate_info_tmp;
* '_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) \
+#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) \
+#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) \
+#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)
+ VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version, _vmsd, \
+ _type)
-#define VMSTATE_INT16_V(_f, _s, _v) \
+#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) \
+#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) \
+#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) \
+#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) \
+#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_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_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) \
+#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) \
+#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) \
+#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_INT16_ARRAY(_f, _s, _n) VMSTATE_INT16_ARRAY_V(_f, _s, _n, 0)
-#define VMSTATE_BUFFER_V(_f, _s, _v) \
+#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_BUFFER(_f, _s) VMSTATE_BUFFER_V(_f, _s, 0)
-#define VMSTATE_END_OF_LIST() \
- {}
+#define VMSTATE_END_OF_LIST() \
+ { \
+ }
#endif
diff --git a/parson/LICENSE b/vendor/parson/LICENSE
index aed1c9b..12cbc1b 100644
--- a/parson/LICENSE
+++ b/vendor/parson/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2012 - 2017 Krzysztof Gabis
+Copyright (c) 2012 - 2019 Krzysztof Gabis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/vendor/parson/README.md b/vendor/parson/README.md
new file mode 100644
index 0000000..56d2de3
--- /dev/null
+++ b/vendor/parson/README.md
@@ -0,0 +1,149 @@
+## About
+Parson is a lighweight [json](http://json.org) library written in C.
+
+## Features
+* Full JSON support
+* Lightweight (only 2 files)
+* Simple API
+* Addressing json values with dot notation (similar to C structs or objects in most OO languages, e.g. "objectA.objectB.value")
+* C89 compatible
+* Test suites
+
+## Installation
+Run:
+```
+git clone https://github.com/kgabis/parson.git
+```
+and copy parson.h and parson.c to you source code tree.
+
+Run ```make test``` to compile and run tests.
+
+## Examples
+### Parsing JSON
+Here is a function, which prints basic commit info (date, sha and author) from a github repository.
+```c
+void print_commits_info(const char *username, const char *repo) {
+ JSON_Value *root_value;
+ JSON_Array *commits;
+ JSON_Object *commit;
+ size_t i;
+
+ char curl_command[512];
+ char cleanup_command[256];
+ char output_filename[] = "commits.json";
+
+ /* it ain't pretty, but it's not a libcurl tutorial */
+ sprintf(curl_command,
+ "curl -s \"https://api.github.com/repos/%s/%s/commits\" > %s",
+ username, repo, output_filename);
+ sprintf(cleanup_command, "rm -f %s", output_filename);
+ system(curl_command);
+
+ /* parsing json and validating output */
+ root_value = json_parse_file(output_filename);
+ if (json_value_get_type(root_value) != JSONArray) {
+ system(cleanup_command);
+ return;
+ }
+
+ /* getting array from root value and printing commit info */
+ commits = json_value_get_array(root_value);
+ printf("%-10.10s %-10.10s %s\n", "Date", "SHA", "Author");
+ for (i = 0; i < json_array_get_count(commits); i++) {
+ commit = json_array_get_object(commits, i);
+ printf("%.10s %.10s %s\n",
+ json_object_dotget_string(commit, "commit.author.date"),
+ json_object_get_string(commit, "sha"),
+ json_object_dotget_string(commit, "commit.author.name"));
+ }
+
+ /* cleanup code */
+ json_value_free(root_value);
+ system(cleanup_command);
+}
+
+```
+Calling ```print_commits_info("torvalds", "linux");``` prints:
+```
+Date SHA Author
+2012-10-15 dd8e8c4a2c David Rientjes
+2012-10-15 3ce9e53e78 Michal Marek
+2012-10-14 29bb4cc5e0 Randy Dunlap
+2012-10-15 325adeb55e Ralf Baechle
+2012-10-14 68687c842c Russell King
+2012-10-14 ddffeb8c4d Linus Torvalds
+...
+```
+
+### Persistence
+In this example I'm using parson to save user information to a file and then load it and validate later.
+```c
+void persistence_example(void) {
+ JSON_Value *schema = json_parse_string("{\"name\":\"\"}");
+ JSON_Value *user_data = json_parse_file("user_data.json");
+ char buf[256];
+ const char *name = NULL;
+ if (user_data == NULL || json_validate(schema, user_data) != JSONSuccess) {
+ puts("Enter your name:");
+ scanf("%s", buf);
+ user_data = json_value_init_object();
+ json_object_set_string(json_object(user_data), "name", buf);
+ json_serialize_to_file(user_data, "user_data.json");
+ }
+ name = json_object_get_string(json_object(user_data), "name");
+ printf("Hello, %s.", name);
+ json_value_free(schema);
+ json_value_free(user_data);
+ return;
+}
+```
+
+### Serialization
+Creating JSON values is very simple thanks to the dot notation.
+Object hierarchy is automatically created when addressing specific fields.
+In the following example I create a simple JSON value containing basic information about a person.
+```c
+void serialization_example(void) {
+ JSON_Value *root_value = json_value_init_object();
+ JSON_Object *root_object = json_value_get_object(root_value);
+ char *serialized_string = NULL;
+ json_object_set_string(root_object, "name", "John Smith");
+ json_object_set_number(root_object, "age", 25);
+ json_object_dotset_string(root_object, "address.city", "Cupertino");
+ json_object_dotset_value(root_object, "contact.emails", json_parse_string("[\"email@example.com\",\"email2@example.com\"]"));
+ serialized_string = json_serialize_to_string_pretty(root_value);
+ puts(serialized_string);
+ json_free_serialized_string(serialized_string);
+ json_value_free(root_value);
+}
+
+```
+
+Output:
+```
+{
+ "name": "John Smith",
+ "age": 25,
+ "address": {
+ "city": "Cupertino"
+ },
+ "contact": {
+ "emails": [
+ "email@example.com",
+ "email2@example.com"
+ ]
+ }
+}
+```
+
+## Contributing
+
+I will always merge *working* bug fixes. However, if you want to add something new to the API, please create an "issue" on github for this first so we can discuss if it should end up in the library before you start implementing it.
+Remember to follow parson's code style and write appropriate tests.
+
+## My other projects
+* [kgflags](https://github.com/kgabis/kgflags) - easy to use command-line flag parsing library
+* [agnes](https://github.com/kgabis/agnes) - header-only NES emulation library
+
+## License
+[The MIT License (MIT)](http://opensource.org/licenses/mit-license.php)
diff --git a/parson/parson.c b/vendor/parson/parson.c
index afbfd2d..95d97ea 100644
--- a/parson/parson.c
+++ b/vendor/parson/parson.c
@@ -1,6 +1,8 @@
/*
+ SPDX-License-Identifier: MIT
+
Parson ( http://kgabis.github.com/parson/ )
- Copyright (c) 2012 - 2017 Krzysztof Gabis
+ Copyright (c) 2012 - 2019 Krzysztof Gabis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -62,6 +64,8 @@
static JSON_Malloc_Function parson_malloc = malloc;
static JSON_Free_Function parson_free = free;
+static int parson_escape_slashes = 1;
+
#define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */
/* Type definitions */
@@ -1018,7 +1022,6 @@ static int json_serialize_string(const char *string, char *buf) {
switch (c) {
case '\"': APPEND_STRING("\\\""); break;
case '\\': APPEND_STRING("\\\\"); break;
- case '/': APPEND_STRING("\\/"); break; /* to make json embeddable in xml\/html */
case '\b': APPEND_STRING("\\b"); break;
case '\f': APPEND_STRING("\\f"); break;
case '\n': APPEND_STRING("\\n"); break;
@@ -1056,6 +1059,13 @@ static int json_serialize_string(const char *string, char *buf) {
case '\x1d': APPEND_STRING("\\u001d"); break;
case '\x1e': APPEND_STRING("\\u001e"); break;
case '\x1f': APPEND_STRING("\\u001f"); break;
+ case '/':
+ if (parson_escape_slashes) {
+ APPEND_STRING("\\/"); /* to make json embeddable in xml\/html */
+ } else {
+ APPEND_STRING("/");
+ }
+ break;
default:
if (buf != NULL) {
buf[0] = c;
@@ -2044,3 +2054,7 @@ void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Fu
parson_malloc = malloc_fun;
parson_free = free_fun;
}
+
+void json_set_escape_slashes(int escape_slashes) {
+ parson_escape_slashes = escape_slashes;
+}
diff --git a/parson/parson.h b/vendor/parson/parson.h
index f97f711..186fcb0 100644
--- a/parson/parson.h
+++ b/vendor/parson/parson.h
@@ -1,6 +1,8 @@
/*
+ SPDX-License-Identifier: MIT
+
Parson ( http://kgabis.github.com/parson/ )
- Copyright (c) 2012 - 2017 Krzysztof Gabis
+ Copyright (c) 2012 - 2019 Krzysztof Gabis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -60,6 +62,10 @@ typedef void (*JSON_Free_Function)(void *);
from stdlib will be used for all allocations */
void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun);
+/* Sets if slashes should be escaped or not when serializing JSON. By default slashes are escaped.
+ This function sets a global setting and is not thread safe. */
+void json_set_escape_slashes(int escape_slashes);
+
/* Parses first JSON value in a file, returns NULL in case of error */
JSON_Value * json_parse_file(const char *filename);