diff --git a/.gitignore b/.gitignore index 72537aa..9bf151b 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ /qemu-5.2.0-rc1.tar.xz /qemu-5.2.0-rc3.tar.xz /qemu-5.2.0.tar.xz +/qemu-6.0.0.tar.xz diff --git a/0001-redhat-Adding-slirp-to-the-exploded-tree.patch b/0001-redhat-Adding-slirp-to-the-exploded-tree.patch deleted file mode 100644 index 4895179..0000000 --- a/0001-redhat-Adding-slirp-to-the-exploded-tree.patch +++ /dev/null @@ -1,17001 +0,0 @@ -From f04f3d3ab0bb9ffd06a16ee5157f08bcb4f5f459 Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Wed, 2 Dec 2020 07:38:31 +0100 -Subject: redhat: Adding slirp to the exploded tree - -RH-Author: Danilo de Paula -Message-id: <20190907020756.8619-1-ddepaula@redhat.com> -Patchwork-id: 90309 -O-Subject: [RHEL-AV-8.1.0 qemu-kvm PATCH 1/1] redhat: Adding slirp to the exploded tree -Bugzilla: -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Wainer dos Santos Moschetta - -Until qemu-kvm-3.1 slirp used to live as a regular folder in qemu-kvm. -After that it got moved into its own submodule. Which means it's not -part of the qemu-kvm git tree anymore. - -This passed unoticed for RHEL-AV-8.0.1 and 8.1.0 because qemu still ships -the code in the tarball. That's why scratch builds still works (it's based in -the tarball content). - -As we're receiving some CVE's against slirp, we need a way to patch -slirp in RHEL-8.1.0 without handling as a separate package (as we do for -firmwares). - -The simplest solution is to copy the slirp folder from the tarball into the -exploded tree. - -To be able to do that, I had to make some changes: - -slirp needs to be removed from .gitmodules, otherwise git complains -about files on it. - -Since "make -C redhat rh-brew" uses the tarball and apply all the -patches on top of it, we need to remove the folder from the tarball before applying -the patch (because we are actually re-applying them). - -We also need to use --ignore-submodule while generating the patches for -scratch-build, otherwise it will include some weird definition of the -slirp folder in the patch, something that /usr/bin/patch gets mad with. - -After that I compared the patch list, after and before this change, and -saw no major differences. - -This is an exploded-tree-only change and shouldn't be applied to dist-git. - -Signed-off-by: Danilo C. L. de Paula - -Rebase notes (5.1.0-rc2): - - Update slirp directory to commit ce94eba2042d52a0ba3d9e252ebce86715e94275 (used upstream) - -Rebase notes (5.2.0-rc4): - - Update slirp directory to commit 8f43a99191afb47ca3f3c6972f6306209f367ece (used upstream) ---- - .gitmodules | 3 - - slirp/.clang-format | 58 ++ - slirp/.gitignore | 10 + - slirp/.gitlab-ci.yml | 27 + - slirp/CHANGELOG.md | 88 ++ - slirp/COPYRIGHT | 62 ++ - slirp/Makefile | 62 ++ - slirp/README.md | 60 ++ - slirp/build-aux/git-version-gen | 158 ++++ - slirp/build-aux/meson-dist | 16 + - slirp/meson.build | 134 +++ - slirp/src/arp_table.c | 92 ++ - slirp/src/bootp.c | 369 ++++++++ - slirp/src/bootp.h | 129 +++ - slirp/src/cksum.c | 179 ++++ - slirp/src/debug.h | 51 + - slirp/src/dhcpv6.c | 224 +++++ - slirp/src/dhcpv6.h | 68 ++ - slirp/src/dnssearch.c | 306 ++++++ - slirp/src/if.c | 213 +++++ - slirp/src/if.h | 25 + - slirp/src/ip.h | 242 +++++ - slirp/src/ip6.h | 214 +++++ - slirp/src/ip6_icmp.c | 433 +++++++++ - slirp/src/ip6_icmp.h | 219 +++++ - slirp/src/ip6_input.c | 85 ++ - slirp/src/ip6_output.c | 39 + - slirp/src/ip_icmp.c | 492 ++++++++++ - slirp/src/ip_icmp.h | 166 ++++ - slirp/src/ip_input.c | 461 +++++++++ - slirp/src/ip_output.c | 169 ++++ - slirp/src/libslirp-version.h.in | 24 + - slirp/src/libslirp.h | 171 ++++ - slirp/src/libslirp.map | 30 + - slirp/src/main.h | 16 + - slirp/src/mbuf.c | 224 +++++ - slirp/src/mbuf.h | 127 +++ - slirp/src/misc.c | 390 ++++++++ - slirp/src/misc.h | 72 ++ - slirp/src/ncsi-pkt.h | 445 +++++++++ - slirp/src/ncsi.c | 197 ++++ - slirp/src/ndp_table.c | 87 ++ - slirp/src/sbuf.c | 168 ++++ - slirp/src/sbuf.h | 27 + - slirp/src/slirp.c | 1189 ++++++++++++++++++++++++ - slirp/src/slirp.h | 284 ++++++ - slirp/src/socket.c | 954 +++++++++++++++++++ - slirp/src/socket.h | 164 ++++ - slirp/src/state.c | 379 ++++++++ - slirp/src/stream.c | 120 +++ - slirp/src/stream.h | 35 + - slirp/src/tcp.h | 169 ++++ - slirp/src/tcp_input.c | 1539 +++++++++++++++++++++++++++++++ - slirp/src/tcp_output.c | 516 +++++++++++ - slirp/src/tcp_subr.c | 980 ++++++++++++++++++++ - slirp/src/tcp_timer.c | 286 ++++++ - slirp/src/tcp_timer.h | 130 +++ - slirp/src/tcp_var.h | 161 ++++ - slirp/src/tcpip.h | 104 +++ - slirp/src/tftp.c | 464 ++++++++++ - slirp/src/tftp.h | 54 ++ - slirp/src/udp.c | 365 ++++++++ - slirp/src/udp.h | 90 ++ - slirp/src/udp6.c | 173 ++++ - slirp/src/util.c | 428 +++++++++ - slirp/src/util.h | 189 ++++ - slirp/src/version.c | 8 + - slirp/src/vmstate.c | 444 +++++++++ - slirp/src/vmstate.h | 391 ++++++++ - 69 files changed, 16445 insertions(+), 3 deletions(-) - create mode 100644 slirp/.clang-format - create mode 100644 slirp/.gitignore - create mode 100644 slirp/.gitlab-ci.yml - create mode 100644 slirp/CHANGELOG.md - create mode 100644 slirp/COPYRIGHT - create mode 100644 slirp/Makefile - create mode 100644 slirp/README.md - create mode 100755 slirp/build-aux/git-version-gen - create mode 100755 slirp/build-aux/meson-dist - create mode 100644 slirp/meson.build - create mode 100644 slirp/src/arp_table.c - create mode 100644 slirp/src/bootp.c - create mode 100644 slirp/src/bootp.h - create mode 100644 slirp/src/cksum.c - create mode 100644 slirp/src/debug.h - create mode 100644 slirp/src/dhcpv6.c - create mode 100644 slirp/src/dhcpv6.h - create mode 100644 slirp/src/dnssearch.c - create mode 100644 slirp/src/if.c - create mode 100644 slirp/src/if.h - create mode 100644 slirp/src/ip.h - create mode 100644 slirp/src/ip6.h - create mode 100644 slirp/src/ip6_icmp.c - create mode 100644 slirp/src/ip6_icmp.h - create mode 100644 slirp/src/ip6_input.c - create mode 100644 slirp/src/ip6_output.c - create mode 100644 slirp/src/ip_icmp.c - create mode 100644 slirp/src/ip_icmp.h - create mode 100644 slirp/src/ip_input.c - create mode 100644 slirp/src/ip_output.c - create mode 100644 slirp/src/libslirp-version.h.in - create mode 100644 slirp/src/libslirp.h - create mode 100644 slirp/src/libslirp.map - create mode 100644 slirp/src/main.h - create mode 100644 slirp/src/mbuf.c - create mode 100644 slirp/src/mbuf.h - create mode 100644 slirp/src/misc.c - create mode 100644 slirp/src/misc.h - create mode 100644 slirp/src/ncsi-pkt.h - create mode 100644 slirp/src/ncsi.c - create mode 100644 slirp/src/ndp_table.c - create mode 100644 slirp/src/sbuf.c - create mode 100644 slirp/src/sbuf.h - create mode 100644 slirp/src/slirp.c - create mode 100644 slirp/src/slirp.h - create mode 100644 slirp/src/socket.c - create mode 100644 slirp/src/socket.h - create mode 100644 slirp/src/state.c - create mode 100644 slirp/src/stream.c - create mode 100644 slirp/src/stream.h - create mode 100644 slirp/src/tcp.h - create mode 100644 slirp/src/tcp_input.c - create mode 100644 slirp/src/tcp_output.c - create mode 100644 slirp/src/tcp_subr.c - create mode 100644 slirp/src/tcp_timer.c - create mode 100644 slirp/src/tcp_timer.h - create mode 100644 slirp/src/tcp_var.h - create mode 100644 slirp/src/tcpip.h - create mode 100644 slirp/src/tftp.c - create mode 100644 slirp/src/tftp.h - create mode 100644 slirp/src/udp.c - create mode 100644 slirp/src/udp.h - create mode 100644 slirp/src/udp6.c - create mode 100644 slirp/src/util.c - create mode 100644 slirp/src/util.h - create mode 100644 slirp/src/version.c - create mode 100644 slirp/src/vmstate.c - create mode 100644 slirp/src/vmstate.h - -diff --git a/slirp/.clang-format b/slirp/.clang-format -new file mode 100644 -index 0000000000..17fb49fe65 ---- /dev/null -+++ b/slirp/.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/slirp/CHANGELOG.md b/slirp/CHANGELOG.md -new file mode 100644 -index 0000000000..67b0a74195 ---- /dev/null -+++ b/slirp/CHANGELOG.md -@@ -0,0 +1,88 @@ -+# Changelog -+ -+All notable changes to this project will be documented in this file. -+ -+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -+ -+## [Unreleased] -+ -+### Added -+ -+### Changed -+ -+### Deprecated -+ -+### Fixed -+ -+## [4.2.0] - 2020-03-17 -+ -+### Added -+ -+ - New API function `slirp_add_unix`: add a forward rule to a Unix socket. -+ - New API function `slirp_remove_guestfwd`: remove a forward rule previously -+ added by `slirp_add_exec`, `slirp_add_unix` or `slirp_add_guestfwd` -+ - New SlirpConfig.outbound_addr{,6} fields to bind output socket to a -+ specific address -+ -+### Changed -+ -+ - socket: do not fallback on host loopback if get_dns_addr() failed -+ or the address is in slirp network -+ -+### Fixed -+ -+ - ncsi: fix checksum OOB memory access -+ - `tcp_emu()`: fix OOB accesses -+ - tftp: restrict relative path access -+ - state: fix loading of guestfwd state -+ -+## [4.1.0] - 2019-12-02 -+ -+### Added -+ -+ - The `slirp_new()` API, simpler and more extensible than `slirp_init()`. -+ - Allow custom MTU configuration. -+ - Option to disable host loopback connections. -+ - CI now runs scan-build too. -+ -+### Changed -+ -+ - Disable `tcp_emu()` by default. `tcp_emu()` is known to have caused -+ several CVEs, and not useful today in most cases. The feature can -+ be still enabled by setting `SlirpConfig.enable_emu` to true. -+ - meson build system is now `subproject()` friendly. -+ - Replace remaining `malloc()`/`free()` with glib (which aborts on OOM) -+ - Various code cleanups. -+ -+### Deprecated -+ -+ - The `slirp_init()` API. -+ -+### Fixed -+ -+ - `getpeername()` error after `shutdown(SHUT_WR)`. -+ - Exec forward: correctly parse command lines that contain spaces. -+ - Allow 0.0.0.0 destination address. -+ - Make host receive broadcast packets. -+ - Various memory related fixes (heap overflow, leaks, NULL -+ dereference). -+ - Compilation warnings, dead code. -+ -+## [4.0.0] - 2019-05-24 -+ -+### Added -+ -+ - Installable as a shared library. -+ - meson build system -+ (& make build system for in-tree QEMU integration) -+ -+### Changed -+ -+ - Standalone project, removing any QEMU dependency. -+ - License clarifications. -+ -+[unreleased]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.2.0...master -+[4.2.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.1.0...v4.2.0 -+[4.1.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.0.0...v4.1.0 -+[4.0.0]: https://gitlab.freedesktop.org/slirp/libslirp/commits/v4.0.0 -diff --git a/slirp/COPYRIGHT b/slirp/COPYRIGHT -new file mode 100644 -index 0000000000..ed49512dbc ---- /dev/null -+++ b/slirp/COPYRIGHT -@@ -0,0 +1,62 @@ -+Slirp was written by Danny Gasparovski. -+Copyright (c), 1995,1996 All Rights Reserved. -+ -+Slirp is free software; "free" as in you don't have to pay for it, and you -+are free to do whatever you want with it. I do not accept any donations, -+monetary or otherwise, for Slirp. Instead, I would ask you to pass this -+potential donation to your favorite charity. In fact, I encourage -+*everyone* who finds Slirp useful to make a small donation to their -+favorite charity (for example, GreenPeace). This is not a requirement, but -+a suggestion from someone who highly values the service they provide. -+ -+The copyright terms and conditions: -+ -+---BEGIN--- -+ -+ Copyright (c) 1995,1996 Danny Gasparovski. 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 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 ``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 -+ DANNY GASPAROVSKI 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. -+ -+---END--- -+ -+This basically means you can do anything you want with the software, except -+1) call it your own, and 2) claim warranty on it. There is no warranty for -+this software. None. Nada. If you lose a million dollars while using -+Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***. -+ -+If these conditions cannot be met due to legal restrictions (E.g. where it -+is against the law to give out Software without warranty), you must cease -+using the software and delete all copies you have. -+ -+Slirp uses code that is copyrighted by the following people/organizations: -+ -+Juha Pirkola. -+Gregory M. Christy. -+The Regents of the University of California. -+Carnegie Mellon University. -+The Australian National University. -+RSA Data Security, Inc. -+ -+Please read the top of each source file for the details on the various -+copyrights. -diff --git a/slirp/Makefile b/slirp/Makefile -new file mode 100644 -index 0000000000..8857b4159b ---- /dev/null -+++ b/slirp/Makefile -@@ -0,0 +1,62 @@ -+ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) -+BUILD_DIR ?= . -+ -+LIBSLIRP = $(BUILD_DIR)/libslirp.a -+SLIRP_MAJOR_VERSION = 4 -+SLIRP_MINOR_VERSION = 2 -+SLIRP_MICRO_VERSION = 0 -+SLIRP_VERSION_STRING = "$(SLIRP_MAJOR_VERSION).$(SLIRP_MINOR_VERSION).$(SLIRP_MICRO_VERSION)-git" -+ -+all: $(LIBSLIRP) -+ -+SRCS := $(wildcard src/*.c) -+OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o) -+DEPS := $(OBJS:%.o=%.d) -+ -+INC_DIRS := $(BUILD_DIR)/src -+INC_FLAGS := $(addprefix -I,$(INC_DIRS)) -+ -+override CFLAGS += \ -+ -DG_LOG_DOMAIN='"Slirp"' \ -+ $(shell $(PKG_CONFIG) --cflags glib-2.0) \ -+ $(INC_FLAGS) \ -+ -MMD -MP -+override LDFLAGS += $(shell $(PKG_CONFIG) --libs glib-2.0) -+ -+$(BUILD_DIR)/src/libslirp-version.h: Makefile -+ @$(MKDIR_P) $(dir $@) -+ $(call quiet-command,cat $(ROOT_DIR)/src/libslirp-version.h.in | \ -+ sed 's/@SLIRP_MAJOR_VERSION@/$(SLIRP_MAJOR_VERSION)/' | \ -+ sed 's/@SLIRP_MINOR_VERSION@/$(SLIRP_MINOR_VERSION)/' | \ -+ sed 's/@SLIRP_MICRO_VERSION@/$(SLIRP_MICRO_VERSION)/' | \ -+ sed 's/@SLIRP_VERSION_STRING@/$(SLIRP_VERSION_STRING)/' \ -+ > $@,"GEN","$@") -+ -+$(OBJS): $(BUILD_DIR)/src/libslirp-version.h -+ -+$(LIBSLIRP): $(OBJS) -+ -+.PHONY: clean -+ -+clean: -+ rm -r $(OBJS) $(DEPS) $(LIBSLIRP) $(BUILD_DIR)/src/libslirp-version.h -+ -+$(BUILD_DIR)/src/%.o: $(ROOT_DIR)/src/%.c -+ @$(MKDIR_P) $(dir $@) -+ $(call quiet-command,$(CC) $(CFLAGS) -c -o $@ $<,"CC","$@") -+ -+%.a: -+ $(call quiet-command,rm -f $@ && $(AR) rcs $@ $^,"AR","$@") -+ -+PKG_CONFIG ?= pkg-config -+MKDIR_P ?= mkdir -p -+quiet-command-run = $(if $(V),,$(if $2,printf " %-7s %s\n" $2 $3 && ))$1 -+quiet-@ = $(if $(V),,@) -+quiet-command = $(quiet-@)$(call quiet-command-run,$1,$2,$3) -+ -+print-%: -+ @echo '$*=$($*)' -+ -+.SUFFIXES: -+ -+-include $(DEPS) -diff --git a/slirp/README.md b/slirp/README.md -new file mode 100644 -index 0000000000..dc11e5f18b ---- /dev/null -+++ b/slirp/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/slirp/build-aux/git-version-gen b/slirp/build-aux/git-version-gen -new file mode 100755 -index 0000000000..5617eb8d4e ---- /dev/null -+++ b/slirp/build-aux/git-version-gen -@@ -0,0 +1,158 @@ -+#!/bin/sh -+# Print a version string. -+scriptversion=2010-06-14.19; # UTC -+ -+# Copyright (C) 2007-2010 Free Software Foundation, Inc. -+# -+# This program is free software: you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 3 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program. If not, see . -+ -+# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/. -+# It may be run two ways: -+# - from a git repository in which the "git describe" command below -+# produces useful output (thus requiring at least one signed tag) -+# - from a non-git-repo directory containing a .tarball-version file, which -+# presumes this script is invoked like "./git-version-gen .tarball-version". -+ -+# In order to use intra-version strings in your project, you will need two -+# separate generated version string files: -+# -+# .tarball-version - present only in a distribution tarball, and not in -+# a checked-out repository. Created with contents that were learned at -+# the last time autoconf was run, and used by git-version-gen. Must not -+# be present in either $(srcdir) or $(builddir) for git-version-gen to -+# give accurate answers during normal development with a checked out tree, -+# but must be present in a tarball when there is no version control system. -+# Therefore, it cannot be used in any dependencies. GNUmakefile has -+# hooks to force a reconfigure at distribution time to get the value -+# correct, without penalizing normal development with extra reconfigures. -+# -+# .version - present in a checked-out repository and in a distribution -+# tarball. Usable in dependencies, particularly for files that don't -+# want to depend on config.h but do want to track version changes. -+# Delete this file prior to any autoconf run where you want to rebuild -+# files to pick up a version string change; and leave it stale to -+# minimize rebuild time after unrelated changes to configure sources. -+# -+# It is probably wise to add these two files to .gitignore, so that you -+# don't accidentally commit either generated file. -+# -+# Use the following line in your configure.ac, so that $(VERSION) will -+# automatically be up-to-date each time configure is run (and note that -+# since configure.ac no longer includes a version string, Makefile rules -+# should not depend on configure.ac for version updates). -+# -+# AC_INIT([GNU project], -+# m4_esyscmd([build-aux/git-version-gen .tarball-version]), -+# [bug-project@example]) -+# -+# Then use the following lines in your Makefile.am, so that .version -+# will be present for dependencies, and so that .tarball-version will -+# exist in distribution tarballs. -+# -+# BUILT_SOURCES = $(top_srcdir)/.version -+# $(top_srcdir)/.version: -+# echo $(VERSION) > $@-t && mv $@-t $@ -+# dist-hook: -+# echo $(VERSION) > $(distdir)/.tarball-version -+ -+case $# in -+ 1|2) ;; -+ *) echo 1>&2 "Usage: $0 \$srcdir/.tarball-version" \ -+ '[TAG-NORMALIZATION-SED-SCRIPT]' -+ exit 1;; -+esac -+ -+tarball_version_file=$1 -+tag_sed_script="${2:-s/x/x/}" -+nl=' -+' -+ -+# Avoid meddling by environment variable of the same name. -+v= -+ -+# First see if there is a tarball-only version file. -+# then try "git describe", then default. -+if test -f $tarball_version_file -+then -+ v=`cat $tarball_version_file` || exit 1 -+ case $v in -+ *$nl*) v= ;; # reject multi-line output -+ [0-9]*) ;; -+ *) v= ;; -+ esac -+ test -z "$v" \ -+ && echo "$0: WARNING: $tarball_version_file seems to be damaged" 1>&2 -+fi -+ -+if test -n "$v" -+then -+ : # use $v -+elif test -d .git \ -+ && v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \ -+ || git describe --abbrev=4 HEAD 2>/dev/null` \ -+ && v=`printf '%s\n' "$v" | sed "$tag_sed_script"` \ -+ && case $v in -+ v[0-9]*) ;; -+ *) (exit 1) ;; -+ esac -+then -+ # Is this a new git that lists number of commits since the last -+ # tag or the previous older version that did not? -+ # Newer: v6.10-77-g0f8faeb -+ # Older: v6.10-g0f8faeb -+ case $v in -+ *-*-*) : git describe is okay three part flavor ;; -+ *-*) -+ : git describe is older two part flavor -+ # Recreate the number of commits and rewrite such that the -+ # result is the same as if we were using the newer version -+ # of git describe. -+ vtag=`echo "$v" | sed 's/-.*//'` -+ numcommits=`git rev-list "$vtag"..HEAD | wc -l` -+ v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`; -+ ;; -+ esac -+ -+ # Change the first '-' to a '.', so version-comparing tools work properly. -+ # Remove the "g" in git describe's output string, to save a byte. -+ v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`; -+else -+ v=UNKNOWN -+fi -+ -+v=`echo "$v" |sed 's/^v//'` -+ -+# Don't declare a version "dirty" merely because a time stamp has changed. -+git update-index --refresh > /dev/null 2>&1 -+ -+dirty=`sh -c 'git diff-index --name-only HEAD' 2>/dev/null` || dirty= -+case "$dirty" in -+ '') ;; -+ *) # Append the suffix only if there isn't one already. -+ case $v in -+ *-dirty) ;; -+ *) v="$v-dirty" ;; -+ esac ;; -+esac -+ -+# Omit the trailing newline, so that m4_esyscmd can use the result directly. -+echo "$v" | tr -d "$nl" -+ -+# Local variables: -+# eval: (add-hook 'write-file-hooks 'time-stamp) -+# time-stamp-start: "scriptversion=" -+# time-stamp-format: "%:y-%02m-%02d.%02H" -+# time-stamp-time-zone: "UTC" -+# time-stamp-end: "; # UTC" -+# End: -diff --git a/slirp/build-aux/meson-dist b/slirp/build-aux/meson-dist -new file mode 100755 -index 0000000000..80d534fec6 ---- /dev/null -+++ b/slirp/build-aux/meson-dist -@@ -0,0 +1,16 @@ -+#!/bin/bash -+ -+set -e -+set -o pipefail -+ -+if test "$1" = ""; then -+ echo "Version not provided" >&2 -+ exit 1 -+fi -+if ! test -d "$2"; then -+ echo "Source directory not provided" >&2 -+ exit 1 -+fi -+ -+# generate tarball version -+echo "$1" > "$MESON_DIST_ROOT/.tarball-version" -diff --git a/slirp/meson.build b/slirp/meson.build -new file mode 100644 -index 0000000000..3a27149373 ---- /dev/null -+++ b/slirp/meson.build -@@ -0,0 +1,134 @@ -+project('libslirp', 'c', -+ version : run_command('build-aux/git-version-gen', '@0@/.tarball-version'.format(meson.source_root()), check : true).stdout().strip(), -+ license : 'BSD-3-Clause', -+ default_options : ['warning_level=1', 'c_std=gnu99'], -+ meson_version : '>= 0.49', -+) -+ -+meson.add_dist_script('build-aux/meson-dist', meson.project_version(), meson.source_root()) -+ -+version = meson.project_version() -+varr = version.split('.') -+major_version = varr[0] -+minor_version = varr[1] -+micro_version = varr[2] -+ -+conf = configuration_data() -+conf.set('SLIRP_MAJOR_VERSION', major_version) -+conf.set('SLIRP_MINOR_VERSION', minor_version) -+conf.set('SLIRP_MICRO_VERSION', micro_version) -+conf.set_quoted('SLIRP_VERSION_STRING', version) -+ -+# libtool versioning - this applies to libslirp -+# -+# See http://sources.redhat.com/autobook/autobook/autobook_91.html#SEC91 for details -+# -+# - If interfaces have been changed or added, but binary compatibility -+# has been preserved, change: -+# CURRENT += 1 -+# REVISION = 0 -+# AGE += 1 -+# - If binary compatibility has been broken (eg removed or changed -+# interfaces), change: -+# CURRENT += 1 -+# REVISION = 0 -+# AGE = 0 -+# - If the interface is the same as the previous version, but bugs are -+# fixed, change: -+# REVISION += 1 -+lt_current = 2 -+lt_revision = 0 -+lt_age = 2 -+lt_version = '@0@.@1@.@2@'.format(lt_current - lt_age, lt_age, lt_revision) -+ -+host_system = host_machine.system() -+ -+glib_dep = dependency('glib-2.0') -+ -+cc = meson.get_compiler('c') -+ -+platform_deps = [] -+ -+if host_system == 'windows' -+ platform_deps += [ -+ cc.find_library('ws2_32'), -+ cc.find_library('iphlpapi') -+ ] -+endif -+ -+cargs = [ -+ '-DG_LOG_DOMAIN="Slirp"', -+] -+ -+sources = [ -+ 'src/arp_table.c', -+ 'src/bootp.c', -+ 'src/cksum.c', -+ 'src/dhcpv6.c', -+ 'src/dnssearch.c', -+ 'src/if.c', -+ 'src/ip6_icmp.c', -+ 'src/ip6_input.c', -+ 'src/ip6_output.c', -+ 'src/ip_icmp.c', -+ 'src/ip_input.c', -+ 'src/ip_output.c', -+ 'src/mbuf.c', -+ 'src/misc.c', -+ 'src/ncsi.c', -+ 'src/ndp_table.c', -+ 'src/sbuf.c', -+ 'src/slirp.c', -+ 'src/socket.c', -+ 'src/state.c', -+ 'src/stream.c', -+ 'src/tcp_input.c', -+ 'src/tcp_output.c', -+ 'src/tcp_subr.c', -+ 'src/tcp_timer.c', -+ 'src/tftp.c', -+ 'src/udp.c', -+ 'src/udp6.c', -+ 'src/util.c', -+ 'src/version.c', -+ 'src/vmstate.c', -+] -+ -+mapfile = 'src/libslirp.map' -+vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile) -+ -+configure_file( -+ input : 'src/libslirp-version.h.in', -+ output : 'libslirp-version.h', -+ install_dir : join_paths(get_option('includedir'), 'slirp'), -+ configuration : conf -+) -+ -+lib = library('slirp', sources, -+ version : lt_version, -+ c_args : cargs, -+ link_args : vflag, -+ link_depends : mapfile, -+ dependencies : [glib_dep, platform_deps], -+ install : true -+) -+ -+libslirp_dep = declare_dependency( -+ include_directories: include_directories('.', 'src'), -+ link_with: lib) -+ -+install_headers(['src/libslirp.h'], subdir : 'slirp') -+ -+pkg = import('pkgconfig') -+ -+pkg.generate( -+ version : version, -+ libraries : lib, -+ requires : [ -+ 'glib-2.0', -+ ], -+ name : 'slirp', -+ description : 'User-space network stack', -+ filebase : 'slirp', -+ subdirs : 'slirp', -+) -diff --git a/slirp/src/arp_table.c b/slirp/src/arp_table.c -new file mode 100644 -index 0000000000..959e5b9ec0 ---- /dev/null -+++ b/slirp/src/arp_table.c -@@ -0,0 +1,92 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * ARP table -+ * -+ * Copyright (c) 2011 AdaCore -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "slirp.h" -+ -+#include -+ -+void arp_table_add(Slirp *slirp, uint32_t ip_addr, -+ const uint8_t ethaddr[ETH_ALEN]) -+{ -+ const uint32_t broadcast_addr = -+ ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr; -+ ArpTable *arptbl = &slirp->arp_table; -+ int i; -+ -+ DEBUG_CALL("arp_table_add"); -+ DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){ .s_addr = ip_addr })); -+ DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x", ethaddr[0], ethaddr[1], -+ ethaddr[2], ethaddr[3], ethaddr[4], ethaddr[5]); -+ -+ if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) { -+ /* Do not register broadcast addresses */ -+ return; -+ } -+ -+ /* Search for an entry */ -+ for (i = 0; i < ARP_TABLE_SIZE; i++) { -+ if (arptbl->table[i].ar_sip == ip_addr) { -+ /* Update the entry */ -+ memcpy(arptbl->table[i].ar_sha, ethaddr, ETH_ALEN); -+ return; -+ } -+ } -+ -+ /* No entry found, create a new one */ -+ arptbl->table[arptbl->next_victim].ar_sip = ip_addr; -+ memcpy(arptbl->table[arptbl->next_victim].ar_sha, ethaddr, ETH_ALEN); -+ arptbl->next_victim = (arptbl->next_victim + 1) % ARP_TABLE_SIZE; -+} -+ -+bool arp_table_search(Slirp *slirp, uint32_t ip_addr, -+ uint8_t out_ethaddr[ETH_ALEN]) -+{ -+ const uint32_t broadcast_addr = -+ ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr; -+ ArpTable *arptbl = &slirp->arp_table; -+ int i; -+ -+ DEBUG_CALL("arp_table_search"); -+ DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){ .s_addr = ip_addr })); -+ -+ /* If broadcast address */ -+ if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) { -+ /* return Ethernet broadcast address */ -+ memset(out_ethaddr, 0xff, ETH_ALEN); -+ return 1; -+ } -+ -+ for (i = 0; i < ARP_TABLE_SIZE; i++) { -+ if (arptbl->table[i].ar_sip == ip_addr) { -+ memcpy(out_ethaddr, arptbl->table[i].ar_sha, ETH_ALEN); -+ DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x", -+ out_ethaddr[0], out_ethaddr[1], out_ethaddr[2], -+ out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]); -+ return 1; -+ } -+ } -+ -+ return 0; -+} -diff --git a/slirp/src/bootp.c b/slirp/src/bootp.c -new file mode 100644 -index 0000000000..46e96810ab ---- /dev/null -+++ b/slirp/src/bootp.c -@@ -0,0 +1,369 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * QEMU BOOTP/DHCP server -+ * -+ * Copyright (c) 2004 Fabrice Bellard -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+#include "slirp.h" -+ -+#if defined(_WIN32) -+/* Windows ntohl() returns an u_long value. -+ * Add a type cast to match the format strings. */ -+#define ntohl(n) ((uint32_t)ntohl(n)) -+#endif -+ -+/* XXX: only DHCP is supported */ -+ -+#define LEASE_TIME (24 * 3600) -+ -+static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE }; -+ -+#define DPRINTF(fmt, ...) DEBUG_CALL(fmt, ##__VA_ARGS__) -+ -+static BOOTPClient *get_new_addr(Slirp *slirp, struct in_addr *paddr, -+ const uint8_t *macaddr) -+{ -+ BOOTPClient *bc; -+ int i; -+ -+ for (i = 0; i < NB_BOOTP_CLIENTS; i++) { -+ bc = &slirp->bootp_clients[i]; -+ if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) -+ goto found; -+ } -+ return NULL; -+found: -+ bc = &slirp->bootp_clients[i]; -+ bc->allocated = 1; -+ paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i); -+ return bc; -+} -+ -+static BOOTPClient *request_addr(Slirp *slirp, const struct in_addr *paddr, -+ const uint8_t *macaddr) -+{ -+ uint32_t req_addr = ntohl(paddr->s_addr); -+ uint32_t dhcp_addr = ntohl(slirp->vdhcp_startaddr.s_addr); -+ BOOTPClient *bc; -+ -+ if (req_addr >= dhcp_addr && req_addr < (dhcp_addr + NB_BOOTP_CLIENTS)) { -+ bc = &slirp->bootp_clients[req_addr - dhcp_addr]; -+ if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) { -+ bc->allocated = 1; -+ return bc; -+ } -+ } -+ return NULL; -+} -+ -+static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr, -+ const uint8_t *macaddr) -+{ -+ BOOTPClient *bc; -+ int i; -+ -+ for (i = 0; i < NB_BOOTP_CLIENTS; i++) { -+ if (!memcmp(macaddr, slirp->bootp_clients[i].macaddr, 6)) -+ goto found; -+ } -+ return NULL; -+found: -+ bc = &slirp->bootp_clients[i]; -+ bc->allocated = 1; -+ paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i); -+ return bc; -+} -+ -+static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type, -+ struct in_addr *preq_addr) -+{ -+ const uint8_t *p, *p_end; -+ int len, tag; -+ -+ *pmsg_type = 0; -+ preq_addr->s_addr = htonl(0L); -+ -+ p = bp->bp_vend; -+ p_end = p + DHCP_OPT_LEN; -+ if (memcmp(p, rfc1533_cookie, 4) != 0) -+ return; -+ p += 4; -+ while (p < p_end) { -+ tag = p[0]; -+ if (tag == RFC1533_PAD) { -+ p++; -+ } else if (tag == RFC1533_END) { -+ break; -+ } else { -+ p++; -+ if (p >= p_end) -+ break; -+ len = *p++; -+ if (p + len > p_end) { -+ break; -+ } -+ DPRINTF("dhcp: tag=%d len=%d\n", tag, len); -+ -+ switch (tag) { -+ case RFC2132_MSG_TYPE: -+ if (len >= 1) -+ *pmsg_type = p[0]; -+ break; -+ case RFC2132_REQ_ADDR: -+ if (len >= 4) { -+ memcpy(&(preq_addr->s_addr), p, 4); -+ } -+ break; -+ default: -+ break; -+ } -+ p += len; -+ } -+ } -+ if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) && -+ bp->bp_ciaddr.s_addr) { -+ memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4); -+ } -+} -+ -+static void bootp_reply(Slirp *slirp, const struct bootp_t *bp) -+{ -+ BOOTPClient *bc = NULL; -+ struct mbuf *m; -+ struct bootp_t *rbp; -+ struct sockaddr_in saddr, daddr; -+ struct in_addr preq_addr; -+ int dhcp_msg_type, val; -+ uint8_t *q; -+ uint8_t *end; -+ uint8_t client_ethaddr[ETH_ALEN]; -+ -+ /* extract exact DHCP msg type */ -+ dhcp_decode(bp, &dhcp_msg_type, &preq_addr); -+ DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type); -+ if (preq_addr.s_addr != htonl(0L)) -+ DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr)); -+ else { -+ DPRINTF("\n"); -+ } -+ -+ if (dhcp_msg_type == 0) -+ dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */ -+ -+ if (dhcp_msg_type != DHCPDISCOVER && dhcp_msg_type != DHCPREQUEST) -+ return; -+ -+ /* Get client's hardware address from bootp request */ -+ memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN); -+ -+ m = m_get(slirp); -+ if (!m) { -+ return; -+ } -+ m->m_data += IF_MAXLINKHDR; -+ rbp = (struct bootp_t *)m->m_data; -+ m->m_data += sizeof(struct udpiphdr); -+ memset(rbp, 0, sizeof(struct bootp_t)); -+ -+ if (dhcp_msg_type == DHCPDISCOVER) { -+ if (preq_addr.s_addr != htonl(0L)) { -+ bc = request_addr(slirp, &preq_addr, client_ethaddr); -+ if (bc) { -+ daddr.sin_addr = preq_addr; -+ } -+ } -+ if (!bc) { -+ new_addr: -+ bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr); -+ if (!bc) { -+ DPRINTF("no address left\n"); -+ return; -+ } -+ } -+ memcpy(bc->macaddr, client_ethaddr, ETH_ALEN); -+ } else if (preq_addr.s_addr != htonl(0L)) { -+ bc = request_addr(slirp, &preq_addr, client_ethaddr); -+ if (bc) { -+ daddr.sin_addr = preq_addr; -+ memcpy(bc->macaddr, client_ethaddr, ETH_ALEN); -+ } else { -+ /* DHCPNAKs should be sent to broadcast */ -+ daddr.sin_addr.s_addr = 0xffffffff; -+ } -+ } else { -+ bc = find_addr(slirp, &daddr.sin_addr, bp->bp_hwaddr); -+ if (!bc) { -+ /* if never assigned, behaves as if it was already -+ assigned (windows fix because it remembers its address) */ -+ goto new_addr; -+ } -+ } -+ -+ /* Update ARP table for this IP address */ -+ arp_table_add(slirp, daddr.sin_addr.s_addr, client_ethaddr); -+ -+ saddr.sin_addr = slirp->vhost_addr; -+ saddr.sin_port = htons(BOOTP_SERVER); -+ -+ daddr.sin_port = htons(BOOTP_CLIENT); -+ -+ rbp->bp_op = BOOTP_REPLY; -+ rbp->bp_xid = bp->bp_xid; -+ rbp->bp_htype = 1; -+ rbp->bp_hlen = 6; -+ memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN); -+ -+ rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */ -+ rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */ -+ -+ q = rbp->bp_vend; -+ end = (uint8_t *)&rbp[1]; -+ memcpy(q, rfc1533_cookie, 4); -+ q += 4; -+ -+ if (bc) { -+ DPRINTF("%s addr=%08" PRIx32 "\n", -+ (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed", -+ ntohl(daddr.sin_addr.s_addr)); -+ -+ if (dhcp_msg_type == DHCPDISCOVER) { -+ *q++ = RFC2132_MSG_TYPE; -+ *q++ = 1; -+ *q++ = DHCPOFFER; -+ } else /* DHCPREQUEST */ { -+ *q++ = RFC2132_MSG_TYPE; -+ *q++ = 1; -+ *q++ = DHCPACK; -+ } -+ -+ if (slirp->bootp_filename) { -+ g_assert(strlen(slirp->bootp_filename) < sizeof(rbp->bp_file)); -+ strcpy(rbp->bp_file, slirp->bootp_filename); -+ } -+ -+ *q++ = RFC2132_SRV_ID; -+ *q++ = 4; -+ memcpy(q, &saddr.sin_addr, 4); -+ q += 4; -+ -+ *q++ = RFC1533_NETMASK; -+ *q++ = 4; -+ memcpy(q, &slirp->vnetwork_mask, 4); -+ q += 4; -+ -+ if (!slirp->restricted) { -+ *q++ = RFC1533_GATEWAY; -+ *q++ = 4; -+ memcpy(q, &saddr.sin_addr, 4); -+ q += 4; -+ -+ *q++ = RFC1533_DNS; -+ *q++ = 4; -+ memcpy(q, &slirp->vnameserver_addr, 4); -+ q += 4; -+ } -+ -+ *q++ = RFC2132_LEASE_TIME; -+ *q++ = 4; -+ val = htonl(LEASE_TIME); -+ memcpy(q, &val, 4); -+ q += 4; -+ -+ if (*slirp->client_hostname) { -+ val = strlen(slirp->client_hostname); -+ if (q + val + 2 >= end) { -+ g_warning("DHCP packet size exceeded, " -+ "omitting host name option."); -+ } else { -+ *q++ = RFC1533_HOSTNAME; -+ *q++ = val; -+ memcpy(q, slirp->client_hostname, val); -+ q += val; -+ } -+ } -+ -+ if (slirp->vdomainname) { -+ val = strlen(slirp->vdomainname); -+ if (q + val + 2 >= end) { -+ g_warning("DHCP packet size exceeded, " -+ "omitting domain name option."); -+ } else { -+ *q++ = RFC1533_DOMAINNAME; -+ *q++ = val; -+ memcpy(q, slirp->vdomainname, val); -+ q += val; -+ } -+ } -+ -+ if (slirp->tftp_server_name) { -+ val = strlen(slirp->tftp_server_name); -+ if (q + val + 2 >= end) { -+ g_warning("DHCP packet size exceeded, " -+ "omitting tftp-server-name option."); -+ } else { -+ *q++ = RFC2132_TFTP_SERVER_NAME; -+ *q++ = val; -+ memcpy(q, slirp->tftp_server_name, val); -+ q += val; -+ } -+ } -+ -+ if (slirp->vdnssearch) { -+ val = slirp->vdnssearch_len; -+ if (q + val >= end) { -+ g_warning("DHCP packet size exceeded, " -+ "omitting domain-search option."); -+ } else { -+ memcpy(q, slirp->vdnssearch, val); -+ q += val; -+ } -+ } -+ } else { -+ static const char nak_msg[] = "requested address not available"; -+ -+ DPRINTF("nak'ed addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr)); -+ -+ *q++ = RFC2132_MSG_TYPE; -+ *q++ = 1; -+ *q++ = DHCPNAK; -+ -+ *q++ = RFC2132_MESSAGE; -+ *q++ = sizeof(nak_msg) - 1; -+ memcpy(q, nak_msg, sizeof(nak_msg) - 1); -+ q += sizeof(nak_msg) - 1; -+ } -+ assert(q < end); -+ *q = RFC1533_END; -+ -+ daddr.sin_addr.s_addr = 0xffffffffu; -+ -+ m->m_len = sizeof(struct bootp_t) - sizeof(struct ip) - sizeof(struct udphdr); -+ udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); -+} -+ -+void bootp_input(struct mbuf *m) -+{ -+ struct bootp_t *bp = mtod(m, struct bootp_t *); -+ -+ if (bp->bp_op == BOOTP_REQUEST) { -+ bootp_reply(m->slirp, bp); -+ } -+} -diff --git a/slirp/src/bootp.h b/slirp/src/bootp.h -new file mode 100644 -index 0000000000..a57fa51bcb ---- /dev/null -+++ b/slirp/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]; -+ char bp_file[128]; -+ uint8_t bp_vend[DHCP_OPT_LEN]; -+}; -+ -+typedef struct { -+ uint16_t allocated; -+ uint8_t macaddr[6]; -+} BOOTPClient; -+ -+#define NB_BOOTP_CLIENTS 16 -+ -+void bootp_input(struct mbuf *m); -+ -+#endif -diff --git a/slirp/src/cksum.c b/slirp/src/cksum.c -new file mode 100644 -index 0000000000..4d08380a4e ---- /dev/null -+++ b/slirp/src/cksum.c -@@ -0,0 +1,179 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * Copyright (c) 1988, 1992, 1993 -+ * The Regents of the University of California. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. Neither the name of the University nor the names of its contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -+ * SUCH DAMAGE. -+ * -+ * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 -+ * in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp -+ */ -+ -+#include "slirp.h" -+ -+/* -+ * Checksum routine for Internet Protocol family headers (Portable Version). -+ * -+ * This routine is very heavily used in the network -+ * code and should be modified for each CPU to be as fast as possible. -+ * -+ * XXX Since we will never span more than 1 mbuf, we can optimise this -+ */ -+ -+#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) -+#define REDUCE \ -+ { \ -+ l_util.l = sum; \ -+ sum = l_util.s[0] + l_util.s[1]; \ -+ (void)ADDCARRY(sum); \ -+ } -+ -+int cksum(struct mbuf *m, int len) -+{ -+ register uint16_t *w; -+ register int sum = 0; -+ register int mlen = 0; -+ int byte_swapped = 0; -+ -+ union { -+ uint8_t c[2]; -+ uint16_t s; -+ } s_util; -+ union { -+ uint16_t s[2]; -+ uint32_t l; -+ } l_util; -+ -+ if (m->m_len == 0) -+ goto cont; -+ w = mtod(m, uint16_t *); -+ -+ mlen = m->m_len; -+ -+ if (len < mlen) -+ mlen = len; -+ len -= mlen; -+ /* -+ * Force to even boundary. -+ */ -+ if ((1 & (uintptr_t)w) && (mlen > 0)) { -+ REDUCE; -+ sum <<= 8; -+ s_util.c[0] = *(uint8_t *)w; -+ w = (uint16_t *)((int8_t *)w + 1); -+ mlen--; -+ byte_swapped = 1; -+ } -+ /* -+ * Unroll the loop to make overhead from -+ * branches &c small. -+ */ -+ while ((mlen -= 32) >= 0) { -+ sum += w[0]; -+ sum += w[1]; -+ sum += w[2]; -+ sum += w[3]; -+ sum += w[4]; -+ sum += w[5]; -+ sum += w[6]; -+ sum += w[7]; -+ sum += w[8]; -+ sum += w[9]; -+ sum += w[10]; -+ sum += w[11]; -+ sum += w[12]; -+ sum += w[13]; -+ sum += w[14]; -+ sum += w[15]; -+ w += 16; -+ } -+ mlen += 32; -+ while ((mlen -= 8) >= 0) { -+ sum += w[0]; -+ sum += w[1]; -+ sum += w[2]; -+ sum += w[3]; -+ w += 4; -+ } -+ mlen += 8; -+ if (mlen == 0 && byte_swapped == 0) -+ goto cont; -+ REDUCE; -+ while ((mlen -= 2) >= 0) { -+ sum += *w++; -+ } -+ -+ if (byte_swapped) { -+ REDUCE; -+ sum <<= 8; -+ if (mlen == -1) { -+ s_util.c[1] = *(uint8_t *)w; -+ sum += s_util.s; -+ mlen = 0; -+ } else -+ -+ mlen = -1; -+ } else if (mlen == -1) -+ s_util.c[0] = *(uint8_t *)w; -+ -+cont: -+ if (len) { -+ DEBUG_ERROR("cksum: out of data"); -+ DEBUG_ERROR(" len = %d", len); -+ } -+ if (mlen == -1) { -+ /* The last mbuf has odd # of bytes. Follow the -+ standard (the odd byte may be shifted left by 8 bits -+ or not as determined by endian-ness of the machine) */ -+ s_util.c[1] = 0; -+ sum += s_util.s; -+ } -+ REDUCE; -+ return (~sum & 0xffff); -+} -+ -+int ip6_cksum(struct mbuf *m) -+{ -+ /* TODO: Optimize this by being able to pass the ip6_pseudohdr to cksum -+ * separately from the mbuf */ -+ struct ip6 save_ip, *ip = mtod(m, struct ip6 *); -+ struct ip6_pseudohdr *ih = mtod(m, struct ip6_pseudohdr *); -+ int sum; -+ -+ save_ip = *ip; -+ -+ ih->ih_src = save_ip.ip_src; -+ ih->ih_dst = save_ip.ip_dst; -+ ih->ih_pl = htonl((uint32_t)ntohs(save_ip.ip_pl)); -+ ih->ih_zero_hi = 0; -+ ih->ih_zero_lo = 0; -+ ih->ih_nh = save_ip.ip_nh; -+ -+ sum = cksum(m, ((int)sizeof(struct ip6_pseudohdr)) + ntohl(ih->ih_pl)); -+ -+ *ip = save_ip; -+ -+ return sum; -+} -diff --git a/slirp/src/debug.h b/slirp/src/debug.h -new file mode 100644 -index 0000000000..47712bd78b ---- /dev/null -+++ b/slirp/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/slirp/src/dhcpv6.c b/slirp/src/dhcpv6.c -new file mode 100644 -index 0000000000..77b451b910 ---- /dev/null -+++ b/slirp/src/dhcpv6.c -@@ -0,0 +1,224 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * SLIRP stateless DHCPv6 -+ * -+ * We only support stateless DHCPv6, e.g. for network booting. -+ * See RFC 3315, RFC 3736, RFC 3646 and RFC 5970 for details. -+ * -+ * Copyright 2016 Thomas Huth, Red Hat Inc. -+ * -+ * 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. -+ */ -+ -+#include "slirp.h" -+#include "dhcpv6.h" -+ -+/* DHCPv6 message types */ -+#define MSGTYPE_REPLY 7 -+#define MSGTYPE_INFO_REQUEST 11 -+ -+/* DHCPv6 option types */ -+#define OPTION_CLIENTID 1 -+#define OPTION_IAADDR 5 -+#define OPTION_ORO 6 -+#define OPTION_DNS_SERVERS 23 -+#define OPTION_BOOTFILE_URL 59 -+ -+struct requested_infos { -+ uint8_t *client_id; -+ int client_id_len; -+ bool want_dns; -+ bool want_boot_url; -+}; -+ -+/** -+ * Analyze the info request message sent by the client to see what data it -+ * provided and what it wants to have. The information is gathered in the -+ * "requested_infos" struct. Note that client_id (if provided) points into -+ * the odata region, thus the caller must keep odata valid as long as it -+ * needs to access the requested_infos struct. -+ */ -+static int dhcpv6_parse_info_request(Slirp *slirp, uint8_t *odata, int olen, -+ struct requested_infos *ri) -+{ -+ int i, req_opt; -+ -+ while (olen > 4) { -+ /* Parse one option */ -+ int option = odata[0] << 8 | odata[1]; -+ int len = odata[2] << 8 | odata[3]; -+ -+ if (len + 4 > olen) { -+ slirp->cb->guest_error("Guest sent bad DHCPv6 packet!", -+ slirp->opaque); -+ return -E2BIG; -+ } -+ -+ switch (option) { -+ case OPTION_IAADDR: -+ /* According to RFC3315, we must discard requests with IA option */ -+ return -EINVAL; -+ case OPTION_CLIENTID: -+ if (len > 256) { -+ /* Avoid very long IDs which could cause problems later */ -+ return -E2BIG; -+ } -+ ri->client_id = odata + 4; -+ ri->client_id_len = len; -+ break; -+ case OPTION_ORO: /* Option request option */ -+ if (len & 1) { -+ return -EINVAL; -+ } -+ /* Check which options the client wants to have */ -+ for (i = 0; i < len; i += 2) { -+ req_opt = odata[4 + i] << 8 | odata[4 + i + 1]; -+ switch (req_opt) { -+ case OPTION_DNS_SERVERS: -+ ri->want_dns = true; -+ break; -+ case OPTION_BOOTFILE_URL: -+ ri->want_boot_url = true; -+ break; -+ default: -+ DEBUG_MISC("dhcpv6: Unsupported option request %d", -+ req_opt); -+ } -+ } -+ break; -+ default: -+ DEBUG_MISC("dhcpv6 info req: Unsupported option %d, len=%d", option, -+ len); -+ } -+ -+ odata += len + 4; -+ olen -= len + 4; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * Handle information request messages -+ */ -+static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas, -+ uint32_t xid, uint8_t *odata, int olen) -+{ -+ struct requested_infos ri = { NULL }; -+ struct sockaddr_in6 sa6, da6; -+ struct mbuf *m; -+ uint8_t *resp; -+ -+ if (dhcpv6_parse_info_request(slirp, odata, olen, &ri) < 0) { -+ return; -+ } -+ -+ m = m_get(slirp); -+ if (!m) { -+ return; -+ } -+ memset(m->m_data, 0, m->m_size); -+ m->m_data += IF_MAXLINKHDR; -+ resp = (uint8_t *)m->m_data + sizeof(struct ip6) + sizeof(struct udphdr); -+ -+ /* Fill in response */ -+ *resp++ = MSGTYPE_REPLY; -+ *resp++ = (uint8_t)(xid >> 16); -+ *resp++ = (uint8_t)(xid >> 8); -+ *resp++ = (uint8_t)xid; -+ -+ if (ri.client_id) { -+ *resp++ = OPTION_CLIENTID >> 8; /* option-code high byte */ -+ *resp++ = OPTION_CLIENTID; /* option-code low byte */ -+ *resp++ = ri.client_id_len >> 8; /* option-len high byte */ -+ *resp++ = ri.client_id_len; /* option-len low byte */ -+ memcpy(resp, ri.client_id, ri.client_id_len); -+ resp += ri.client_id_len; -+ } -+ if (ri.want_dns) { -+ *resp++ = OPTION_DNS_SERVERS >> 8; /* option-code high byte */ -+ *resp++ = OPTION_DNS_SERVERS; /* option-code low byte */ -+ *resp++ = 0; /* option-len high byte */ -+ *resp++ = 16; /* option-len low byte */ -+ memcpy(resp, &slirp->vnameserver_addr6, 16); -+ resp += 16; -+ } -+ if (ri.want_boot_url) { -+ uint8_t *sa = slirp->vhost_addr6.s6_addr; -+ int slen, smaxlen; -+ -+ *resp++ = OPTION_BOOTFILE_URL >> 8; /* option-code high byte */ -+ *resp++ = OPTION_BOOTFILE_URL; /* option-code low byte */ -+ smaxlen = (uint8_t *)m->m_data + slirp->if_mtu - (resp + 2); -+ slen = slirp_fmt((char *)resp + 2, smaxlen, -+ "tftp://[%02x%02x:%02x%02x:%02x%02x:%02x%02x:" -+ "%02x%02x:%02x%02x:%02x%02x:%02x%02x]/%s", -+ sa[0], sa[1], sa[2], sa[3], sa[4], sa[5], sa[6], sa[7], -+ sa[8], sa[9], sa[10], sa[11], sa[12], sa[13], sa[14], -+ sa[15], slirp->bootp_filename); -+ *resp++ = slen >> 8; /* option-len high byte */ -+ *resp++ = slen; /* option-len low byte */ -+ resp += slen; -+ } -+ -+ sa6.sin6_addr = slirp->vhost_addr6; -+ sa6.sin6_port = DHCPV6_SERVER_PORT; -+ da6.sin6_addr = srcsas->sin6_addr; -+ da6.sin6_port = srcsas->sin6_port; -+ m->m_data += sizeof(struct ip6) + sizeof(struct udphdr); -+ m->m_len = resp - (uint8_t *)m->m_data; -+ udp6_output(NULL, m, &sa6, &da6); -+} -+ -+/** -+ * Handle DHCPv6 messages sent by the client -+ */ -+void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m) -+{ -+ uint8_t *data = (uint8_t *)m->m_data + sizeof(struct udphdr); -+ int data_len = m->m_len - sizeof(struct udphdr); -+ uint32_t xid; -+ -+ if (data_len < 4) { -+ return; -+ } -+ -+ xid = ntohl(*(uint32_t *)data) & 0xffffff; -+ -+ switch (data[0]) { -+ case MSGTYPE_INFO_REQUEST: -+ dhcpv6_info_request(m->slirp, srcsas, xid, &data[4], data_len - 4); -+ break; -+ default: -+ DEBUG_MISC("dhcpv6_input: Unsupported message type 0x%x", data[0]); -+ } -+} -diff --git a/slirp/src/dhcpv6.h b/slirp/src/dhcpv6.h -new file mode 100644 -index 0000000000..d12c49b36c ---- /dev/null -+++ b/slirp/src/dhcpv6.h -@@ -0,0 +1,68 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * Definitions and prototypes for SLIRP stateless DHCPv6 -+ * -+ * Copyright 2016 Thomas Huth, Red Hat Inc. -+ * -+ * 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 SLIRP_DHCPV6_H -+#define SLIRP_DHCPV6_H -+ -+#define DHCPV6_SERVER_PORT 547 -+ -+#define ALLDHCP_MULTICAST \ -+ { \ -+ .s6_addr = { \ -+ 0xff, \ -+ 0x02, \ -+ 0x00, \ -+ 0x00, \ -+ 0x00, \ -+ 0x00, \ -+ 0x00, \ -+ 0x00, \ -+ 0x00, \ -+ 0x00, \ -+ 0x00, \ -+ 0x00, \ -+ 0x00, \ -+ 0x01, \ -+ 0x00, \ -+ 0x02 \ -+ } \ -+ } -+ -+#define in6_dhcp_multicast(a) in6_equal(a, &(struct in6_addr)ALLDHCP_MULTICAST) -+ -+void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m); -+ -+#endif -diff --git a/slirp/src/dnssearch.c b/slirp/src/dnssearch.c -new file mode 100644 -index 0000000000..55497e860e ---- /dev/null -+++ b/slirp/src/dnssearch.c -@@ -0,0 +1,306 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * Domain search option for DHCP (RFC 3397) -+ * -+ * Copyright (c) 2012 Klaus Stengel -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "slirp.h" -+ -+static const uint8_t RFC3397_OPT_DOMAIN_SEARCH = 119; -+static const uint8_t MAX_OPT_LEN = 255; -+static const uint8_t OPT_HEADER_LEN = 2; -+static const uint8_t REFERENCE_LEN = 2; -+ -+struct compact_domain; -+ -+typedef struct compact_domain { -+ struct compact_domain *self; -+ struct compact_domain *refdom; -+ uint8_t *labels; -+ size_t len; -+ size_t common_octets; -+} CompactDomain; -+ -+static size_t domain_suffix_diffoff(const CompactDomain *a, -+ const CompactDomain *b) -+{ -+ size_t la = a->len, lb = b->len; -+ uint8_t *da = a->labels + la, *db = b->labels + lb; -+ size_t i, lm = (la < lb) ? la : lb; -+ -+ for (i = 0; i < lm; i++) { -+ da--; -+ db--; -+ if (*da != *db) { -+ break; -+ } -+ } -+ return i; -+} -+ -+static int domain_suffix_ord(const void *cva, const void *cvb) -+{ -+ const CompactDomain *a = cva, *b = cvb; -+ size_t la = a->len, lb = b->len; -+ size_t doff = domain_suffix_diffoff(a, b); -+ uint8_t ca = a->labels[la - doff]; -+ uint8_t cb = b->labels[lb - doff]; -+ -+ if (ca < cb) { -+ return -1; -+ } -+ if (ca > cb) { -+ return 1; -+ } -+ if (la < lb) { -+ return -1; -+ } -+ if (la > lb) { -+ return 1; -+ } -+ return 0; -+} -+ -+static size_t domain_common_label(CompactDomain *a, CompactDomain *b) -+{ -+ size_t res, doff = domain_suffix_diffoff(a, b); -+ uint8_t *first_eq_pos = a->labels + (a->len - doff); -+ uint8_t *label = a->labels; -+ -+ while (*label && label < first_eq_pos) { -+ label += *label + 1; -+ } -+ res = a->len - (label - a->labels); -+ /* only report if it can help to reduce the packet size */ -+ return (res > REFERENCE_LEN) ? res : 0; -+} -+ -+static void domain_fixup_order(CompactDomain *cd, size_t n) -+{ -+ size_t i; -+ -+ for (i = 0; i < n; i++) { -+ CompactDomain *cur = cd + i, *next = cd[i].self; -+ -+ while (!cur->common_octets) { -+ CompactDomain *tmp = next->self; /* backup target value */ -+ -+ next->self = cur; -+ cur->common_octets++; -+ -+ cur = next; -+ next = tmp; -+ } -+ } -+} -+ -+static void domain_mklabels(CompactDomain *cd, const char *input) -+{ -+ uint8_t *len_marker = cd->labels; -+ uint8_t *output = len_marker; /* pre-incremented */ -+ const char *in = input; -+ char cur_chr; -+ size_t len = 0; -+ -+ if (cd->len == 0) { -+ goto fail; -+ } -+ cd->len++; -+ -+ do { -+ cur_chr = *in++; -+ if (cur_chr == '.' || cur_chr == '\0') { -+ len = output - len_marker; -+ if ((len == 0 && cur_chr == '.') || len >= 64) { -+ goto fail; -+ } -+ *len_marker = len; -+ -+ output++; -+ len_marker = output; -+ } else { -+ output++; -+ *output = cur_chr; -+ } -+ } while (cur_chr != '\0'); -+ -+ /* ensure proper zero-termination */ -+ if (len != 0) { -+ *len_marker = 0; -+ cd->len++; -+ } -+ return; -+ -+fail: -+ g_warning("failed to parse domain name '%s'\n", input); -+ cd->len = 0; -+} -+ -+static void domain_mkxrefs(CompactDomain *doms, CompactDomain *last, -+ size_t depth) -+{ -+ CompactDomain *i = doms, *target = doms; -+ -+ do { -+ if (i->labels < target->labels) { -+ target = i; -+ } -+ } while (i++ != last); -+ -+ for (i = doms; i != last; i++) { -+ CompactDomain *group_last; -+ size_t next_depth; -+ -+ if (i->common_octets == depth) { -+ continue; -+ } -+ -+ next_depth = -1; -+ for (group_last = i; group_last != last; group_last++) { -+ size_t co = group_last->common_octets; -+ if (co <= depth) { -+ break; -+ } -+ if (co < next_depth) { -+ next_depth = co; -+ } -+ } -+ domain_mkxrefs(i, group_last, next_depth); -+ -+ i = group_last; -+ if (i == last) { -+ break; -+ } -+ } -+ -+ if (depth == 0) { -+ return; -+ } -+ -+ i = doms; -+ do { -+ if (i != target && i->refdom == NULL) { -+ i->refdom = target; -+ i->common_octets = depth; -+ } -+ } while (i++ != last); -+} -+ -+static size_t domain_compactify(CompactDomain *domains, size_t n) -+{ -+ uint8_t *start = domains->self->labels, *outptr = start; -+ size_t i; -+ -+ for (i = 0; i < n; i++) { -+ CompactDomain *cd = domains[i].self; -+ CompactDomain *rd = cd->refdom; -+ -+ if (rd != NULL) { -+ size_t moff = (rd->labels - start) + (rd->len - cd->common_octets); -+ if (moff < 0x3FFFu) { -+ cd->len -= cd->common_octets - 2; -+ cd->labels[cd->len - 1] = moff & 0xFFu; -+ cd->labels[cd->len - 2] = 0xC0u | (moff >> 8); -+ } -+ } -+ -+ if (cd->labels != outptr) { -+ memmove(outptr, cd->labels, cd->len); -+ cd->labels = outptr; -+ } -+ outptr += cd->len; -+ } -+ return outptr - start; -+} -+ -+int translate_dnssearch(Slirp *s, const char **names) -+{ -+ size_t blocks, bsrc_start, bsrc_end, bdst_start; -+ size_t i, num_domains, memreq = 0; -+ uint8_t *result = NULL, *outptr; -+ CompactDomain *domains = NULL; -+ -+ num_domains = g_strv_length((GStrv)(void *)names); -+ if (num_domains == 0) { -+ return -2; -+ } -+ -+ domains = g_malloc(num_domains * sizeof(*domains)); -+ -+ for (i = 0; i < num_domains; i++) { -+ size_t nlen = strlen(names[i]); -+ memreq += nlen + 2; /* 1 zero octet + 1 label length octet */ -+ domains[i].self = domains + i; -+ domains[i].len = nlen; -+ domains[i].common_octets = 0; -+ domains[i].refdom = NULL; -+ } -+ -+ /* reserve extra 2 header bytes for each 255 bytes of output */ -+ memreq += DIV_ROUND_UP(memreq, MAX_OPT_LEN) * OPT_HEADER_LEN; -+ result = g_malloc(memreq * sizeof(*result)); -+ -+ outptr = result; -+ for (i = 0; i < num_domains; i++) { -+ domains[i].labels = outptr; -+ domain_mklabels(domains + i, names[i]); -+ outptr += domains[i].len; -+ } -+ -+ if (outptr == result) { -+ g_free(domains); -+ g_free(result); -+ return -1; -+ } -+ -+ qsort(domains, num_domains, sizeof(*domains), domain_suffix_ord); -+ domain_fixup_order(domains, num_domains); -+ -+ for (i = 1; i < num_domains; i++) { -+ size_t cl = domain_common_label(domains + i - 1, domains + i); -+ domains[i - 1].common_octets = cl; -+ } -+ -+ domain_mkxrefs(domains, domains + num_domains - 1, 0); -+ memreq = domain_compactify(domains, num_domains); -+ -+ blocks = DIV_ROUND_UP(memreq, MAX_OPT_LEN); -+ bsrc_end = memreq; -+ bsrc_start = (blocks - 1) * MAX_OPT_LEN; -+ bdst_start = bsrc_start + blocks * OPT_HEADER_LEN; -+ memreq += blocks * OPT_HEADER_LEN; -+ -+ while (blocks--) { -+ size_t len = bsrc_end - bsrc_start; -+ memmove(result + bdst_start, result + bsrc_start, len); -+ result[bdst_start - 2] = RFC3397_OPT_DOMAIN_SEARCH; -+ result[bdst_start - 1] = len; -+ bsrc_end = bsrc_start; -+ bsrc_start -= MAX_OPT_LEN; -+ bdst_start -= MAX_OPT_LEN + OPT_HEADER_LEN; -+ } -+ -+ g_free(domains); -+ s->vdnssearch = result; -+ s->vdnssearch_len = memreq; -+ return 0; -+} -diff --git a/slirp/src/if.c b/slirp/src/if.c -new file mode 100644 -index 0000000000..23190b5593 ---- /dev/null -+++ b/slirp/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/slirp/src/if.h b/slirp/src/if.h -new file mode 100644 -index 0000000000..7cf9d2750e ---- /dev/null -+++ b/slirp/src/if.h -@@ -0,0 +1,25 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * Copyright (c) 1995 Danny Gasparovski. -+ */ -+ -+#ifndef IF_H -+#define IF_H -+ -+#define IF_COMPRESS 0x01 /* We want compression */ -+#define IF_NOCOMPRESS 0x02 /* Do not do compression */ -+#define IF_AUTOCOMP 0x04 /* Autodetect (default) */ -+#define IF_NOCIDCOMP 0x08 /* CID compression */ -+ -+#define IF_MTU_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 */ -+ -+/* 2 for alignment, 14 for ethernet */ -+#define IF_MAXLINKHDR (2 + ETH_HLEN) -+ -+#endif -diff --git a/slirp/src/ip.h b/slirp/src/ip.h -new file mode 100644 -index 0000000000..e5d4aa8a6d ---- /dev/null -+++ b/slirp/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 -+ -+#if G_BYTE_ORDER == G_BIG_ENDIAN -+#undef NTOHL -+#undef NTOHS -+#undef HTONL -+#undef HTONS -+#define NTOHL(d) -+#define NTOHS(d) -+#define HTONL(d) -+#define HTONS(d) -+#else -+#ifndef NTOHL -+#define NTOHL(d) ((d) = ntohl((d))) -+#endif -+#ifndef NTOHS -+#define NTOHS(d) ((d) = ntohs((uint16_t)(d))) -+#endif -+#ifndef HTONL -+#define HTONL(d) ((d) = htonl((d))) -+#endif -+#ifndef HTONS -+#define HTONS(d) ((d) = htons((uint16_t)(d))) -+#endif -+#endif -+ -+typedef uint32_t n_long; /* long as received from the net */ -+ -+/* -+ * Definitions for internet protocol version 4. -+ * Per RFC 791, September 1981. -+ */ -+#define IPVERSION 4 -+ -+/* -+ * Structure of an internet header, naked of options. -+ */ -+struct ip { -+#if G_BYTE_ORDER == G_BIG_ENDIAN -+ uint8_t ip_v : 4, /* version */ -+ ip_hl : 4; /* header length */ -+#else -+ uint8_t ip_hl : 4, /* header length */ -+ ip_v : 4; /* version */ -+#endif -+ uint8_t ip_tos; /* type of service */ -+ uint16_t ip_len; /* total length */ -+ uint16_t ip_id; /* identification */ -+ uint16_t ip_off; /* fragment offset field */ -+#define IP_DF 0x4000 /* don't fragment flag */ -+#define IP_MF 0x2000 /* more fragments flag */ -+#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ -+ uint8_t ip_ttl; /* time to live */ -+ uint8_t ip_p; /* protocol */ -+ uint16_t ip_sum; /* checksum */ -+ struct in_addr ip_src, ip_dst; /* source and dest address */ -+} SLIRP_PACKED; -+ -+#define IP_MAXPACKET 65535 /* maximum packet size */ -+ -+/* -+ * Definitions for IP type of service (ip_tos) -+ */ -+#define IPTOS_LOWDELAY 0x10 -+#define IPTOS_THROUGHPUT 0x08 -+#define IPTOS_RELIABILITY 0x04 -+ -+/* -+ * Definitions for options. -+ */ -+#define IPOPT_COPIED(o) ((o)&0x80) -+#define IPOPT_CLASS(o) ((o)&0x60) -+#define IPOPT_NUMBER(o) ((o)&0x1f) -+ -+#define IPOPT_CONTROL 0x00 -+#define IPOPT_RESERVED1 0x20 -+#define IPOPT_DEBMEAS 0x40 -+#define IPOPT_RESERVED2 0x60 -+ -+#define IPOPT_EOL 0 /* end of option list */ -+#define IPOPT_NOP 1 /* no operation */ -+ -+#define IPOPT_RR 7 /* record packet route */ -+#define IPOPT_TS 68 /* timestamp */ -+#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ -+#define IPOPT_LSRR 131 /* loose source route */ -+#define IPOPT_SATID 136 /* satnet id */ -+#define IPOPT_SSRR 137 /* strict source route */ -+ -+/* -+ * Offsets to fields in options other than EOL and NOP. -+ */ -+#define IPOPT_OPTVAL 0 /* option ID */ -+#define IPOPT_OLEN 1 /* option length */ -+#define IPOPT_OFFSET 2 /* offset within option */ -+#define IPOPT_MINOFF 4 /* min value of above */ -+ -+/* -+ * Time stamp option structure. -+ */ -+struct ip_timestamp { -+ uint8_t ipt_code; /* IPOPT_TS */ -+ uint8_t ipt_len; /* size of structure (variable) */ -+ uint8_t ipt_ptr; /* index of current entry */ -+#if G_BYTE_ORDER == G_BIG_ENDIAN -+ uint8_t ipt_oflw : 4, /* overflow counter */ -+ ipt_flg : 4; /* flags, see below */ -+#else -+ uint8_t ipt_flg : 4, /* flags, see below */ -+ ipt_oflw : 4; /* overflow counter */ -+#endif -+ union ipt_timestamp { -+ n_long ipt_time[1]; -+ struct ipt_ta { -+ struct in_addr ipt_addr; -+ n_long ipt_time; -+ } ipt_ta[1]; -+ } ipt_timestamp; -+} SLIRP_PACKED; -+ -+/* flag bits for ipt_flg */ -+#define IPOPT_TS_TSONLY 0 /* timestamps only */ -+#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ -+#define IPOPT_TS_PRESPEC 3 /* specified modules only */ -+ -+/* bits for security (not byte swapped) */ -+#define IPOPT_SECUR_UNCLASS 0x0000 -+#define IPOPT_SECUR_CONFID 0xf135 -+#define IPOPT_SECUR_EFTO 0x789a -+#define IPOPT_SECUR_MMMM 0xbc4d -+#define IPOPT_SECUR_RESTR 0xaf13 -+#define IPOPT_SECUR_SECRET 0xd788 -+#define IPOPT_SECUR_TOPSECRET 0x6bc5 -+ -+/* -+ * Internet implementation parameters. -+ */ -+#define MAXTTL 255 /* maximum time to live (seconds) */ -+#define IPDEFTTL 64 /* default ttl, from RFC 1340 */ -+#define IPFRAGTTL 60 /* time to live for frags, slowhz */ -+#define IPTTLDEC 1 /* subtracted when forwarding */ -+ -+#define IP_MSS 576 /* default maximum segment size */ -+ -+#if GLIB_SIZEOF_VOID_P == 4 -+struct mbuf_ptr { -+ struct mbuf *mptr; -+ uint32_t dummy; -+} SLIRP_PACKED; -+#else -+struct mbuf_ptr { -+ struct mbuf *mptr; -+} SLIRP_PACKED; -+#endif -+struct qlink { -+ void *next, *prev; -+}; -+ -+/* -+ * Overlay for ip header used by other protocols (tcp, udp). -+ */ -+struct ipovly { -+ struct mbuf_ptr ih_mbuf; /* backpointer to mbuf */ -+ uint8_t ih_x1; /* (unused) */ -+ uint8_t ih_pr; /* protocol */ -+ uint16_t ih_len; /* protocol length */ -+ struct in_addr ih_src; /* source internet address */ -+ struct in_addr ih_dst; /* destination internet address */ -+} SLIRP_PACKED; -+ -+/* -+ * Ip reassembly queue structure. Each fragment -+ * being reassembled is attached to one of these structures. -+ * They are timed out after ipq_ttl drops to 0, and may also -+ * be reclaimed if memory becomes tight. -+ * size 28 bytes -+ */ -+struct ipq { -+ struct qlink frag_link; /* to ip headers of fragments */ -+ struct qlink ip_link; /* to other reass headers */ -+ uint8_t ipq_ttl; /* time for reass q to live */ -+ uint8_t ipq_p; /* protocol of this fragment */ -+ uint16_t ipq_id; /* sequence id for reassembly */ -+ struct in_addr ipq_src, ipq_dst; -+}; -+ -+/* -+ * Ip header, when holding a fragment. -+ * -+ * Note: ipf_link must be at same offset as frag_link above -+ */ -+struct ipasfrag { -+ struct qlink ipf_link; -+ struct ip ipf_ip; -+}; -+ -+G_STATIC_ASSERT(offsetof(struct ipq, frag_link) == -+ offsetof(struct ipasfrag, ipf_link)); -+ -+#define ipf_off ipf_ip.ip_off -+#define ipf_tos ipf_ip.ip_tos -+#define ipf_len ipf_ip.ip_len -+#define ipf_next ipf_link.next -+#define ipf_prev ipf_link.prev -+ -+#endif -diff --git a/slirp/src/ip6.h b/slirp/src/ip6.h -new file mode 100644 -index 0000000000..0630309d29 ---- /dev/null -+++ b/slirp/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 -+#include -+ -+#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(ð[2], &ip.s6_addr[16 - (ETH_ALEN - 2)], ETH_ALEN - 2); -+} -+ -+/* -+ * Definitions for internet protocol version 6. -+ * Per RFC 2460, December 1998. -+ */ -+#define IP6VERSION 6 -+#define IP6_HOP_LIMIT 255 -+ -+/* -+ * Structure of an internet header, naked of options. -+ */ -+struct ip6 { -+#if G_BYTE_ORDER == G_BIG_ENDIAN -+ uint32_t ip_v : 4, /* version */ -+ ip_tc_hi : 4, /* traffic class */ -+ ip_tc_lo : 4, ip_fl_hi : 4, /* flow label */ -+ ip_fl_lo : 16; -+#else -+ uint32_t ip_tc_hi : 4, ip_v : 4, ip_fl_hi : 4, ip_tc_lo : 4, ip_fl_lo : 16; -+#endif -+ uint16_t ip_pl; /* payload length */ -+ uint8_t ip_nh; /* next header */ -+ uint8_t ip_hl; /* hop limit */ -+ struct in6_addr ip_src, ip_dst; /* source and dest address */ -+}; -+ -+/* -+ * IPv6 pseudo-header used by upper-layer protocols -+ */ -+struct ip6_pseudohdr { -+ struct in6_addr ih_src; /* source internet address */ -+ struct in6_addr ih_dst; /* destination internet address */ -+ uint32_t ih_pl; /* upper-layer packet length */ -+ uint16_t ih_zero_hi; /* zero */ -+ uint8_t ih_zero_lo; /* zero */ -+ uint8_t ih_nh; /* next header */ -+}; -+ -+/* -+ * We don't want to mark these ip6 structs as packed as they are naturally -+ * correctly aligned; instead assert that there is no stray padding. -+ * If we marked the struct as packed then we would be unable to take -+ * the address of any of the fields in it. -+ */ -+G_STATIC_ASSERT(sizeof(struct ip6) == 40); -+G_STATIC_ASSERT(sizeof(struct ip6_pseudohdr) == 40); -+ -+#endif -diff --git a/slirp/src/ip6_icmp.c b/slirp/src/ip6_icmp.c -new file mode 100644 -index 0000000000..d9c872bc97 ---- /dev/null -+++ b/slirp/src/ip6_icmp.c -@@ -0,0 +1,433 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * Copyright (c) 2013 -+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne. -+ */ -+ -+#include "slirp.h" -+#include "ip6_icmp.h" -+ -+#define NDP_Interval \ -+ g_rand_int_range(slirp->grand, NDP_MinRtrAdvInterval, NDP_MaxRtrAdvInterval) -+ -+static void ra_timer_handler(void *opaque) -+{ -+ Slirp *slirp = opaque; -+ -+ slirp->cb->timer_mod(slirp->ra_timer, -+ slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS + -+ NDP_Interval, -+ slirp->opaque); -+ ndp_send_ra(slirp); -+} -+ -+void icmp6_init(Slirp *slirp) -+{ -+ if (!slirp->in6_enabled) { -+ return; -+ } -+ -+ slirp->ra_timer = -+ slirp->cb->timer_new(ra_timer_handler, slirp, slirp->opaque); -+ slirp->cb->timer_mod(slirp->ra_timer, -+ slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS + -+ NDP_Interval, -+ slirp->opaque); -+} -+ -+void icmp6_cleanup(Slirp *slirp) -+{ -+ if (!slirp->in6_enabled) { -+ return; -+ } -+ -+ slirp->cb->timer_free(slirp->ra_timer, slirp->opaque); -+} -+ -+static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 *ip, -+ struct icmp6 *icmp) -+{ -+ struct mbuf *t = m_get(slirp); -+ t->m_len = sizeof(struct ip6) + ntohs(ip->ip_pl); -+ memcpy(t->m_data, m->m_data, t->m_len); -+ -+ /* IPv6 Packet */ -+ struct ip6 *rip = mtod(t, struct ip6 *); -+ rip->ip_dst = ip->ip_src; -+ rip->ip_src = ip->ip_dst; -+ -+ /* ICMPv6 packet */ -+ t->m_data += sizeof(struct ip6); -+ struct icmp6 *ricmp = mtod(t, struct icmp6 *); -+ ricmp->icmp6_type = ICMP6_ECHO_REPLY; -+ ricmp->icmp6_cksum = 0; -+ -+ /* Checksum */ -+ t->m_data -= sizeof(struct ip6); -+ ricmp->icmp6_cksum = ip6_cksum(t); -+ -+ ip6_output(NULL, t, 0); -+} -+ -+void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code) -+{ -+ Slirp *slirp = m->slirp; -+ struct mbuf *t; -+ struct ip6 *ip = mtod(m, struct ip6 *); -+ char addrstr[INET6_ADDRSTRLEN]; -+ -+ DEBUG_CALL("icmp6_send_error"); -+ DEBUG_ARG("type = %d, code = %d", type, code); -+ -+ if (IN6_IS_ADDR_MULTICAST(&ip->ip_src) || in6_zero(&ip->ip_src)) { -+ /* TODO icmp error? */ -+ return; -+ } -+ -+ t = m_get(slirp); -+ -+ /* IPv6 packet */ -+ struct ip6 *rip = mtod(t, struct ip6 *); -+ rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR; -+ rip->ip_dst = ip->ip_src; -+ inet_ntop(AF_INET6, &rip->ip_dst, addrstr, INET6_ADDRSTRLEN); -+ DEBUG_ARG("target = %s", addrstr); -+ -+ rip->ip_nh = IPPROTO_ICMPV6; -+ const int error_data_len = MIN( -+ m->m_len, 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); -+ -+ /* ICMPv6 packet */ -+ t->m_data += sizeof(struct ip6); -+ struct icmp6 *ricmp = mtod(t, struct icmp6 *); -+ ricmp->icmp6_type = type; -+ ricmp->icmp6_code = code; -+ ricmp->icmp6_cksum = 0; -+ -+ switch (type) { -+ case ICMP6_UNREACH: -+ case ICMP6_TIMXCEED: -+ ricmp->icmp6_err.unused = 0; -+ break; -+ case ICMP6_TOOBIG: -+ ricmp->icmp6_err.mtu = htonl(slirp->if_mtu); -+ break; -+ case ICMP6_PARAMPROB: -+ /* TODO: Handle this case */ -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ t->m_data += ICMP6_ERROR_MINLEN; -+ memcpy(t->m_data, m->m_data, error_data_len); -+ -+ /* Checksum */ -+ t->m_data -= ICMP6_ERROR_MINLEN; -+ t->m_data -= sizeof(struct ip6); -+ ricmp->icmp6_cksum = ip6_cksum(t); -+ -+ ip6_output(NULL, t, 0); -+} -+ -+/* -+ * Send NDP Router Advertisement -+ */ -+void ndp_send_ra(Slirp *slirp) -+{ -+ DEBUG_CALL("ndp_send_ra"); -+ -+ /* Build IPv6 packet */ -+ struct mbuf *t = m_get(slirp); -+ struct ip6 *rip = mtod(t, struct ip6 *); -+ size_t pl_size = 0; -+ struct in6_addr addr; -+ uint32_t scope_id; -+ -+ rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR; -+ rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST; -+ rip->ip_nh = IPPROTO_ICMPV6; -+ -+ /* Build ICMPv6 packet */ -+ t->m_data += sizeof(struct ip6); -+ struct icmp6 *ricmp = mtod(t, struct icmp6 *); -+ ricmp->icmp6_type = ICMP6_NDP_RA; -+ ricmp->icmp6_code = 0; -+ ricmp->icmp6_cksum = 0; -+ -+ /* NDP */ -+ ricmp->icmp6_nra.chl = NDP_AdvCurHopLimit; -+ ricmp->icmp6_nra.M = NDP_AdvManagedFlag; -+ ricmp->icmp6_nra.O = NDP_AdvOtherConfigFlag; -+ ricmp->icmp6_nra.reserved = 0; -+ ricmp->icmp6_nra.lifetime = htons(NDP_AdvDefaultLifetime); -+ ricmp->icmp6_nra.reach_time = htonl(NDP_AdvReachableTime); -+ ricmp->icmp6_nra.retrans_time = htonl(NDP_AdvRetransTime); -+ t->m_data += ICMP6_NDP_RA_MINLEN; -+ pl_size += ICMP6_NDP_RA_MINLEN; -+ -+ /* Source link-layer address (NDP option) */ -+ struct ndpopt *opt = mtod(t, struct ndpopt *); -+ opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE; -+ opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8; -+ in6_compute_ethaddr(rip->ip_src, opt->ndpopt_linklayer); -+ t->m_data += NDPOPT_LINKLAYER_LEN; -+ pl_size += NDPOPT_LINKLAYER_LEN; -+ -+ /* Prefix information (NDP option) */ -+ struct ndpopt *opt2 = mtod(t, struct ndpopt *); -+ opt2->ndpopt_type = NDPOPT_PREFIX_INFO; -+ opt2->ndpopt_len = NDPOPT_PREFIXINFO_LEN / 8; -+ opt2->ndpopt_prefixinfo.prefix_length = slirp->vprefix_len; -+ opt2->ndpopt_prefixinfo.L = 1; -+ opt2->ndpopt_prefixinfo.A = 1; -+ opt2->ndpopt_prefixinfo.reserved1 = 0; -+ opt2->ndpopt_prefixinfo.valid_lt = htonl(NDP_AdvValidLifetime); -+ opt2->ndpopt_prefixinfo.pref_lt = htonl(NDP_AdvPrefLifetime); -+ opt2->ndpopt_prefixinfo.reserved2 = 0; -+ opt2->ndpopt_prefixinfo.prefix = slirp->vprefix_addr6; -+ t->m_data += NDPOPT_PREFIXINFO_LEN; -+ pl_size += NDPOPT_PREFIXINFO_LEN; -+ -+ /* Prefix information (NDP option) */ -+ if (get_dns6_addr(&addr, &scope_id) >= 0) { -+ /* Host system does have an IPv6 DNS server, announce our proxy. */ -+ struct ndpopt *opt3 = mtod(t, struct ndpopt *); -+ opt3->ndpopt_type = NDPOPT_RDNSS; -+ opt3->ndpopt_len = NDPOPT_RDNSS_LEN / 8; -+ opt3->ndpopt_rdnss.reserved = 0; -+ opt3->ndpopt_rdnss.lifetime = htonl(2 * NDP_MaxRtrAdvInterval); -+ opt3->ndpopt_rdnss.addr = slirp->vnameserver_addr6; -+ t->m_data += NDPOPT_RDNSS_LEN; -+ pl_size += NDPOPT_RDNSS_LEN; -+ } -+ -+ rip->ip_pl = htons(pl_size); -+ t->m_data -= sizeof(struct ip6) + pl_size; -+ t->m_len = sizeof(struct ip6) + pl_size; -+ -+ /* ICMPv6 Checksum */ -+ ricmp->icmp6_cksum = ip6_cksum(t); -+ -+ ip6_output(NULL, t, 0); -+} -+ -+/* -+ * Send NDP Neighbor Solitication -+ */ -+void ndp_send_ns(Slirp *slirp, struct in6_addr addr) -+{ -+ char addrstr[INET6_ADDRSTRLEN]; -+ -+ inet_ntop(AF_INET6, &addr, addrstr, INET6_ADDRSTRLEN); -+ -+ DEBUG_CALL("ndp_send_ns"); -+ DEBUG_ARG("target = %s", addrstr); -+ -+ /* Build IPv6 packet */ -+ struct mbuf *t = m_get(slirp); -+ struct ip6 *rip = mtod(t, struct ip6 *); -+ rip->ip_src = slirp->vhost_addr6; -+ rip->ip_dst = (struct in6_addr)SOLICITED_NODE_PREFIX; -+ memcpy(&rip->ip_dst.s6_addr[13], &addr.s6_addr[13], 3); -+ rip->ip_nh = IPPROTO_ICMPV6; -+ rip->ip_pl = htons(ICMP6_NDP_NS_MINLEN + NDPOPT_LINKLAYER_LEN); -+ t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl); -+ -+ /* Build ICMPv6 packet */ -+ t->m_data += sizeof(struct ip6); -+ struct icmp6 *ricmp = mtod(t, struct icmp6 *); -+ ricmp->icmp6_type = ICMP6_NDP_NS; -+ ricmp->icmp6_code = 0; -+ ricmp->icmp6_cksum = 0; -+ -+ /* NDP */ -+ ricmp->icmp6_nns.reserved = 0; -+ ricmp->icmp6_nns.target = addr; -+ -+ /* Build NDP option */ -+ t->m_data += ICMP6_NDP_NS_MINLEN; -+ struct ndpopt *opt = mtod(t, struct ndpopt *); -+ opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE; -+ opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8; -+ in6_compute_ethaddr(slirp->vhost_addr6, opt->ndpopt_linklayer); -+ -+ /* ICMPv6 Checksum */ -+ t->m_data -= ICMP6_NDP_NA_MINLEN; -+ t->m_data -= sizeof(struct ip6); -+ ricmp->icmp6_cksum = ip6_cksum(t); -+ -+ ip6_output(NULL, t, 1); -+} -+ -+/* -+ * Send NDP Neighbor Advertisement -+ */ -+static void ndp_send_na(Slirp *slirp, struct ip6 *ip, struct icmp6 *icmp) -+{ -+ /* Build IPv6 packet */ -+ struct mbuf *t = m_get(slirp); -+ struct ip6 *rip = mtod(t, struct ip6 *); -+ rip->ip_src = icmp->icmp6_nns.target; -+ if (in6_zero(&ip->ip_src)) { -+ rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST; -+ } else { -+ rip->ip_dst = ip->ip_src; -+ } -+ rip->ip_nh = IPPROTO_ICMPV6; -+ rip->ip_pl = htons(ICMP6_NDP_NA_MINLEN + NDPOPT_LINKLAYER_LEN); -+ t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl); -+ -+ /* Build ICMPv6 packet */ -+ t->m_data += sizeof(struct ip6); -+ struct icmp6 *ricmp = mtod(t, struct icmp6 *); -+ ricmp->icmp6_type = ICMP6_NDP_NA; -+ ricmp->icmp6_code = 0; -+ ricmp->icmp6_cksum = 0; -+ -+ /* NDP */ -+ ricmp->icmp6_nna.R = NDP_IsRouter; -+ ricmp->icmp6_nna.S = !IN6_IS_ADDR_MULTICAST(&rip->ip_dst); -+ ricmp->icmp6_nna.O = 1; -+ ricmp->icmp6_nna.reserved_hi = 0; -+ ricmp->icmp6_nna.reserved_lo = 0; -+ ricmp->icmp6_nna.target = icmp->icmp6_nns.target; -+ -+ /* Build NDP option */ -+ t->m_data += ICMP6_NDP_NA_MINLEN; -+ struct ndpopt *opt = mtod(t, struct ndpopt *); -+ opt->ndpopt_type = NDPOPT_LINKLAYER_TARGET; -+ opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8; -+ in6_compute_ethaddr(ricmp->icmp6_nna.target, opt->ndpopt_linklayer); -+ -+ /* ICMPv6 Checksum */ -+ t->m_data -= ICMP6_NDP_NA_MINLEN; -+ t->m_data -= sizeof(struct ip6); -+ ricmp->icmp6_cksum = ip6_cksum(t); -+ -+ ip6_output(NULL, t, 0); -+} -+ -+/* -+ * Process a NDP message -+ */ -+static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip, -+ struct icmp6 *icmp) -+{ -+ m->m_len += ETH_HLEN; -+ m->m_data -= ETH_HLEN; -+ struct ethhdr *eth = mtod(m, struct ethhdr *); -+ m->m_len -= ETH_HLEN; -+ m->m_data += ETH_HLEN; -+ -+ switch (icmp->icmp6_type) { -+ case ICMP6_NDP_RS: -+ DEBUG_CALL(" type = Router Solicitation"); -+ if (ip->ip_hl == 255 && icmp->icmp6_code == 0 && -+ ntohs(ip->ip_pl) >= ICMP6_NDP_RS_MINLEN) { -+ /* Gratuitous NDP */ -+ ndp_table_add(slirp, ip->ip_src, eth->h_source); -+ -+ ndp_send_ra(slirp); -+ } -+ break; -+ -+ case ICMP6_NDP_RA: -+ DEBUG_CALL(" type = Router Advertisement"); -+ slirp->cb->guest_error("Warning: guest sent NDP RA, but shouldn't", -+ slirp->opaque); -+ break; -+ -+ case ICMP6_NDP_NS: -+ DEBUG_CALL(" type = Neighbor Solicitation"); -+ if (ip->ip_hl == 255 && icmp->icmp6_code == 0 && -+ !IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nns.target) && -+ ntohs(ip->ip_pl) >= ICMP6_NDP_NS_MINLEN && -+ (!in6_zero(&ip->ip_src) || -+ in6_solicitednode_multicast(&ip->ip_dst))) { -+ if (in6_equal_host(&icmp->icmp6_nns.target)) { -+ /* Gratuitous NDP */ -+ ndp_table_add(slirp, ip->ip_src, eth->h_source); -+ ndp_send_na(slirp, ip, icmp); -+ } -+ } -+ break; -+ -+ case ICMP6_NDP_NA: -+ DEBUG_CALL(" type = Neighbor Advertisement"); -+ if (ip->ip_hl == 255 && icmp->icmp6_code == 0 && -+ ntohs(ip->ip_pl) >= ICMP6_NDP_NA_MINLEN && -+ !IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nna.target) && -+ (!IN6_IS_ADDR_MULTICAST(&ip->ip_dst) || icmp->icmp6_nna.S == 0)) { -+ ndp_table_add(slirp, ip->ip_src, eth->h_source); -+ } -+ break; -+ -+ case ICMP6_NDP_REDIRECT: -+ DEBUG_CALL(" type = Redirect"); -+ slirp->cb->guest_error( -+ "Warning: guest sent NDP REDIRECT, but shouldn't", slirp->opaque); -+ break; -+ } -+} -+ -+/* -+ * Process a received ICMPv6 message. -+ */ -+void icmp6_input(struct mbuf *m) -+{ -+ struct icmp6 *icmp; -+ struct ip6 *ip = mtod(m, struct ip6 *); -+ Slirp *slirp = m->slirp; -+ int hlen = sizeof(struct ip6); -+ -+ DEBUG_CALL("icmp6_input"); -+ DEBUG_ARG("m = %p", m); -+ DEBUG_ARG("m_len = %d", m->m_len); -+ -+ if (ntohs(ip->ip_pl) < ICMP6_MINLEN) { -+ goto end; -+ } -+ -+ if (ip6_cksum(m)) { -+ goto end; -+ } -+ -+ m->m_len -= hlen; -+ m->m_data += hlen; -+ icmp = mtod(m, struct icmp6 *); -+ m->m_len += hlen; -+ m->m_data -= hlen; -+ -+ DEBUG_ARG("icmp6_type = %d", icmp->icmp6_type); -+ switch (icmp->icmp6_type) { -+ case ICMP6_ECHO_REQUEST: -+ if (in6_equal_host(&ip->ip_dst)) { -+ icmp6_send_echoreply(m, slirp, ip, icmp); -+ } else { -+ /* TODO */ -+ g_critical("external icmpv6 not supported yet"); -+ } -+ break; -+ -+ case ICMP6_NDP_RS: -+ case ICMP6_NDP_RA: -+ case ICMP6_NDP_NS: -+ case ICMP6_NDP_NA: -+ case ICMP6_NDP_REDIRECT: -+ ndp_input(m, slirp, ip, icmp); -+ break; -+ -+ case ICMP6_UNREACH: -+ case ICMP6_TOOBIG: -+ case ICMP6_TIMXCEED: -+ case ICMP6_PARAMPROB: -+ /* XXX? report error? close socket? */ -+ default: -+ break; -+ } -+ -+end: -+ m_free(m); -+} -diff --git a/slirp/src/ip6_icmp.h b/slirp/src/ip6_icmp.h -new file mode 100644 -index 0000000000..c37e60f28d ---- /dev/null -+++ b/slirp/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/slirp/src/ip6_input.c b/slirp/src/ip6_input.c -new file mode 100644 -index 0000000000..a83e4f8e3d ---- /dev/null -+++ b/slirp/src/ip6_input.c -@@ -0,0 +1,85 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * Copyright (c) 2013 -+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne. -+ */ -+ -+#include "slirp.h" -+#include "ip6_icmp.h" -+ -+/* -+ * IP initialization: fill in IP protocol switch table. -+ * All protocols not implemented in kernel go to raw IP protocol handler. -+ */ -+void ip6_init(Slirp *slirp) -+{ -+ icmp6_init(slirp); -+} -+ -+void ip6_cleanup(Slirp *slirp) -+{ -+ icmp6_cleanup(slirp); -+} -+ -+void ip6_input(struct mbuf *m) -+{ -+ struct ip6 *ip6; -+ Slirp *slirp = m->slirp; -+ -+ if (!slirp->in6_enabled) { -+ goto bad; -+ } -+ -+ DEBUG_CALL("ip6_input"); -+ DEBUG_ARG("m = %p", m); -+ DEBUG_ARG("m_len = %d", m->m_len); -+ -+ if (m->m_len < sizeof(struct ip6)) { -+ goto bad; -+ } -+ -+ ip6 = mtod(m, struct ip6 *); -+ -+ if (ip6->ip_v != IP6VERSION) { -+ goto bad; -+ } -+ -+ if (ntohs(ip6->ip_pl) + sizeof(struct ip6) > slirp->if_mtu) { -+ icmp6_send_error(m, ICMP6_TOOBIG, 0); -+ goto bad; -+ } -+ -+ // Check if the message size is big enough to hold what's -+ // set in the payload length header. If not this is an invalid -+ // packet -+ if (m->m_len < ntohs(ip6->ip_pl) + sizeof(struct ip6)) { -+ goto bad; -+ } -+ -+ /* check ip_ttl for a correct ICMP reply */ -+ if (ip6->ip_hl == 0) { -+ icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS); -+ goto bad; -+ } -+ -+ /* -+ * Switch out to protocol's input routine. -+ */ -+ switch (ip6->ip_nh) { -+ case IPPROTO_TCP: -+ NTOHS(ip6->ip_pl); -+ tcp_input(m, sizeof(struct ip6), (struct socket *)NULL, AF_INET6); -+ break; -+ case IPPROTO_UDP: -+ udp6_input(m); -+ break; -+ case IPPROTO_ICMPV6: -+ icmp6_input(m); -+ break; -+ default: -+ m_free(m); -+ } -+ return; -+bad: -+ m_free(m); -+} -diff --git a/slirp/src/ip6_output.c b/slirp/src/ip6_output.c -new file mode 100644 -index 0000000000..b86110662c ---- /dev/null -+++ b/slirp/src/ip6_output.c -@@ -0,0 +1,39 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * Copyright (c) 2013 -+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne. -+ */ -+ -+#include "slirp.h" -+ -+/* Number of packets queued before we start sending -+ * (to prevent allocing too many mbufs) */ -+#define IF6_THRESH 10 -+ -+/* -+ * IPv6 output. The packet in mbuf chain m contains a IP header -+ */ -+int ip6_output(struct socket *so, struct mbuf *m, int fast) -+{ -+ struct ip6 *ip = mtod(m, struct ip6 *); -+ -+ DEBUG_CALL("ip6_output"); -+ DEBUG_ARG("so = %p", so); -+ DEBUG_ARG("m = %p", m); -+ -+ /* Fill IPv6 header */ -+ ip->ip_v = IP6VERSION; -+ ip->ip_hl = IP6_HOP_LIMIT; -+ ip->ip_tc_hi = 0; -+ ip->ip_tc_lo = 0; -+ ip->ip_fl_hi = 0; -+ ip->ip_fl_lo = 0; -+ -+ if (fast) { -+ if_encap(m->slirp, m); -+ } else { -+ if_output(so, m); -+ } -+ -+ return 0; -+} -diff --git a/slirp/src/ip_icmp.c b/slirp/src/ip_icmp.c -new file mode 100644 -index 0000000000..13a0e55085 ---- /dev/null -+++ b/slirp/src/ip_icmp.c -@@ -0,0 +1,492 @@ -+/* 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) -+{ -+ struct socket *so, *so_next; -+ -+ for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) { -+ so_next = so->so_next; -+ icmp_detach(so); -+ } -+} -+ -+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; -+ } -+ -+ if (slirp_bind_outbound(so, AF_INET) != 0) { -+ // bind failed - close socket -+ closesocket(so->s); -+ 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]; -+ slirp_pstrcpy(bufa, sizeof(bufa), inet_ntoa(ip->ip_src)); -+ slirp_pstrcpy(bufb, sizeof(bufb), inet_ntoa(ip->ip_dst)); -+ DEBUG_MISC(" %.16s to %.16s", bufa, bufb); -+ } -+ if (ip->ip_off & IP_OFFMASK) -+ goto end_error; /* Only reply to fragment 0 */ -+ -+ /* Do not reply to source-only IPs */ -+ if ((ip->ip_src.s_addr & htonl(~(0xf << 28))) == 0) { -+ goto end_error; -+ } -+ -+ shlen = ip->ip_hl << 2; -+ s_ip_len = ip->ip_len; -+ if (ip->ip_p == IPPROTO_ICMP) { -+ icp = (struct icmp *)((char *)ip + shlen); -+ /* -+ * Assume any unknown ICMP type is an error. This isn't -+ * specified by the RFC, but think about it.. -+ */ -+ if (icp->icmp_type > 18 || icmp_flush[icp->icmp_type]) -+ goto end_error; -+ } -+ -+ /* make a copy */ -+ m = m_get(msrc->slirp); -+ if (!m) { -+ goto end_error; -+ } -+ -+ { -+ int new_m_size; -+ new_m_size = -+ sizeof(struct ip) + ICMP_MINLEN + msrc->m_len + ICMP_MAXDATALEN; -+ if (new_m_size > m->m_size) -+ m_inc(m, new_m_size); -+ } -+ memcpy(m->m_data, msrc->m_data, msrc->m_len); -+ m->m_len = msrc->m_len; /* copy msrc to m */ -+ -+ /* make the header of the reply packet */ -+ ip = mtod(m, struct ip *); -+ hlen = sizeof(struct ip); /* no options in reply */ -+ -+ /* fill in icmp */ -+ m->m_data += hlen; -+ m->m_len -= hlen; -+ -+ icp = mtod(m, struct icmp *); -+ -+ if (minsize) -+ s_ip_len = shlen + ICMP_MINLEN; /* return header+8b only */ -+ else if (s_ip_len > ICMP_MAXDATALEN) /* maximum size */ -+ s_ip_len = ICMP_MAXDATALEN; -+ -+ m->m_len = ICMP_MINLEN + s_ip_len; /* 8 bytes ICMP header */ -+ -+ /* min. size = 8+sizeof(struct ip)+8 */ -+ -+ icp->icmp_type = type; -+ icp->icmp_code = code; -+ icp->icmp_id = 0; -+ icp->icmp_seq = 0; -+ -+ memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */ -+ HTONS(icp->icmp_ip.ip_len); -+ HTONS(icp->icmp_ip.ip_id); -+ HTONS(icp->icmp_ip.ip_off); -+ -+ if (message && WITH_ICMP_ERROR_MSG) { /* append message to ICMP packet */ -+ int message_len; -+ char *cpnt; -+ message_len = strlen(message); -+ if (message_len > ICMP_MAXDATALEN) -+ message_len = ICMP_MAXDATALEN; -+ cpnt = (char *)m->m_data + m->m_len; -+ memcpy(cpnt, message, message_len); -+ m->m_len += message_len; -+ } -+ -+ icp->icmp_cksum = 0; -+ icp->icmp_cksum = cksum(m, m->m_len); -+ -+ m->m_data -= hlen; -+ m->m_len += hlen; -+ -+ /* fill in ip */ -+ ip->ip_hl = hlen >> 2; -+ ip->ip_len = m->m_len; -+ -+ ip->ip_tos = ((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */ -+ -+ ip->ip_ttl = MAXTTL; -+ ip->ip_p = IPPROTO_ICMP; -+ ip->ip_dst = ip->ip_src; /* ip addresses */ -+ ip->ip_src = m->slirp->vhost_addr; -+ -+ (void)ip_output((struct socket *)NULL, m); -+ -+end_error: -+ return; -+} -+#undef ICMP_MAXDATALEN -+ -+/* -+ * Reflect the ip packet back to the source -+ */ -+void icmp_reflect(struct mbuf *m) -+{ -+ register struct ip *ip = mtod(m, struct ip *); -+ int hlen = ip->ip_hl << 2; -+ int optlen = hlen - sizeof(struct ip); -+ register struct icmp *icp; -+ -+ /* -+ * Send an icmp packet back to the ip level, -+ * after supplying a checksum. -+ */ -+ m->m_data += hlen; -+ m->m_len -= hlen; -+ icp = mtod(m, struct icmp *); -+ -+ icp->icmp_type = ICMP_ECHOREPLY; -+ icp->icmp_cksum = 0; -+ icp->icmp_cksum = cksum(m, ip->ip_len - hlen); -+ -+ m->m_data -= hlen; -+ m->m_len += hlen; -+ -+ /* fill in ip */ -+ if (optlen > 0) { -+ /* -+ * Strip out original options by copying rest of first -+ * mbuf's data back, and adjust the IP length. -+ */ -+ memmove((char *)(ip + 1), (char *)ip + hlen, -+ (unsigned)(m->m_len - hlen)); -+ hlen -= optlen; -+ ip->ip_hl = hlen >> 2; -+ ip->ip_len -= optlen; -+ m->m_len -= optlen; -+ } -+ -+ ip->ip_ttl = MAXTTL; -+ { /* swap */ -+ struct in_addr icmp_dst; -+ icmp_dst = ip->ip_dst; -+ ip->ip_dst = ip->ip_src; -+ ip->ip_src = icmp_dst; -+ } -+ -+ (void)ip_output((struct socket *)NULL, m); -+} -+ -+void icmp_receive(struct socket *so) -+{ -+ struct mbuf *m = so->so_m; -+ struct ip *ip = mtod(m, struct ip *); -+ int hlen = ip->ip_hl << 2; -+ uint8_t error_code; -+ struct icmp *icp; -+ int id, len; -+ -+ m->m_data += hlen; -+ m->m_len -= hlen; -+ icp = mtod(m, struct icmp *); -+ -+ id = icp->icmp_id; -+ len = recv(so->s, icp, M_ROOM(m), 0); -+ /* -+ * The behavior of reading SOCK_DGRAM+IPPROTO_ICMP sockets is inconsistent -+ * between host OSes. On Linux, only the ICMP header and payload is -+ * included. On macOS/Darwin, the socket acts like a raw socket and -+ * includes the IP header as well. On other BSDs, SOCK_DGRAM+IPPROTO_ICMP -+ * sockets aren't supported at all, so we treat them like raw sockets. It -+ * isn't possible to detect this difference at runtime, so we must use an -+ * #ifdef to determine if we need to remove the IP header. -+ */ -+#ifdef CONFIG_BSD -+ if (len >= sizeof(struct ip)) { -+ struct ip *inner_ip = mtod(m, struct ip *); -+ int inner_hlen = inner_ip->ip_hl << 2; -+ if (inner_hlen > len) { -+ len = -1; -+ errno = -EINVAL; -+ } else { -+ len -= inner_hlen; -+ memmove(icp, (unsigned char *)icp + inner_hlen, len); -+ } -+ } else { -+ len = -1; -+ errno = -EINVAL; -+ } -+#endif -+ icp->icmp_id = id; -+ -+ m->m_data -= hlen; -+ m->m_len += hlen; -+ -+ if (len == -1 || len == 0) { -+ if (errno == ENETUNREACH) { -+ error_code = ICMP_UNREACH_NET; -+ } else { -+ error_code = ICMP_UNREACH_HOST; -+ } -+ DEBUG_MISC(" udp icmp rx errno = %d-%s", errno, strerror(errno)); -+ icmp_send_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno)); -+ } else { -+ icmp_reflect(so->so_m); -+ so->so_m = NULL; /* Don't m_free() it again! */ -+ } -+ icmp_detach(so); -+} -diff --git a/slirp/src/ip_icmp.h b/slirp/src/ip_icmp.h -new file mode 100644 -index 0000000000..84707db247 ---- /dev/null -+++ b/slirp/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/slirp/src/ip_input.c b/slirp/src/ip_input.c -new file mode 100644 -index 0000000000..7f017a238a ---- /dev/null -+++ b/slirp/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) { -+ struct ipasfrag *prev; -+ 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; -+ } -+ prev = q; -+ q = q->ipf_next; -+ ip_deq(prev); -+ m_free(dtom(slirp, 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 delta = (char *)q - (m->m_flags & M_EXT ? m->m_ext : m->m_dat); -+ -+ 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 (m->m_flags & M_EXT) { -+ 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); -+ memmove(opts, opts + olen, (unsigned)i); -+ m->m_len -= olen; -+ -+ ip->ip_hl = sizeof(struct ip) >> 2; -+} -diff --git a/slirp/src/ip_output.c b/slirp/src/ip_output.c -new file mode 100644 -index 0000000000..22916a37df ---- /dev/null -+++ b/slirp/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/slirp/src/libslirp-version.h.in b/slirp/src/libslirp-version.h.in -new file mode 100644 -index 0000000000..faa6c85952 ---- /dev/null -+++ b/slirp/src/libslirp-version.h.in -@@ -0,0 +1,24 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+#ifndef LIBSLIRP_VERSION_H_ -+#define LIBSLIRP_VERSION_H_ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#define SLIRP_MAJOR_VERSION @SLIRP_MAJOR_VERSION@ -+#define SLIRP_MINOR_VERSION @SLIRP_MINOR_VERSION@ -+#define SLIRP_MICRO_VERSION @SLIRP_MICRO_VERSION@ -+#define SLIRP_VERSION_STRING @SLIRP_VERSION_STRING@ -+ -+#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/slirp/src/libslirp.h b/slirp/src/libslirp.h -new file mode 100644 -index 0000000000..fb4c7e882c ---- /dev/null -+++ b/slirp/src/libslirp.h -@@ -0,0 +1,171 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+#ifndef LIBSLIRP_H -+#define LIBSLIRP_H -+ -+#include -+#include -+#include -+ -+#ifdef _WIN32 -+#include -+#include -+#else -+#include -+#include -+#endif -+ -+#include "libslirp-version.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef struct Slirp Slirp; -+ -+enum { -+ SLIRP_POLL_IN = 1 << 0, -+ SLIRP_POLL_OUT = 1 << 1, -+ SLIRP_POLL_PRI = 1 << 2, -+ SLIRP_POLL_ERR = 1 << 3, -+ SLIRP_POLL_HUP = 1 << 4, -+}; -+ -+typedef ssize_t (*SlirpReadCb)(void *buf, size_t len, void *opaque); -+typedef ssize_t (*SlirpWriteCb)(const void *buf, size_t len, void *opaque); -+typedef void (*SlirpTimerCb)(void *opaque); -+typedef int (*SlirpAddPollCb)(int fd, int events, void *opaque); -+typedef int (*SlirpGetREventsCb)(int idx, void *opaque); -+ -+/* -+ * Callbacks from slirp -+ */ -+typedef struct SlirpCb { -+ /* -+ * Send an ethernet frame to the guest network. The opaque -+ * parameter is the one given to slirp_init(). The function -+ * doesn't need to send all the data and may return 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/slirp/src/mbuf.h b/slirp/src/mbuf.h -new file mode 100644 -index 0000000000..546e7852c5 ---- /dev/null -+++ b/slirp/src/mbuf.h -@@ -0,0 +1,127 @@ -+/* 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. -+ * -+ * @(#)mbuf.h 8.3 (Berkeley) 1/21/94 -+ * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp -+ */ -+ -+#ifndef MBUF_H -+#define MBUF_H -+ -+/* -+ * Macros for type conversion -+ * mtod(m,t) - convert mbuf pointer to data pointer of correct type -+ */ -+#define mtod(m, t) ((t)(m)->m_data) -+ -+/* XXX About mbufs for slirp: -+ * Only one mbuf is ever used in a chain, for each "cell" of data. -+ * m_nextpkt points to the next packet, if fragmented. -+ * If the data is too large, the M_EXT is used, and a larger block -+ * is alloced. Therefore, m_free[m] must check for M_EXT and if set -+ * free the m_ext. This is inefficient memory-wise, but who cares. -+ */ -+ -+/* -+ * mbufs allow to have a gap between the start of the allocated buffer (m_ext if -+ * M_EXT is set, m_dat otherwise) and the in-use data: -+ * -+ * |--gapsize----->|---m_len-------> -+ * |----------m_size------------------------------> -+ * |----M_ROOM--------------------> -+ * |-M_FREEROOM--> -+ * -+ * ^ ^ ^ -+ * m_dat/m_ext m_data end of buffer -+ */ -+ -+/* -+ * How much room is in the mbuf, from m_data to the end of the mbuf -+ */ -+#define M_ROOM(m) \ -+ ((m->m_flags & M_EXT) ? (((m)->m_ext + (m)->m_size) - (m)->m_data) : \ -+ (((m)->m_dat + (m)->m_size) - (m)->m_data)) -+ -+/* -+ * How much free room there is -+ */ -+#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len) -+ -+struct mbuf { -+ /* XXX should union some of these! */ -+ /* header at beginning of each mbuf: */ -+ struct mbuf *m_next; /* Linked list of mbufs */ -+ struct mbuf *m_prev; -+ struct mbuf *m_nextpkt; /* Next packet in queue/record */ -+ struct mbuf *m_prevpkt; /* Flags aren't used in the output queue */ -+ int m_flags; /* Misc flags */ -+ -+ int m_size; /* Size of mbuf, from m_dat or m_ext */ -+ struct socket *m_so; -+ -+ char *m_data; /* Current location of data */ -+ int m_len; /* Amount of data in this mbuf, from m_data */ -+ -+ Slirp *slirp; -+ bool resolution_requested; -+ uint64_t expiration_date; -+ char *m_ext; -+ /* start of dynamic buffer area, must be last element */ -+ char m_dat[]; -+}; -+ -+#define ifq_prev m_prev -+#define ifq_next m_next -+#define ifs_prev m_prevpkt -+#define ifs_next m_nextpkt -+#define ifq_so m_so -+ -+#define M_EXT 0x01 /* m_ext points to more (malloced) data */ -+#define M_FREELIST 0x02 /* mbuf is on free list */ -+#define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */ -+#define M_DOFREE \ -+ 0x08 /* when m_free is called on the mbuf, free() \ -+ * it rather than putting it on the free list */ -+ -+void m_init(Slirp *); -+void m_cleanup(Slirp *slirp); -+struct mbuf *m_get(Slirp *); -+void m_free(struct mbuf *); -+void m_cat(register struct mbuf *, register struct mbuf *); -+void m_inc(struct mbuf *, int); -+void m_adj(struct mbuf *, int); -+int m_copy(struct mbuf *, struct mbuf *, int, int); -+struct mbuf *dtom(Slirp *, void *); -+ -+static inline void ifs_init(struct mbuf *ifm) -+{ -+ ifm->ifs_next = ifm->ifs_prev = ifm; -+} -+ -+#endif -diff --git a/slirp/src/misc.c b/slirp/src/misc.c -new file mode 100644 -index 0000000000..e6bc0a207d ---- /dev/null -+++ b/slirp/src/misc.c -@@ -0,0 +1,390 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * Copyright (c) 1995 Danny Gasparovski. -+ */ -+ -+#include "slirp.h" -+#ifdef G_OS_UNIX -+#include -+#endif -+ -+inline void insque(void *a, void *b) -+{ -+ register struct quehead *element = (struct quehead *)a; -+ register struct quehead *head = (struct quehead *)b; -+ element->qh_link = head->qh_link; -+ head->qh_link = (struct quehead *)element; -+ element->qh_rlink = (struct quehead *)head; -+ ((struct quehead *)(element->qh_link))->qh_rlink = -+ (struct quehead *)element; -+} -+ -+inline void remque(void *a) -+{ -+ register struct quehead *element = (struct quehead *)a; -+ ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink; -+ ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link; -+ element->qh_rlink = NULL; -+} -+ -+/* TODO: IPv6 */ -+struct gfwd_list *add_guestfwd(struct gfwd_list **ex_ptr, SlirpWriteCb write_cb, -+ void *opaque, struct in_addr addr, int port) -+{ -+ struct gfwd_list *f = g_new0(struct gfwd_list, 1); -+ -+ f->write_cb = write_cb; -+ f->opaque = opaque; -+ f->ex_fport = port; -+ f->ex_addr = addr; -+ f->ex_next = *ex_ptr; -+ *ex_ptr = f; -+ -+ return f; -+} -+ -+struct gfwd_list *add_exec(struct gfwd_list **ex_ptr, const char *cmdline, -+ struct in_addr addr, int port) -+{ -+ struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port); -+ -+ f->ex_exec = g_strdup(cmdline); -+ -+ return f; -+} -+ -+struct gfwd_list *add_unix(struct gfwd_list **ex_ptr, const char *unixsock, -+ struct in_addr addr, int port) -+{ -+ struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port); -+ -+ f->ex_unix = g_strdup(unixsock); -+ -+ return f; -+} -+ -+int remove_guestfwd(struct gfwd_list **ex_ptr, struct in_addr addr, int port) -+{ -+ for (; *ex_ptr != NULL; ex_ptr = &((*ex_ptr)->ex_next)) { -+ struct gfwd_list *f = *ex_ptr; -+ if (f->ex_addr.s_addr == addr.s_addr && f->ex_fport == port) { -+ *ex_ptr = f->ex_next; -+ g_free(f->ex_exec); -+ g_free(f); -+ return 0; -+ } -+ } -+ return -1; -+} -+ -+static int slirp_socketpair_with_oob(int sv[2]) -+{ -+ struct sockaddr_in addr = { -+ .sin_family = AF_INET, -+ .sin_port = 0, -+ .sin_addr.s_addr = INADDR_ANY, -+ }; -+ socklen_t addrlen = sizeof(addr); -+ int ret, s; -+ -+ sv[1] = -1; -+ s = slirp_socket(AF_INET, SOCK_STREAM, 0); -+ if (s < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 || -+ listen(s, 1) < 0 || -+ getsockname(s, (struct sockaddr *)&addr, &addrlen) < 0) { -+ goto err; -+ } -+ -+ sv[1] = slirp_socket(AF_INET, SOCK_STREAM, 0); -+ if (sv[1] < 0) { -+ goto err; -+ } -+ /* -+ * This connect won't block because we've already listen()ed on -+ * the server end (even though we won't accept() the connection -+ * until later on). -+ */ -+ do { -+ ret = connect(sv[1], (struct sockaddr *)&addr, addrlen); -+ } while (ret < 0 && errno == EINTR); -+ if (ret < 0) { -+ goto err; -+ } -+ -+ do { -+ sv[0] = accept(s, (struct sockaddr *)&addr, &addrlen); -+ } while (sv[0] < 0 && errno == EINTR); -+ if (sv[0] < 0) { -+ goto err; -+ } -+ -+ closesocket(s); -+ return 0; -+ -+err: -+ g_critical("slirp_socketpair(): %s", strerror(errno)); -+ if (s >= 0) { -+ closesocket(s); -+ } -+ if (sv[1] >= 0) { -+ closesocket(sv[1]); -+ } -+ return -1; -+} -+ -+static void fork_exec_child_setup(gpointer data) -+{ -+#ifndef _WIN32 -+ setsid(); -+#endif -+} -+ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -+ -+#if !GLIB_CHECK_VERSION(2, 58, 0) -+typedef struct SlirpGSpawnFds { -+ GSpawnChildSetupFunc child_setup; -+ gpointer user_data; -+ gint stdin_fd; -+ gint stdout_fd; -+ gint stderr_fd; -+} SlirpGSpawnFds; -+ -+static inline void slirp_gspawn_fds_setup(gpointer user_data) -+{ -+ SlirpGSpawnFds *q = (SlirpGSpawnFds *)user_data; -+ -+ dup2(q->stdin_fd, 0); -+ dup2(q->stdout_fd, 1); -+ dup2(q->stderr_fd, 2); -+ q->child_setup(q->user_data); -+} -+#endif -+ -+static inline gboolean -+g_spawn_async_with_fds_slirp(const gchar *working_directory, gchar **argv, -+ gchar **envp, GSpawnFlags flags, -+ GSpawnChildSetupFunc child_setup, -+ gpointer user_data, GPid *child_pid, gint stdin_fd, -+ gint stdout_fd, gint stderr_fd, GError **error) -+{ -+#if GLIB_CHECK_VERSION(2, 58, 0) -+ return g_spawn_async_with_fds(working_directory, argv, envp, flags, -+ child_setup, user_data, child_pid, stdin_fd, -+ stdout_fd, stderr_fd, error); -+#else -+ SlirpGSpawnFds setup = { -+ .child_setup = child_setup, -+ .user_data = user_data, -+ .stdin_fd = stdin_fd, -+ .stdout_fd = stdout_fd, -+ .stderr_fd = stderr_fd, -+ }; -+ -+ return g_spawn_async(working_directory, argv, envp, flags, -+ slirp_gspawn_fds_setup, &setup, child_pid, error); -+#endif -+} -+ -+#define g_spawn_async_with_fds(wd, argv, env, f, c, d, p, ifd, ofd, efd, err) \ -+ g_spawn_async_with_fds_slirp(wd, argv, env, f, c, d, p, ifd, ofd, efd, err) -+ -+#pragma GCC diagnostic pop -+ -+int fork_exec(struct socket *so, const char *ex) -+{ -+ GError *err = NULL; -+ gint argc = 0; -+ gchar **argv = NULL; -+ int opt, sp[2]; -+ -+ DEBUG_CALL("fork_exec"); -+ DEBUG_ARG("so = %p", so); -+ DEBUG_ARG("ex = %p", ex); -+ -+ if (slirp_socketpair_with_oob(sp) < 0) { -+ return 0; -+ } -+ -+ if (!g_shell_parse_argv(ex, &argc, &argv, &err)) { -+ g_critical("fork_exec invalid command: %s\nerror: %s", ex, err->message); -+ g_error_free(err); -+ return 0; -+ } -+ -+ g_spawn_async_with_fds(NULL /* cwd */, argv, NULL /* env */, -+ G_SPAWN_SEARCH_PATH, fork_exec_child_setup, -+ NULL /* data */, NULL /* child_pid */, sp[1], sp[1], -+ sp[1], &err); -+ g_strfreev(argv); -+ -+ if (err) { -+ g_critical("fork_exec: %s", err->message); -+ g_error_free(err); -+ closesocket(sp[0]); -+ closesocket(sp[1]); -+ return 0; -+ } -+ -+ so->s = sp[0]; -+ closesocket(sp[1]); -+ slirp_socket_set_fast_reuse(so->s); -+ opt = 1; -+ setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); -+ slirp_set_nonblock(so->s); -+ so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque); -+ return 1; -+} -+ -+int open_unix(struct socket *so, const char *unixpath) -+{ -+#ifdef G_OS_UNIX -+ struct sockaddr_un sa; -+ int s; -+ -+ DEBUG_CALL("open_unix"); -+ DEBUG_ARG("so = %p", so); -+ DEBUG_ARG("unixpath = %s", unixpath); -+ -+ memset(&sa, 0, sizeof(sa)); -+ sa.sun_family = AF_UNIX; -+ if (g_strlcpy(sa.sun_path, unixpath, sizeof(sa.sun_path)) >= sizeof(sa.sun_path)) { -+ g_critical("Bad unix path: %s", unixpath); -+ return 0; -+ } -+ -+ s = slirp_socket(PF_UNIX, SOCK_STREAM, 0); -+ if (s < 0) { -+ g_critical("open_unix(): %s", strerror(errno)); -+ return 0; -+ } -+ -+ if (connect(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) { -+ g_critical("open_unix(): %s", strerror(errno)); -+ closesocket(s); -+ return 0; -+ } -+ -+ so->s = s; -+ slirp_set_nonblock(so->s); -+ so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque); -+ -+ return 1; -+#else -+ g_assert_not_reached(); -+#endif -+} -+ -+char *slirp_connection_info(Slirp *slirp) -+{ -+ GString *str = g_string_new(NULL); -+ const char *const tcpstates[] = { -+ [TCPS_CLOSED] = "CLOSED", [TCPS_LISTEN] = "LISTEN", -+ [TCPS_SYN_SENT] = "SYN_SENT", [TCPS_SYN_RECEIVED] = "SYN_RCVD", -+ [TCPS_ESTABLISHED] = "ESTABLISHED", [TCPS_CLOSE_WAIT] = "CLOSE_WAIT", -+ [TCPS_FIN_WAIT_1] = "FIN_WAIT_1", [TCPS_CLOSING] = "CLOSING", -+ [TCPS_LAST_ACK] = "LAST_ACK", [TCPS_FIN_WAIT_2] = "FIN_WAIT_2", -+ [TCPS_TIME_WAIT] = "TIME_WAIT", -+ }; -+ struct in_addr dst_addr; -+ struct sockaddr_in src; -+ socklen_t src_len; -+ uint16_t dst_port; -+ struct socket *so; -+ const char *state; -+ char buf[20]; -+ -+ g_string_append_printf(str, -+ " Protocol[State] FD Source Address Port " -+ "Dest. Address Port RecvQ SendQ\n"); -+ -+ /* TODO: IPv6 */ -+ -+ for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) { -+ if (so->so_state & SS_HOSTFWD) { -+ state = "HOST_FORWARD"; -+ } else if (so->so_tcpcb) { -+ state = tcpstates[so->so_tcpcb->t_state]; -+ } else { -+ state = "NONE"; -+ } -+ if (so->so_state & (SS_HOSTFWD | SS_INCOMING)) { -+ src_len = sizeof(src); -+ getsockname(so->s, (struct sockaddr *)&src, &src_len); -+ dst_addr = so->so_laddr; -+ dst_port = so->so_lport; -+ } else { -+ src.sin_addr = so->so_laddr; -+ src.sin_port = so->so_lport; -+ dst_addr = so->so_faddr; -+ dst_port = so->so_fport; -+ } -+ slirp_fmt0(buf, sizeof(buf), " TCP[%s]", state); -+ g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s, -+ src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : -+ "*", -+ ntohs(src.sin_port)); -+ g_string_append_printf(str, "%15s %5d %5d %5d\n", inet_ntoa(dst_addr), -+ ntohs(dst_port), so->so_rcv.sb_cc, -+ so->so_snd.sb_cc); -+ } -+ -+ for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) { -+ if (so->so_state & SS_HOSTFWD) { -+ slirp_fmt0(buf, sizeof(buf), " UDP[HOST_FORWARD]"); -+ src_len = sizeof(src); -+ getsockname(so->s, (struct sockaddr *)&src, &src_len); -+ dst_addr = so->so_laddr; -+ dst_port = so->so_lport; -+ } else { -+ slirp_fmt0(buf, sizeof(buf), " UDP[%d sec]", -+ (so->so_expire - curtime) / 1000); -+ src.sin_addr = so->so_laddr; -+ src.sin_port = so->so_lport; -+ dst_addr = so->so_faddr; -+ dst_port = so->so_fport; -+ } -+ g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s, -+ src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : -+ "*", -+ ntohs(src.sin_port)); -+ g_string_append_printf(str, "%15s %5d %5d %5d\n", inet_ntoa(dst_addr), -+ ntohs(dst_port), so->so_rcv.sb_cc, -+ so->so_snd.sb_cc); -+ } -+ -+ for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) { -+ slirp_fmt0(buf, sizeof(buf), " ICMP[%d sec]", -+ (so->so_expire - curtime) / 1000); -+ src.sin_addr = so->so_laddr; -+ dst_addr = so->so_faddr; -+ g_string_append_printf(str, "%-19s %3d %15s - ", buf, so->s, -+ src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : -+ "*"); -+ g_string_append_printf(str, "%15s - %5d %5d\n", inet_ntoa(dst_addr), -+ so->so_rcv.sb_cc, so->so_snd.sb_cc); -+ } -+ -+ return g_string_free(str, FALSE); -+} -+ -+int slirp_bind_outbound(struct socket *so, unsigned short af) -+{ -+ int ret = 0; -+ struct sockaddr *addr = NULL; -+ int addr_size = 0; -+ -+ if (af == AF_INET && so->slirp->outbound_addr != NULL) { -+ addr = (struct sockaddr *)so->slirp->outbound_addr; -+ addr_size = sizeof(struct sockaddr_in); -+ } else if (af == AF_INET6 && so->slirp->outbound_addr6 != NULL) { -+ addr = (struct sockaddr *)so->slirp->outbound_addr6; -+ addr_size = sizeof(struct sockaddr_in6); -+ } -+ -+ if (addr != NULL) { -+ ret = bind(so->s, addr, addr_size); -+ } -+ return ret; -+} -\ No newline at end of file -diff --git a/slirp/src/misc.h b/slirp/src/misc.h -new file mode 100644 -index 0000000000..81b370cfb1 ---- /dev/null -+++ b/slirp/src/misc.h -@@ -0,0 +1,72 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * Copyright (c) 1995 Danny Gasparovski. -+ */ -+ -+#ifndef MISC_H -+#define MISC_H -+ -+#include "libslirp.h" -+ -+struct gfwd_list { -+ SlirpWriteCb write_cb; -+ void *opaque; -+ struct in_addr ex_addr; /* Server address */ -+ int ex_fport; /* Port to telnet to */ -+ char *ex_exec; /* Command line of what to exec */ -+ char *ex_unix; /* unix socket */ -+ struct gfwd_list *ex_next; -+}; -+ -+#define EMU_NONE 0x0 -+ -+/* TCP emulations */ -+#define EMU_CTL 0x1 -+#define EMU_FTP 0x2 -+#define EMU_KSH 0x3 -+#define EMU_IRC 0x4 -+#define EMU_REALAUDIO 0x5 -+#define EMU_RLOGIN 0x6 -+#define EMU_IDENT 0x7 -+ -+#define EMU_NOCONNECT 0x10 /* Don't connect */ -+ -+struct tos_t { -+ uint16_t lport; -+ uint16_t fport; -+ uint8_t tos; -+ uint8_t emu; -+}; -+ -+struct emu_t { -+ uint16_t lport; -+ uint16_t fport; -+ uint8_t tos; -+ uint8_t emu; -+ struct emu_t *next; -+}; -+ -+struct slirp_quehead { -+ struct slirp_quehead *qh_link; -+ struct slirp_quehead *qh_rlink; -+}; -+ -+void slirp_insque(void *, void *); -+void slirp_remque(void *); -+int fork_exec(struct socket *so, const char *ex); -+int open_unix(struct socket *so, const char *unixsock); -+ -+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_unix(struct gfwd_list **ex_ptr, const char *unixsock, -+ struct in_addr addr, int port); -+ -+int remove_guestfwd(struct gfwd_list **ex_ptr, struct in_addr addr, int port); -+ -+int slirp_bind_outbound(struct socket *so, unsigned short af); -+ -+#endif -diff --git a/slirp/src/ncsi-pkt.h b/slirp/src/ncsi-pkt.h -new file mode 100644 -index 0000000000..7795ad83ee ---- /dev/null -+++ b/slirp/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/slirp/src/ncsi.c b/slirp/src/ncsi.c -new file mode 100644 -index 0000000000..75dcc08356 ---- /dev/null -+++ b/slirp/src/ncsi.c -@@ -0,0 +1,197 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * NC-SI (Network Controller Sideband Interface) "echo" model -+ * -+ * Copyright (C) 2016-2018 IBM Corp. -+ * -+ * 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. -+ */ -+#include "slirp.h" -+ -+#include "ncsi-pkt.h" -+ -+static uint32_t ncsi_calculate_checksum(uint16_t *data, int len) -+{ -+ uint32_t checksum = 0; -+ int i; -+ -+ /* -+ * 32-bit unsigned sum of the NC-SI packet header and NC-SI packet -+ * payload interpreted as a series of 16-bit unsigned integer values. -+ */ -+ for (i = 0; i < len / 2; i++) { -+ checksum += htons(data[i]); -+ } -+ -+ checksum = (~checksum + 1); -+ return checksum; -+} -+ -+/* Get Capabilities */ -+static int ncsi_rsp_handler_gc(struct ncsi_rsp_pkt_hdr *rnh) -+{ -+ struct ncsi_rsp_gc_pkt *rsp = (struct ncsi_rsp_gc_pkt *)rnh; -+ -+ rsp->cap = htonl(~0); -+ rsp->bc_cap = htonl(~0); -+ rsp->mc_cap = htonl(~0); -+ rsp->buf_cap = htonl(~0); -+ rsp->aen_cap = htonl(~0); -+ rsp->vlan_mode = 0xff; -+ rsp->uc_cnt = 2; -+ return 0; -+} -+ -+/* Get Link status */ -+static int ncsi_rsp_handler_gls(struct ncsi_rsp_pkt_hdr *rnh) -+{ -+ struct ncsi_rsp_gls_pkt *rsp = (struct ncsi_rsp_gls_pkt *)rnh; -+ -+ rsp->status = htonl(0x1); -+ return 0; -+} -+ -+/* Get Parameters */ -+static int ncsi_rsp_handler_gp(struct ncsi_rsp_pkt_hdr *rnh) -+{ -+ struct ncsi_rsp_gp_pkt *rsp = (struct ncsi_rsp_gp_pkt *)rnh; -+ -+ /* no MAC address filters or VLAN filters on the channel */ -+ rsp->mac_cnt = 0; -+ rsp->mac_enable = 0; -+ rsp->vlan_cnt = 0; -+ rsp->vlan_enable = 0; -+ -+ return 0; -+} -+ -+static const struct ncsi_rsp_handler { -+ unsigned char type; -+ int payload; -+ int (*handler)(struct ncsi_rsp_pkt_hdr *rnh); -+} ncsi_rsp_handlers[] = { { NCSI_PKT_RSP_CIS, 4, NULL }, -+ { NCSI_PKT_RSP_SP, 4, NULL }, -+ { NCSI_PKT_RSP_DP, 4, NULL }, -+ { NCSI_PKT_RSP_EC, 4, NULL }, -+ { NCSI_PKT_RSP_DC, 4, NULL }, -+ { NCSI_PKT_RSP_RC, 4, NULL }, -+ { NCSI_PKT_RSP_ECNT, 4, NULL }, -+ { NCSI_PKT_RSP_DCNT, 4, NULL }, -+ { NCSI_PKT_RSP_AE, 4, NULL }, -+ { NCSI_PKT_RSP_SL, 4, NULL }, -+ { NCSI_PKT_RSP_GLS, 16, ncsi_rsp_handler_gls }, -+ { NCSI_PKT_RSP_SVF, 4, NULL }, -+ { NCSI_PKT_RSP_EV, 4, NULL }, -+ { NCSI_PKT_RSP_DV, 4, NULL }, -+ { NCSI_PKT_RSP_SMA, 4, NULL }, -+ { NCSI_PKT_RSP_EBF, 4, NULL }, -+ { NCSI_PKT_RSP_DBF, 4, NULL }, -+ { NCSI_PKT_RSP_EGMF, 4, NULL }, -+ { NCSI_PKT_RSP_DGMF, 4, NULL }, -+ { NCSI_PKT_RSP_SNFC, 4, NULL }, -+ { NCSI_PKT_RSP_GVI, 40, NULL }, -+ { NCSI_PKT_RSP_GC, 32, ncsi_rsp_handler_gc }, -+ { NCSI_PKT_RSP_GP, 40, ncsi_rsp_handler_gp }, -+ { NCSI_PKT_RSP_GCPS, 172, NULL }, -+ { NCSI_PKT_RSP_GNS, 172, NULL }, -+ { NCSI_PKT_RSP_GNPTS, 172, NULL }, -+ { NCSI_PKT_RSP_GPS, 8, NULL }, -+ { NCSI_PKT_RSP_OEM, 0, NULL }, -+ { NCSI_PKT_RSP_PLDM, 0, NULL }, -+ { NCSI_PKT_RSP_GPUUID, 20, NULL } }; -+ -+/* -+ * packet format : ncsi header + payload + checksum -+ */ -+#define NCSI_MAX_PAYLOAD 172 -+#define NCSI_MAX_LEN (sizeof(struct ncsi_pkt_hdr) + NCSI_MAX_PAYLOAD + 4) -+ -+void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) -+{ -+ const struct ncsi_pkt_hdr *nh = -+ (const struct ncsi_pkt_hdr *)(pkt + ETH_HLEN); -+ uint8_t ncsi_reply[ETH_HLEN + NCSI_MAX_LEN]; -+ struct ethhdr *reh = (struct ethhdr *)ncsi_reply; -+ struct ncsi_rsp_pkt_hdr *rnh = -+ (struct ncsi_rsp_pkt_hdr *)(ncsi_reply + ETH_HLEN); -+ const struct ncsi_rsp_handler *handler = NULL; -+ int i; -+ int ncsi_rsp_len = sizeof(*nh); -+ uint32_t checksum; -+ uint32_t *pchecksum; -+ -+ if (pkt_len < ETH_HLEN + sizeof(struct ncsi_pkt_hdr)) { -+ return; /* packet too short */ -+ } -+ -+ memset(ncsi_reply, 0, sizeof(ncsi_reply)); -+ -+ memset(reh->h_dest, 0xff, ETH_ALEN); -+ memset(reh->h_source, 0xff, ETH_ALEN); -+ reh->h_proto = htons(ETH_P_NCSI); -+ -+ for (i = 0; i < G_N_ELEMENTS(ncsi_rsp_handlers); i++) { -+ if (ncsi_rsp_handlers[i].type == nh->type + 0x80) { -+ handler = &ncsi_rsp_handlers[i]; -+ break; -+ } -+ } -+ -+ rnh->common.mc_id = nh->mc_id; -+ rnh->common.revision = NCSI_PKT_REVISION; -+ rnh->common.id = nh->id; -+ rnh->common.type = nh->type + 0x80; -+ rnh->common.channel = nh->channel; -+ -+ if (handler) { -+ rnh->common.length = htons(handler->payload); -+ rnh->code = htons(NCSI_PKT_RSP_C_COMPLETED); -+ rnh->reason = htons(NCSI_PKT_RSP_R_NO_ERROR); -+ -+ if (handler->handler) { -+ /* TODO: handle errors */ -+ handler->handler(rnh); -+ } -+ ncsi_rsp_len += handler->payload; -+ } else { -+ rnh->common.length = 0; -+ rnh->code = htons(NCSI_PKT_RSP_C_UNAVAILABLE); -+ rnh->reason = htons(NCSI_PKT_RSP_R_UNKNOWN); -+ } -+ -+ /* Add the optional checksum at the end of the frame. */ -+ checksum = ncsi_calculate_checksum((uint16_t *)rnh, ncsi_rsp_len); -+ pchecksum = (uint32_t *)((void *)rnh + ncsi_rsp_len); -+ *pchecksum = htonl(checksum); -+ ncsi_rsp_len += 4; -+ -+ slirp_send_packet_all(slirp, ncsi_reply, ETH_HLEN + ncsi_rsp_len); -+} -diff --git a/slirp/src/ndp_table.c b/slirp/src/ndp_table.c -new file mode 100644 -index 0000000000..110d6ea0e4 ---- /dev/null -+++ b/slirp/src/ndp_table.c -@@ -0,0 +1,87 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * Copyright (c) 2013 -+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne. -+ */ -+ -+#include "slirp.h" -+ -+void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr, -+ uint8_t ethaddr[ETH_ALEN]) -+{ -+ char addrstr[INET6_ADDRSTRLEN]; -+ NdpTable *ndp_table = &slirp->ndp_table; -+ int i; -+ -+ inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN); -+ -+ DEBUG_CALL("ndp_table_add"); -+ DEBUG_ARG("ip = %s", addrstr); -+ DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x", ethaddr[0], ethaddr[1], -+ ethaddr[2], ethaddr[3], ethaddr[4], ethaddr[5]); -+ -+ if (IN6_IS_ADDR_MULTICAST(&ip_addr) || in6_zero(&ip_addr)) { -+ /* Do not register multicast or unspecified addresses */ -+ DEBUG_CALL(" abort: do not register multicast or unspecified address"); -+ return; -+ } -+ -+ /* Search for an entry */ -+ for (i = 0; i < NDP_TABLE_SIZE; i++) { -+ if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) { -+ DEBUG_CALL(" already in table: update the entry"); -+ /* Update the entry */ -+ memcpy(ndp_table->table[i].eth_addr, ethaddr, ETH_ALEN); -+ return; -+ } -+ } -+ -+ /* No entry found, create a new one */ -+ DEBUG_CALL(" create new entry"); -+ ndp_table->table[ndp_table->next_victim].ip_addr = ip_addr; -+ memcpy(ndp_table->table[ndp_table->next_victim].eth_addr, ethaddr, -+ ETH_ALEN); -+ ndp_table->next_victim = (ndp_table->next_victim + 1) % NDP_TABLE_SIZE; -+} -+ -+bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr, -+ uint8_t out_ethaddr[ETH_ALEN]) -+{ -+ char addrstr[INET6_ADDRSTRLEN]; -+ NdpTable *ndp_table = &slirp->ndp_table; -+ int i; -+ -+ inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN); -+ -+ DEBUG_CALL("ndp_table_search"); -+ DEBUG_ARG("ip = %s", addrstr); -+ -+ assert(!in6_zero(&ip_addr)); -+ -+ /* Multicast address: fec0::abcd:efgh/8 -> 33:33:ab:cd:ef:gh */ -+ if (IN6_IS_ADDR_MULTICAST(&ip_addr)) { -+ out_ethaddr[0] = 0x33; -+ out_ethaddr[1] = 0x33; -+ out_ethaddr[2] = ip_addr.s6_addr[12]; -+ out_ethaddr[3] = ip_addr.s6_addr[13]; -+ out_ethaddr[4] = ip_addr.s6_addr[14]; -+ out_ethaddr[5] = ip_addr.s6_addr[15]; -+ DEBUG_ARG("multicast addr = %02x:%02x:%02x:%02x:%02x:%02x", -+ out_ethaddr[0], out_ethaddr[1], out_ethaddr[2], -+ out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]); -+ return 1; -+ } -+ -+ for (i = 0; i < NDP_TABLE_SIZE; i++) { -+ if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) { -+ memcpy(out_ethaddr, ndp_table->table[i].eth_addr, ETH_ALEN); -+ DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x", -+ out_ethaddr[0], out_ethaddr[1], out_ethaddr[2], -+ out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]); -+ return 1; -+ } -+ } -+ -+ DEBUG_CALL(" ip not found in table"); -+ return 0; -+} -diff --git a/slirp/src/sbuf.c b/slirp/src/sbuf.c -new file mode 100644 -index 0000000000..2fb9176144 ---- /dev/null -+++ b/slirp/src/sbuf.c -@@ -0,0 +1,168 @@ -+/* 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) -+{ -+ g_free(sb->sb_data); -+} -+ -+bool sbdrop(struct sbuf *sb, size_t num) -+{ -+ int limit = sb->sb_datalen / 2; -+ -+ g_warn_if_fail(num <= sb->sb_cc); -+ 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, size_t size) -+{ -+ sb->sb_wptr = sb->sb_rptr = sb->sb_data = g_realloc(sb->sb_data, size); -+ sb->sb_cc = 0; -+ sb->sb_datalen = size; -+} -+ -+/* -+ * 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, size_t off, size_t len, char *to) -+{ -+ char *from; -+ -+ g_assert(len + off <= sb->sb_cc); -+ -+ from = sb->sb_rptr + off; -+ if (from >= sb->sb_data + sb->sb_datalen) -+ from -= sb->sb_datalen; -+ -+ if (from < sb->sb_wptr) { -+ memcpy(to, from, len); -+ } else { -+ /* re-use off */ -+ off = (sb->sb_data + sb->sb_datalen) - from; -+ if (off > len) -+ off = len; -+ memcpy(to, from, off); -+ len -= off; -+ if (len) -+ memcpy(to + off, sb->sb_data, len); -+ } -+} -diff --git a/slirp/src/sbuf.h b/slirp/src/sbuf.h -new file mode 100644 -index 0000000000..01886fbd01 ---- /dev/null -+++ b/slirp/src/sbuf.h -@@ -0,0 +1,27 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * Copyright (c) 1995 Danny Gasparovski. -+ */ -+ -+#ifndef SBUF_H -+#define SBUF_H -+ -+#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc) -+ -+struct sbuf { -+ uint32_t sb_cc; /* actual chars in buffer */ -+ uint32_t sb_datalen; /* Length of data */ -+ char *sb_wptr; /* write pointer. points to where the next -+ * bytes should be written in the sbuf */ -+ char *sb_rptr; /* read pointer. points to where the next -+ * byte should be read from the sbuf */ -+ char *sb_data; /* Actual data */ -+}; -+ -+void sbfree(struct sbuf *sb); -+bool sbdrop(struct sbuf *sb, size_t len); -+void sbreserve(struct sbuf *sb, size_t size); -+void sbappend(struct socket *sb, struct mbuf *mb); -+void sbcopy(struct sbuf *sb, size_t off, size_t len, char *p); -+ -+#endif -diff --git a/slirp/src/slirp.c b/slirp/src/slirp.c -new file mode 100644 -index 0000000000..9be58e2add ---- /dev/null -+++ b/slirp/src/slirp.c -@@ -0,0 +1,1189 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * libslirp glue -+ * -+ * Copyright (c) 2004-2008 Fabrice Bellard -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+#include "slirp.h" -+ -+ -+#ifndef _WIN32 -+#include -+#endif -+ -+/* https://gitlab.freedesktop.org/slirp/libslirp/issues/18 */ -+#if defined(__NetBSD__) && defined(if_mtu) -+#undef if_mtu -+#endif -+ -+int slirp_debug; -+ -+/* Define to 1 if you want KEEPALIVE timers */ -+bool slirp_do_keepalive; -+ -+/* host loopback address */ -+struct in_addr loopback_addr; -+/* host loopback network mask */ -+unsigned long loopback_mask; -+ -+/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */ -+static const uint8_t special_ethaddr[ETH_ALEN] = { 0x52, 0x55, 0x00, -+ 0x00, 0x00, 0x00 }; -+ -+unsigned curtime; -+ -+static struct in_addr dns_addr; -+#ifndef _WIN32 -+static struct in6_addr dns6_addr; -+#endif -+static unsigned dns_addr_time; -+#ifndef _WIN32 -+static unsigned dns6_addr_time; -+#endif -+ -+#define TIMEOUT_FAST 2 /* milliseconds */ -+#define TIMEOUT_SLOW 499 /* milliseconds */ -+/* for the aging of certain requests like DNS */ -+#define TIMEOUT_DEFAULT 1000 /* milliseconds */ -+ -+#ifdef _WIN32 -+ -+int get_dns_addr(struct in_addr *pdns_addr) -+{ -+ FIXED_INFO *FixedInfo = NULL; -+ ULONG BufLen; -+ DWORD ret; -+ IP_ADDR_STRING *pIPAddr; -+ struct in_addr tmp_addr; -+ -+ if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < TIMEOUT_DEFAULT) { -+ *pdns_addr = dns_addr; -+ return 0; -+ } -+ -+ FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO)); -+ BufLen = sizeof(FIXED_INFO); -+ -+ if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) { -+ if (FixedInfo) { -+ GlobalFree(FixedInfo); -+ FixedInfo = NULL; -+ } -+ FixedInfo = GlobalAlloc(GPTR, BufLen); -+ } -+ -+ if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) { -+ printf("GetNetworkParams failed. ret = %08x\n", (unsigned)ret); -+ if (FixedInfo) { -+ GlobalFree(FixedInfo); -+ FixedInfo = NULL; -+ } -+ return -1; -+ } -+ -+ pIPAddr = &(FixedInfo->DnsServerList); -+ inet_aton(pIPAddr->IpAddress.String, &tmp_addr); -+ *pdns_addr = tmp_addr; -+ dns_addr = tmp_addr; -+ dns_addr_time = curtime; -+ if (FixedInfo) { -+ GlobalFree(FixedInfo); -+ FixedInfo = NULL; -+ } -+ return 0; -+} -+ -+int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id) -+{ -+ return -1; -+} -+ -+static void winsock_cleanup(void) -+{ -+ WSACleanup(); -+} -+ -+#else -+ -+static int get_dns_addr_cached(void *pdns_addr, void *cached_addr, -+ socklen_t addrlen, struct stat *cached_stat, -+ unsigned *cached_time) -+{ -+ struct stat old_stat; -+ if (curtime - *cached_time < TIMEOUT_DEFAULT) { -+ memcpy(pdns_addr, cached_addr, addrlen); -+ return 0; -+ } -+ old_stat = *cached_stat; -+ if (stat("/etc/resolv.conf", cached_stat) != 0) { -+ return -1; -+ } -+ if (cached_stat->st_dev == old_stat.st_dev && -+ cached_stat->st_ino == old_stat.st_ino && -+ cached_stat->st_size == old_stat.st_size && -+ cached_stat->st_mtime == old_stat.st_mtime) { -+ memcpy(pdns_addr, cached_addr, addrlen); -+ return 0; -+ } -+ return 1; -+} -+ -+static int get_dns_addr_resolv_conf(int af, void *pdns_addr, void *cached_addr, -+ socklen_t addrlen, uint32_t *scope_id, -+ unsigned *cached_time) -+{ -+ char buff[512]; -+ char buff2[257]; -+ FILE *f; -+ int found = 0; -+ void *tmp_addr = alloca(addrlen); -+ unsigned if_index; -+ -+ f = fopen("/etc/resolv.conf", "r"); -+ if (!f) -+ return -1; -+ -+ DEBUG_MISC("IP address of your DNS(s):"); -+ while (fgets(buff, 512, f) != NULL) { -+ if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) { -+ char *c = strchr(buff2, '%'); -+ if (c) { -+ if_index = if_nametoindex(c + 1); -+ *c = '\0'; -+ } else { -+ if_index = 0; -+ } -+ -+ if (!inet_pton(af, buff2, tmp_addr)) { -+ continue; -+ } -+ /* If it's the first one, set it to dns_addr */ -+ if (!found) { -+ memcpy(pdns_addr, tmp_addr, addrlen); -+ memcpy(cached_addr, tmp_addr, addrlen); -+ if (scope_id) { -+ *scope_id = if_index; -+ } -+ *cached_time = curtime; -+ } -+ -+ if (++found > 3) { -+ DEBUG_MISC(" (more)"); -+ break; -+ } else if (slirp_debug & DBG_MISC) { -+ char s[INET6_ADDRSTRLEN]; -+ const char *res = inet_ntop(af, tmp_addr, s, sizeof(s)); -+ if (!res) { -+ res = " (string conversion error)"; -+ } -+ DEBUG_MISC(" %s", res); -+ } -+ } -+ } -+ fclose(f); -+ if (!found) -+ return -1; -+ return 0; -+} -+ -+int get_dns_addr(struct in_addr *pdns_addr) -+{ -+ static struct stat dns_addr_stat; -+ -+ if (dns_addr.s_addr != 0) { -+ int ret; -+ ret = get_dns_addr_cached(pdns_addr, &dns_addr, sizeof(dns_addr), -+ &dns_addr_stat, &dns_addr_time); -+ if (ret <= 0) { -+ return ret; -+ } -+ } -+ return get_dns_addr_resolv_conf(AF_INET, pdns_addr, &dns_addr, -+ sizeof(dns_addr), NULL, &dns_addr_time); -+} -+ -+int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id) -+{ -+ static struct stat dns6_addr_stat; -+ -+ if (!in6_zero(&dns6_addr)) { -+ int ret; -+ ret = get_dns_addr_cached(pdns6_addr, &dns6_addr, sizeof(dns6_addr), -+ &dns6_addr_stat, &dns6_addr_time); -+ if (ret <= 0) { -+ return ret; -+ } -+ } -+ return get_dns_addr_resolv_conf(AF_INET6, pdns6_addr, &dns6_addr, -+ sizeof(dns6_addr), scope_id, -+ &dns6_addr_time); -+} -+ -+#endif -+ -+static void slirp_init_once(void) -+{ -+ static int initialized; -+ const char *debug; -+#ifdef _WIN32 -+ WSADATA Data; -+#endif -+ -+ if (initialized) { -+ return; -+ } -+ initialized = 1; -+ -+#ifdef _WIN32 -+ WSAStartup(MAKEWORD(2, 0), &Data); -+ atexit(winsock_cleanup); -+#endif -+ -+ loopback_addr.s_addr = htonl(INADDR_LOOPBACK); -+ loopback_mask = htonl(IN_CLASSA_NET); -+ -+ debug = g_getenv("SLIRP_DEBUG"); -+ if (debug) { -+ const GDebugKey keys[] = { -+ { "call", DBG_CALL }, -+ { "misc", DBG_MISC }, -+ { "error", DBG_ERROR }, -+ { "tftp", DBG_TFTP }, -+ }; -+ slirp_debug = g_parse_debug_string(debug, keys, G_N_ELEMENTS(keys)); -+ } -+} -+ -+Slirp *slirp_new(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaque) -+{ -+ Slirp *slirp; -+ -+ 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); -+ g_return_val_if_fail(!cfg->bootfile || -+ (strlen(cfg->bootfile) < -+ G_SIZEOF_MEMBER(struct bootp_t, bp_file)), NULL); -+ -+ slirp = g_malloc0(sizeof(Slirp)); -+ -+ slirp_init_once(); -+ -+ slirp->opaque = opaque; -+ slirp->cb = callbacks; -+ slirp->grand = g_rand_new(); -+ slirp->restricted = cfg->restricted; -+ -+ slirp->in_enabled = cfg->in_enabled; -+ slirp->in6_enabled = cfg->in6_enabled; -+ -+ if_init(slirp); -+ ip_init(slirp); -+ ip6_init(slirp); -+ -+ m_init(slirp); -+ -+ 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), -+ cfg->vhostname); -+ } -+ 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); -+ } -+ 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; -+ -+ if (cfg->version >= 2) { -+ slirp->outbound_addr = cfg->outbound_addr; -+ slirp->outbound_addr6 = cfg->outbound_addr6; -+ } else { -+ slirp->outbound_addr = NULL; -+ slirp->outbound_addr6 = NULL; -+ } -+ 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.version = 1; -+ 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_new(&cfg, callbacks, opaque); -+} -+ -+void slirp_cleanup(Slirp *slirp) -+{ -+ struct gfwd_list *e, *next; -+ -+ for (e = slirp->guestfwd_list; e; e = next) { -+ next = e->ex_next; -+ g_free(e->ex_exec); -+ g_free(e->ex_unix); -+ g_free(e); -+ } -+ -+ ip_cleanup(slirp); -+ ip6_cleanup(slirp); -+ m_cleanup(slirp); -+ -+ g_rand_free(slirp->grand); -+ -+ g_free(slirp->vdnssearch); -+ g_free(slirp->tftp_prefix); -+ g_free(slirp->bootp_filename); -+ g_free(slirp->vdomainname); -+ g_free(slirp); -+} -+ -+#define CONN_CANFSEND(so) \ -+ (((so)->so_state & (SS_FCANTSENDMORE | SS_ISFCONNECTED)) == SS_ISFCONNECTED) -+#define CONN_CANFRCV(so) \ -+ (((so)->so_state & (SS_FCANTRCVMORE | SS_ISFCONNECTED)) == SS_ISFCONNECTED) -+ -+static void slirp_update_timeout(Slirp *slirp, uint32_t *timeout) -+{ -+ uint32_t t; -+ -+ if (*timeout <= TIMEOUT_FAST) { -+ return; -+ } -+ -+ t = MIN(1000, *timeout); -+ -+ /* If we have tcp timeout with slirp, then we will fill @timeout with -+ * more precise value. -+ */ -+ if (slirp->time_fasttimo) { -+ *timeout = TIMEOUT_FAST; -+ return; -+ } -+ if (slirp->do_slowtimo) { -+ t = MIN(TIMEOUT_SLOW, t); -+ } -+ *timeout = t; -+} -+ -+void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout, -+ SlirpAddPollCb add_poll, void *opaque) -+{ -+ struct socket *so, *so_next; -+ -+ /* -+ * First, TCP sockets -+ */ -+ -+ /* -+ * *_slowtimo needs calling if there are IP fragments -+ * in the fragment queue, or there are TCP connections active -+ */ -+ slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) || -+ (&slirp->ipq.ip_link != slirp->ipq.ip_link.next)); -+ -+ for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) { -+ int events = 0; -+ -+ so_next = so->so_next; -+ -+ so->pollfds_idx = -1; -+ -+ /* -+ * See if we need a tcp_fasttimo -+ */ -+ if (slirp->time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) { -+ slirp->time_fasttimo = curtime; /* Flag when want a fasttimo */ -+ } -+ -+ /* -+ * NOFDREF can include still connecting to local-host, -+ * newly socreated() sockets etc. Don't want to select these. -+ */ -+ if (so->so_state & SS_NOFDREF || so->s == -1) { -+ continue; -+ } -+ -+ /* -+ * Set for reading sockets which are accepting -+ */ -+ if (so->so_state & SS_FACCEPTCONN) { -+ so->pollfds_idx = add_poll( -+ so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque); -+ continue; -+ } -+ -+ /* -+ * Set for writing sockets which are connecting -+ */ -+ if (so->so_state & SS_ISFCONNECTING) { -+ so->pollfds_idx = -+ add_poll(so->s, SLIRP_POLL_OUT | SLIRP_POLL_ERR, opaque); -+ continue; -+ } -+ -+ /* -+ * Set for writing if we are connected, can send more, and -+ * we have something to send -+ */ -+ if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { -+ events |= SLIRP_POLL_OUT | SLIRP_POLL_ERR; -+ } -+ -+ /* -+ * Set for reading (and urgent data) if we are connected, can -+ * receive more, and we have room for it XXX /2 ? -+ */ -+ if (CONN_CANFRCV(so) && -+ (so->so_snd.sb_cc < (so->so_snd.sb_datalen / 2))) { -+ events |= SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR | -+ SLIRP_POLL_PRI; -+ } -+ -+ if (events) { -+ so->pollfds_idx = add_poll(so->s, events, opaque); -+ } -+ } -+ -+ /* -+ * UDP sockets -+ */ -+ for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) { -+ so_next = so->so_next; -+ -+ so->pollfds_idx = -1; -+ -+ /* -+ * See if it's timed out -+ */ -+ if (so->so_expire) { -+ if (so->so_expire <= curtime) { -+ udp_detach(so); -+ continue; -+ } else { -+ slirp->do_slowtimo = true; /* Let socket expire */ -+ } -+ } -+ -+ /* -+ * When UDP packets are received from over the -+ * link, they're sendto()'d straight away, so -+ * no need for setting for writing -+ * Limit the number of packets queued by this session -+ * to 4. Note that even though we try and limit this -+ * to 4 packets, the session could have more queued -+ * if the packets needed to be fragmented -+ * (XXX <= 4 ?) -+ */ -+ if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { -+ so->pollfds_idx = add_poll( -+ so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque); -+ } -+ } -+ -+ /* -+ * ICMP sockets -+ */ -+ for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) { -+ so_next = so->so_next; -+ -+ so->pollfds_idx = -1; -+ -+ /* -+ * See if it's timed out -+ */ -+ if (so->so_expire) { -+ if (so->so_expire <= curtime) { -+ icmp_detach(so); -+ continue; -+ } else { -+ slirp->do_slowtimo = true; /* Let socket expire */ -+ } -+ } -+ -+ if (so->so_state & SS_ISFCONNECTED) { -+ so->pollfds_idx = add_poll( -+ so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque); -+ } -+ } -+ -+ slirp_update_timeout(slirp, timeout); -+} -+ -+void slirp_pollfds_poll(Slirp *slirp, int select_error, -+ SlirpGetREventsCb get_revents, void *opaque) -+{ -+ struct socket *so, *so_next; -+ int ret; -+ -+ curtime = slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS; -+ -+ /* -+ * See if anything has timed out -+ */ -+ if (slirp->time_fasttimo && -+ ((curtime - slirp->time_fasttimo) >= TIMEOUT_FAST)) { -+ tcp_fasttimo(slirp); -+ slirp->time_fasttimo = 0; -+ } -+ if (slirp->do_slowtimo && -+ ((curtime - slirp->last_slowtimo) >= TIMEOUT_SLOW)) { -+ ip_slowtimo(slirp); -+ tcp_slowtimo(slirp); -+ slirp->last_slowtimo = curtime; -+ } -+ -+ /* -+ * Check sockets -+ */ -+ if (!select_error) { -+ /* -+ * Check TCP sockets -+ */ -+ for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) { -+ int revents; -+ -+ so_next = so->so_next; -+ -+ revents = 0; -+ if (so->pollfds_idx != -1) { -+ revents = get_revents(so->pollfds_idx, opaque); -+ } -+ -+ if (so->so_state & SS_NOFDREF || so->s == -1) { -+ continue; -+ } -+ -+ /* -+ * Check for URG data -+ * This will soread as well, so no need to -+ * test for SLIRP_POLL_IN below if this succeeds -+ */ -+ if (revents & SLIRP_POLL_PRI) { -+ ret = sorecvoob(so); -+ if (ret < 0) { -+ /* Socket error might have resulted in the socket being -+ * removed, do not try to do anything more with it. */ -+ continue; -+ } -+ } -+ /* -+ * Check sockets for reading -+ */ -+ else if (revents & -+ (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR)) { -+ /* -+ * Check for incoming connections -+ */ -+ if (so->so_state & SS_FACCEPTCONN) { -+ tcp_connect(so); -+ continue; -+ } /* else */ -+ ret = soread(so); -+ -+ /* Output it if we read something */ -+ if (ret > 0) { -+ tcp_output(sototcpcb(so)); -+ } -+ if (ret < 0) { -+ /* Socket error might have resulted in the socket being -+ * removed, do not try to do anything more with it. */ -+ continue; -+ } -+ } -+ -+ /* -+ * Check sockets for writing -+ */ -+ if (!(so->so_state & SS_NOFDREF) && -+ (revents & (SLIRP_POLL_OUT | SLIRP_POLL_ERR))) { -+ /* -+ * Check for non-blocking, still-connecting sockets -+ */ -+ if (so->so_state & SS_ISFCONNECTING) { -+ /* Connected */ -+ so->so_state &= ~SS_ISFCONNECTING; -+ -+ ret = send(so->s, (const void *)&ret, 0, 0); -+ if (ret < 0) { -+ /* XXXXX Must fix, zero bytes is a NOP */ -+ if (errno == EAGAIN || errno == EWOULDBLOCK || -+ errno == EINPROGRESS || errno == ENOTCONN) { -+ continue; -+ } -+ -+ /* else failed */ -+ so->so_state &= SS_PERSISTENT_MASK; -+ so->so_state |= SS_NOFDREF; -+ } -+ /* else so->so_state &= ~SS_ISFCONNECTING; */ -+ -+ /* -+ * Continue tcp_input -+ */ -+ tcp_input((struct mbuf *)NULL, sizeof(struct ip), so, -+ so->so_ffamily); -+ /* continue; */ -+ } else { -+ ret = sowrite(so); -+ if (ret > 0) { -+ /* Call tcp_output in case we need to send a window -+ * update to the guest, otherwise it will be stuck -+ * until it sends a window probe. */ -+ tcp_output(sototcpcb(so)); -+ } -+ } -+ } -+ } -+ -+ /* -+ * Now UDP sockets. -+ * Incoming packets are sent straight away, they're not buffered. -+ * Incoming UDP data isn't buffered either. -+ */ -+ for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) { -+ int revents; -+ -+ so_next = so->so_next; -+ -+ revents = 0; -+ if (so->pollfds_idx != -1) { -+ revents = get_revents(so->pollfds_idx, opaque); -+ } -+ -+ if (so->s != -1 && -+ (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) { -+ sorecvfrom(so); -+ } -+ } -+ -+ /* -+ * Check incoming ICMP relies. -+ */ -+ for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) { -+ int revents; -+ -+ so_next = so->so_next; -+ -+ revents = 0; -+ if (so->pollfds_idx != -1) { -+ revents = get_revents(so->pollfds_idx, opaque); -+ } -+ -+ if (so->s != -1 && -+ (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) { -+ icmp_receive(so); -+ } -+ } -+ } -+ -+ if_start(slirp); -+} -+ -+static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) -+{ -+ const struct slirp_arphdr *ah = -+ (const struct slirp_arphdr *)(pkt + ETH_HLEN); -+ uint8_t arp_reply[MAX(ETH_HLEN + sizeof(struct slirp_arphdr), 64)]; -+ struct ethhdr *reh = (struct ethhdr *)arp_reply; -+ struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_reply + ETH_HLEN); -+ int ar_op; -+ struct gfwd_list *ex_ptr; -+ -+ if (!slirp->in_enabled) { -+ return; -+ } -+ -+ if (pkt_len < ETH_HLEN + sizeof(struct slirp_arphdr)) { -+ return; /* packet too short */ -+ } -+ -+ ar_op = ntohs(ah->ar_op); -+ switch (ar_op) { -+ case ARPOP_REQUEST: -+ if (ah->ar_tip == ah->ar_sip) { -+ /* Gratuitous ARP */ -+ arp_table_add(slirp, ah->ar_sip, ah->ar_sha); -+ return; -+ } -+ -+ if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) == -+ slirp->vnetwork_addr.s_addr) { -+ if (ah->ar_tip == slirp->vnameserver_addr.s_addr || -+ ah->ar_tip == slirp->vhost_addr.s_addr) -+ goto arp_ok; -+ /* TODO: IPv6 */ -+ for (ex_ptr = slirp->guestfwd_list; ex_ptr; -+ ex_ptr = ex_ptr->ex_next) { -+ if (ex_ptr->ex_addr.s_addr == ah->ar_tip) -+ goto arp_ok; -+ } -+ return; -+ arp_ok: -+ memset(arp_reply, 0, sizeof(arp_reply)); -+ -+ arp_table_add(slirp, ah->ar_sip, ah->ar_sha); -+ -+ /* ARP request for alias/dns mac address */ -+ memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN); -+ memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4); -+ memcpy(&reh->h_source[2], &ah->ar_tip, 4); -+ reh->h_proto = htons(ETH_P_ARP); -+ -+ rah->ar_hrd = htons(1); -+ rah->ar_pro = htons(ETH_P_IP); -+ rah->ar_hln = ETH_ALEN; -+ rah->ar_pln = 4; -+ rah->ar_op = htons(ARPOP_REPLY); -+ memcpy(rah->ar_sha, reh->h_source, ETH_ALEN); -+ rah->ar_sip = ah->ar_tip; -+ memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN); -+ rah->ar_tip = ah->ar_sip; -+ slirp_send_packet_all(slirp, arp_reply, sizeof(arp_reply)); -+ } -+ break; -+ case ARPOP_REPLY: -+ arp_table_add(slirp, ah->ar_sip, ah->ar_sha); -+ break; -+ default: -+ break; -+ } -+} -+ -+void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) -+{ -+ struct mbuf *m; -+ int proto; -+ -+ if (pkt_len < ETH_HLEN) -+ return; -+ -+ proto = (((uint16_t)pkt[12]) << 8) + pkt[13]; -+ switch (proto) { -+ case ETH_P_ARP: -+ arp_input(slirp, pkt, pkt_len); -+ break; -+ case ETH_P_IP: -+ case ETH_P_IPV6: -+ m = m_get(slirp); -+ if (!m) -+ return; -+ /* Note: we add 2 to align the IP header on 4 bytes, -+ * and add the margin for the tcpiphdr overhead */ -+ if (M_FREEROOM(m) < pkt_len + TCPIPHDR_DELTA + 2) { -+ m_inc(m, pkt_len + TCPIPHDR_DELTA + 2); -+ } -+ m->m_len = pkt_len + TCPIPHDR_DELTA + 2; -+ memcpy(m->m_data + TCPIPHDR_DELTA + 2, pkt, pkt_len); -+ -+ m->m_data += TCPIPHDR_DELTA + 2 + ETH_HLEN; -+ m->m_len -= TCPIPHDR_DELTA + 2 + ETH_HLEN; -+ -+ if (proto == ETH_P_IP) { -+ ip_input(m); -+ } else if (proto == ETH_P_IPV6) { -+ ip6_input(m); -+ } -+ break; -+ -+ case ETH_P_NCSI: -+ ncsi_input(slirp, pkt, pkt_len); -+ break; -+ -+ default: -+ break; -+ } -+} -+ -+/* Prepare the IPv4 packet to be sent to the ethernet device. Returns 1 if no -+ * packet should be sent, 0 if the packet must be re-queued, 2 if the packet -+ * is ready to go. -+ */ -+static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh, -+ uint8_t ethaddr[ETH_ALEN]) -+{ -+ const struct ip *iph = (const struct ip *)ifm->m_data; -+ -+ if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) { -+ uint8_t arp_req[ETH_HLEN + sizeof(struct slirp_arphdr)]; -+ struct ethhdr *reh = (struct ethhdr *)arp_req; -+ struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_req + ETH_HLEN); -+ -+ if (!ifm->resolution_requested) { -+ /* If the client addr is not known, send an ARP request */ -+ memset(reh->h_dest, 0xff, ETH_ALEN); -+ memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4); -+ memcpy(&reh->h_source[2], &slirp->vhost_addr, 4); -+ reh->h_proto = htons(ETH_P_ARP); -+ rah->ar_hrd = htons(1); -+ rah->ar_pro = htons(ETH_P_IP); -+ rah->ar_hln = ETH_ALEN; -+ rah->ar_pln = 4; -+ rah->ar_op = htons(ARPOP_REQUEST); -+ -+ /* source hw addr */ -+ memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4); -+ memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4); -+ -+ /* source IP */ -+ rah->ar_sip = slirp->vhost_addr.s_addr; -+ -+ /* target hw addr (none) */ -+ memset(rah->ar_tha, 0, ETH_ALEN); -+ -+ /* target IP */ -+ rah->ar_tip = iph->ip_dst.s_addr; -+ slirp->client_ipaddr = iph->ip_dst; -+ slirp_send_packet_all(slirp, arp_req, sizeof(arp_req)); -+ ifm->resolution_requested = true; -+ -+ /* Expire request and drop outgoing packet after 1 second */ -+ ifm->expiration_date = -+ slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL; -+ } -+ return 0; -+ } else { -+ memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4); -+ /* XXX: not correct */ -+ memcpy(&eh->h_source[2], &slirp->vhost_addr, 4); -+ eh->h_proto = htons(ETH_P_IP); -+ -+ /* Send this */ -+ return 2; -+ } -+} -+ -+/* Prepare the IPv6 packet to be sent to the ethernet device. Returns 1 if no -+ * packet should be sent, 0 if the packet must be re-queued, 2 if the packet -+ * is ready to go. -+ */ -+static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh, -+ uint8_t ethaddr[ETH_ALEN]) -+{ -+ const struct ip6 *ip6h = mtod(ifm, const struct ip6 *); -+ if (!ndp_table_search(slirp, ip6h->ip_dst, ethaddr)) { -+ if (!ifm->resolution_requested) { -+ ndp_send_ns(slirp, ip6h->ip_dst); -+ ifm->resolution_requested = true; -+ ifm->expiration_date = -+ slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL; -+ } -+ return 0; -+ } else { -+ eh->h_proto = htons(ETH_P_IPV6); -+ in6_compute_ethaddr(ip6h->ip_src, eh->h_source); -+ -+ /* Send this */ -+ return 2; -+ } -+} -+ -+/* Output the IP packet to the ethernet device. Returns 0 if the packet must be -+ * re-queued. -+ */ -+int if_encap(Slirp *slirp, struct mbuf *ifm) -+{ -+ uint8_t buf[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; -+ int ret; -+ -+ if (ifm->m_len + ETH_HLEN > sizeof(buf)) { -+ return 1; -+ } -+ -+ switch (iph->ip_v) { -+ case IPVERSION: -+ ret = if_encap4(slirp, ifm, eh, ethaddr); -+ if (ret < 2) { -+ return ret; -+ } -+ break; -+ -+ case IP6VERSION: -+ ret = if_encap6(slirp, ifm, eh, ethaddr); -+ if (ret < 2) { -+ return ret; -+ } -+ break; -+ -+ default: -+ g_assert_not_reached(); -+ } -+ -+ memcpy(eh->h_dest, ethaddr, ETH_ALEN); -+ DEBUG_ARG("src = %02x:%02x:%02x:%02x:%02x:%02x", eh->h_source[0], -+ eh->h_source[1], eh->h_source[2], eh->h_source[3], -+ eh->h_source[4], eh->h_source[5]); -+ DEBUG_ARG("dst = %02x:%02x:%02x:%02x:%02x:%02x", eh->h_dest[0], -+ eh->h_dest[1], eh->h_dest[2], eh->h_dest[3], eh->h_dest[4], -+ eh->h_dest[5]); -+ memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len); -+ slirp_send_packet_all(slirp, buf, ifm->m_len + ETH_HLEN); -+ return 1; -+} -+ -+/* Drop host forwarding rule, return 0 if found. */ -+/* TODO: IPv6 */ -+int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, -+ int host_port) -+{ -+ struct socket *so; -+ struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb); -+ struct sockaddr_in addr; -+ int port = htons(host_port); -+ socklen_t addr_len; -+ -+ for (so = head->so_next; so != head; so = so->so_next) { -+ addr_len = sizeof(addr); -+ if ((so->so_state & SS_HOSTFWD) && -+ getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 && -+ addr.sin_addr.s_addr == host_addr.s_addr && addr.sin_port == port) { -+ so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque); -+ closesocket(so->s); -+ sofree(so); -+ return 0; -+ } -+ } -+ -+ return -1; -+} -+ -+/* TODO: IPv6 */ -+int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, -+ int host_port, struct in_addr guest_addr, int guest_port) -+{ -+ if (!guest_addr.s_addr) { -+ guest_addr = slirp->vdhcp_startaddr; -+ } -+ if (is_udp) { -+ if (!udp_listen(slirp, host_addr.s_addr, htons(host_port), -+ guest_addr.s_addr, htons(guest_port), SS_HOSTFWD)) -+ return -1; -+ } else { -+ if (!tcp_listen(slirp, host_addr.s_addr, htons(host_port), -+ guest_addr.s_addr, htons(guest_port), SS_HOSTFWD)) -+ return -1; -+ } -+ return 0; -+} -+ -+/* TODO: IPv6 */ -+static bool check_guestfwd(Slirp *slirp, struct in_addr *guest_addr, -+ int guest_port) -+{ -+ struct gfwd_list *tmp_ptr; -+ -+ if (!guest_addr->s_addr) { -+ guest_addr->s_addr = slirp->vnetwork_addr.s_addr | -+ (htonl(0x0204) & ~slirp->vnetwork_mask.s_addr); -+ } -+ if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) != -+ slirp->vnetwork_addr.s_addr || -+ guest_addr->s_addr == slirp->vhost_addr.s_addr || -+ guest_addr->s_addr == slirp->vnameserver_addr.s_addr) { -+ return false; -+ } -+ -+ /* check if the port is "bound" */ -+ for (tmp_ptr = slirp->guestfwd_list; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) { -+ if (guest_port == tmp_ptr->ex_fport && -+ guest_addr->s_addr == tmp_ptr->ex_addr.s_addr) -+ return false; -+ } -+ -+ return true; -+} -+ -+int slirp_add_exec(Slirp *slirp, const char *cmdline, -+ struct in_addr *guest_addr, int guest_port) -+{ -+ if (!check_guestfwd(slirp, guest_addr, guest_port)) { -+ return -1; -+ } -+ -+ add_exec(&slirp->guestfwd_list, cmdline, *guest_addr, htons(guest_port)); -+ return 0; -+} -+ -+int slirp_add_unix(Slirp *slirp, const char *unixsock, -+ struct in_addr *guest_addr, int guest_port) -+{ -+#ifdef G_OS_UNIX -+ if (!check_guestfwd(slirp, guest_addr, guest_port)) { -+ return -1; -+ } -+ -+ add_unix(&slirp->guestfwd_list, unixsock, *guest_addr, htons(guest_port)); -+ return 0; -+#else -+ g_warn_if_reached(); -+ return -1; -+#endif -+} -+ -+int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque, -+ struct in_addr *guest_addr, int guest_port) -+{ -+ if (!check_guestfwd(slirp, guest_addr, guest_port)) { -+ return -1; -+ } -+ -+ add_guestfwd(&slirp->guestfwd_list, write_cb, opaque, *guest_addr, -+ htons(guest_port)); -+ return 0; -+} -+ -+int slirp_remove_guestfwd(Slirp *slirp, struct in_addr guest_addr, -+ int guest_port) -+{ -+ return remove_guestfwd(&slirp->guestfwd_list, guest_addr, -+ htons(guest_port)); -+} -+ -+ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags) -+{ -+ if (so->s == -1 && so->guestfwd) { -+ /* XXX this blocks entire thread. Rewrite to use -+ * qemu_chr_fe_write and background I/O callbacks */ -+ so->guestfwd->write_cb(buf, len, so->guestfwd->opaque); -+ return len; -+ } -+ -+ if (so->s == -1) { -+ /* -+ * This should in theory not happen but it is hard to be -+ * sure because some code paths will end up with so->s == -1 -+ * on a failure but don't dispose of the struct socket. -+ * Check specifically, so we don't pass -1 to send(). -+ */ -+ errno = EBADF; -+ return -1; -+ } -+ -+ return send(so->s, buf, len, flags); -+} -+ -+struct socket *slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, -+ int guest_port) -+{ -+ struct socket *so; -+ -+ /* TODO: IPv6 */ -+ for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) { -+ if (so->so_faddr.s_addr == guest_addr.s_addr && -+ htons(so->so_fport) == guest_port) { -+ return so; -+ } -+ } -+ return NULL; -+} -+ -+size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr, -+ int guest_port) -+{ -+ struct iovec iov[2]; -+ struct socket *so; -+ -+ so = slirp_find_ctl_socket(slirp, guest_addr, guest_port); -+ -+ if (!so || so->so_state & SS_NOFDREF) { -+ return 0; -+ } -+ -+ if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen / 2)) { -+ return 0; -+ } -+ -+ return sopreprbuf(so, iov, NULL); -+} -+ -+void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port, -+ const uint8_t *buf, int size) -+{ -+ int ret; -+ struct socket *so = slirp_find_ctl_socket(slirp, guest_addr, guest_port); -+ -+ if (!so) -+ return; -+ -+ ret = soreadbuf(so, (const char *)buf, size); -+ -+ if (ret > 0) -+ tcp_output(sototcpcb(so)); -+} -+ -+void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len) -+{ -+ ssize_t ret = slirp->cb->send_packet(buf, len, slirp->opaque); -+ -+ if (ret < 0) { -+ g_critical("Failed to send packet, ret: %ld", (long)ret); -+ } else if (ret < len) { -+ DEBUG_ERROR("send_packet() didn't send all data: %ld < %lu", (long)ret, -+ (unsigned long)len); -+ } -+} -diff --git a/slirp/src/slirp.h b/slirp/src/slirp.h -new file mode 100644 -index 0000000000..763a65b9ef ---- /dev/null -+++ b/slirp/src/slirp.h -@@ -0,0 +1,284 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+#ifndef SLIRP_H -+#define SLIRP_H -+ -+#ifdef _WIN32 -+ -+/* as defined in sdkddkver.h */ -+#ifndef _WIN32_WINNT -+#define _WIN32_WINNT 0x0600 /* Vista */ -+#endif -+/* reduces the number of implicitly included headers */ -+#ifndef WIN32_LEAN_AND_MEAN -+#define WIN32_LEAN_AND_MEAN -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+ -+#else -+#if !defined(__HAIKU__) -+#define O_BINARY 0 -+#endif -+#endif -+ -+#ifndef _WIN32 -+#include -+#include -+#include -+#include -+#include -+#endif -+ -+#ifdef __APPLE__ -+#include -+#endif -+ -+/* Avoid conflicting with the libc insque() and remque(), which -+ have different prototypes. */ -+#define insque slirp_insque -+#define remque slirp_remque -+#define quehead slirp_quehead -+ -+#include "debug.h" -+#include "util.h" -+ -+#include "libslirp.h" -+#include "ip.h" -+#include "ip6.h" -+#include "tcp.h" -+#include "tcp_timer.h" -+#include "tcp_var.h" -+#include "tcpip.h" -+#include "udp.h" -+#include "ip_icmp.h" -+#include "ip6_icmp.h" -+#include "mbuf.h" -+#include "sbuf.h" -+#include "socket.h" -+#include "if.h" -+#include "main.h" -+#include "misc.h" -+ -+#include "bootp.h" -+#include "tftp.h" -+ -+#define ARPOP_REQUEST 1 /* ARP request */ -+#define ARPOP_REPLY 2 /* ARP reply */ -+ -+struct ethhdr { -+ unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ -+ unsigned char h_source[ETH_ALEN]; /* source ether addr */ -+ unsigned short h_proto; /* packet type ID field */ -+}; -+ -+struct slirp_arphdr { -+ unsigned short ar_hrd; /* format of hardware address */ -+ unsigned short ar_pro; /* format of protocol address */ -+ unsigned char ar_hln; /* length of hardware address */ -+ unsigned char ar_pln; /* length of protocol address */ -+ unsigned short ar_op; /* ARP opcode (command) */ -+ -+ /* -+ * Ethernet looks like this : This bit is variable sized however... -+ */ -+ unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ -+ uint32_t ar_sip; /* sender IP address */ -+ unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ -+ uint32_t ar_tip; /* target IP address */ -+} SLIRP_PACKED; -+ -+#define ARP_TABLE_SIZE 16 -+ -+typedef struct ArpTable { -+ struct slirp_arphdr table[ARP_TABLE_SIZE]; -+ int next_victim; -+} ArpTable; -+ -+void arp_table_add(Slirp *slirp, uint32_t ip_addr, -+ const uint8_t ethaddr[ETH_ALEN]); -+ -+bool arp_table_search(Slirp *slirp, uint32_t ip_addr, -+ uint8_t out_ethaddr[ETH_ALEN]); -+ -+struct ndpentry { -+ unsigned char eth_addr[ETH_ALEN]; /* sender hardware address */ -+ struct in6_addr ip_addr; /* sender IP address */ -+}; -+ -+#define NDP_TABLE_SIZE 16 -+ -+typedef struct NdpTable { -+ struct ndpentry table[NDP_TABLE_SIZE]; -+ int next_victim; -+} NdpTable; -+ -+void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr, -+ uint8_t ethaddr[ETH_ALEN]); -+bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr, -+ uint8_t out_ethaddr[ETH_ALEN]); -+ -+struct Slirp { -+ unsigned time_fasttimo; -+ unsigned last_slowtimo; -+ bool do_slowtimo; -+ -+ bool in_enabled, in6_enabled; -+ -+ /* virtual network configuration */ -+ struct in_addr vnetwork_addr; -+ struct in_addr vnetwork_mask; -+ struct in_addr vhost_addr; -+ struct in6_addr vprefix_addr6; -+ uint8_t vprefix_len; -+ struct in6_addr vhost_addr6; -+ struct in_addr vdhcp_startaddr; -+ struct in_addr vnameserver_addr; -+ struct in6_addr vnameserver_addr6; -+ -+ struct in_addr client_ipaddr; -+ char client_hostname[33]; -+ -+ int restricted; -+ struct gfwd_list *guestfwd_list; -+ -+ int if_mtu; -+ int if_mru; -+ -+ bool disable_host_loopback; -+ -+ /* mbuf states */ -+ struct quehead m_freelist; -+ struct quehead m_usedlist; -+ int mbuf_alloced; -+ -+ /* if states */ -+ struct quehead if_fastq; /* fast queue (for interactive data) */ -+ struct quehead if_batchq; /* queue for non-interactive data */ -+ bool if_start_busy; /* avoid if_start recursion */ -+ -+ /* ip states */ -+ struct ipq ipq; /* ip reass. queue */ -+ uint16_t ip_id; /* ip packet ctr, for ids */ -+ -+ /* bootp/dhcp states */ -+ BOOTPClient bootp_clients[NB_BOOTP_CLIENTS]; -+ char *bootp_filename; -+ size_t vdnssearch_len; -+ uint8_t *vdnssearch; -+ char *vdomainname; -+ -+ /* tcp states */ -+ struct socket tcb; -+ struct socket *tcp_last_so; -+ tcp_seq tcp_iss; /* tcp initial send seq # */ -+ uint32_t tcp_now; /* for RFC 1323 timestamps */ -+ -+ /* udp states */ -+ struct socket udb; -+ struct socket *udp_last_so; -+ -+ /* icmp states */ -+ struct socket icmp; -+ struct socket *icmp_last_so; -+ -+ /* tftp states */ -+ char *tftp_prefix; -+ struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; -+ char *tftp_server_name; -+ -+ ArpTable arp_table; -+ NdpTable ndp_table; -+ -+ GRand *grand; -+ void *ra_timer; -+ -+ bool enable_emu; -+ -+ const SlirpCb *cb; -+ void *opaque; -+ -+ struct sockaddr_in *outbound_addr; -+ struct sockaddr_in6 *outbound_addr6; -+}; -+ -+void if_start(Slirp *); -+ -+int get_dns_addr(struct in_addr *pdns_addr); -+int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id); -+ -+/* ncsi.c */ -+void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len); -+ -+#ifndef _WIN32 -+#include -+#endif -+ -+ -+extern bool slirp_do_keepalive; -+ -+#define TCP_MAXIDLE (TCPTV_KEEPCNT * TCPTV_KEEPINTVL) -+ -+/* dnssearch.c */ -+int translate_dnssearch(Slirp *s, const char **names); -+ -+/* cksum.c */ -+int cksum(struct mbuf *m, int len); -+int ip6_cksum(struct mbuf *m); -+ -+/* if.c */ -+void if_init(Slirp *); -+void if_output(struct socket *, struct mbuf *); -+ -+/* ip_input.c */ -+void ip_init(Slirp *); -+void ip_cleanup(Slirp *); -+void ip_input(struct mbuf *); -+void ip_slowtimo(Slirp *); -+void ip_stripoptions(register struct mbuf *, struct mbuf *); -+ -+/* ip_output.c */ -+int ip_output(struct socket *, struct mbuf *); -+ -+/* ip6_input.c */ -+void ip6_init(Slirp *); -+void ip6_cleanup(Slirp *); -+void ip6_input(struct mbuf *); -+ -+/* ip6_output */ -+int ip6_output(struct socket *, struct mbuf *, int fast); -+ -+/* tcp_input.c */ -+void tcp_input(register struct mbuf *, int, struct socket *, unsigned short af); -+int tcp_mss(register struct tcpcb *, unsigned); -+ -+/* tcp_output.c */ -+int tcp_output(register struct tcpcb *); -+void tcp_setpersist(register struct tcpcb *); -+ -+/* tcp_subr.c */ -+void tcp_init(Slirp *); -+void tcp_cleanup(Slirp *); -+void tcp_template(struct tcpcb *); -+void tcp_respond(struct tcpcb *, register struct tcpiphdr *, -+ register struct mbuf *, tcp_seq, tcp_seq, int, unsigned short); -+struct tcpcb *tcp_newtcpcb(struct socket *); -+struct tcpcb *tcp_close(register struct tcpcb *); -+void tcp_sockclosed(struct tcpcb *); -+int tcp_fconnect(struct socket *, unsigned short af); -+void tcp_connect(struct socket *); -+void tcp_attach(struct socket *); -+uint8_t tcp_tos(struct socket *); -+int tcp_emu(struct socket *, struct mbuf *); -+int tcp_ctl(struct socket *); -+struct tcpcb *tcp_drop(struct tcpcb *tp, int err); -+ -+struct socket *slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, -+ int guest_port); -+ -+void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len); -+ -+#endif -diff --git a/slirp/src/socket.c b/slirp/src/socket.c -new file mode 100644 -index 0000000000..1e385df0d8 ---- /dev/null -+++ b/slirp/src/socket.c -@@ -0,0 +1,954 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * Copyright (c) 1995 Danny Gasparovski. -+ */ -+ -+#include "slirp.h" -+#include "ip_icmp.h" -+#ifdef __sun__ -+#include -+#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) { -+ g_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) { -+ int shutdown_wr = so->so_state & SS_FCANTSENDMORE; -+ -+ if (!shutdown_wr && 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(); -+ } -+ -+ /* -+ * 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(); -+ } -+ 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(); -+ } -+ } /* 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); -+} -+ -+static bool sotranslate_out4(Slirp *s, struct socket *so, struct sockaddr_in *sin) -+{ -+ if (so->so_faddr.s_addr == s->vnameserver_addr.s_addr) { -+ return get_dns_addr(&sin->sin_addr) >= 0; -+ } -+ -+ if (so->so_faddr.s_addr == s->vhost_addr.s_addr || -+ so->so_faddr.s_addr == 0xffffffff) { -+ if (s->disable_host_loopback) { -+ return false; -+ } -+ -+ sin->sin_addr = loopback_addr; -+ } -+ -+ return true; -+} -+ -+static bool sotranslate_out6(Slirp *s, struct socket *so, struct sockaddr_in6 *sin) -+{ -+ if (in6_equal(&so->so_faddr6, &s->vnameserver_addr6)) { -+ uint32_t scope_id; -+ if (get_dns6_addr(&sin->sin6_addr, &scope_id) >= 0) { -+ sin->sin6_scope_id = scope_id; -+ return true; -+ } -+ return false; -+ } -+ -+ if (in6_equal_net(&so->so_faddr6, &s->vprefix_addr6, s->vprefix_len) || -+ in6_equal(&so->so_faddr6, &(struct in6_addr)ALLNODES_MULTICAST)) { -+ if (s->disable_host_loopback) { -+ return false; -+ } -+ -+ sin->sin6_addr = in6addr_loopback; -+ } -+ -+ return true; -+} -+ -+ -+/* -+ * Translate addr in host addr when it is a virtual address -+ */ -+int sotranslate_out(struct socket *so, struct sockaddr_storage *addr) -+{ -+ bool ok = true; -+ -+ switch (addr->ss_family) { -+ case AF_INET: -+ ok = sotranslate_out4(so->slirp, so, (struct sockaddr_in *)addr); -+ break; -+ case AF_INET6: -+ ok = sotranslate_out6(so->slirp, so, (struct sockaddr_in6 *)addr); -+ break; -+ } -+ -+ if (!ok) { -+ errno = EPERM; -+ return -1; -+ } -+ -+ return 0; -+} -+ -+void sotranslate_in(struct socket *so, struct sockaddr_storage *addr) -+{ -+ Slirp *slirp = so->slirp; -+ struct sockaddr_in *sin = (struct sockaddr_in *)addr; -+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; -+ -+ switch (addr->ss_family) { -+ case AF_INET: -+ if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == -+ slirp->vnetwork_addr.s_addr) { -+ uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr; -+ -+ if ((so->so_faddr.s_addr & inv_mask) == inv_mask) { -+ sin->sin_addr = slirp->vhost_addr; -+ } else if (sin->sin_addr.s_addr == loopback_addr.s_addr || -+ so->so_faddr.s_addr != slirp->vhost_addr.s_addr) { -+ sin->sin_addr = so->so_faddr; -+ } -+ } -+ break; -+ -+ case AF_INET6: -+ if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6, -+ slirp->vprefix_len)) { -+ if (in6_equal(&sin6->sin6_addr, &in6addr_loopback) || -+ !in6_equal(&so->so_faddr6, &slirp->vhost_addr6)) { -+ sin6->sin6_addr = so->so_faddr6; -+ } -+ } -+ break; -+ -+ default: -+ break; -+ } -+} -+ -+/* -+ * Translate connections from localhost to the real hostname -+ */ -+void sotranslate_accept(struct socket *so) -+{ -+ Slirp *slirp = so->slirp; -+ -+ switch (so->so_ffamily) { -+ case AF_INET: -+ if (so->so_faddr.s_addr == INADDR_ANY || -+ (so->so_faddr.s_addr & loopback_mask) == -+ (loopback_addr.s_addr & loopback_mask)) { -+ so->so_faddr = slirp->vhost_addr; -+ } -+ break; -+ -+ case AF_INET6: -+ if (in6_equal(&so->so_faddr6, &in6addr_any) || -+ in6_equal(&so->so_faddr6, &in6addr_loopback)) { -+ so->so_faddr6 = slirp->vhost_addr6; -+ } -+ break; -+ -+ default: -+ break; -+ } -+} -+ -+void sodrop(struct socket *s, int num) -+{ -+ if (sbdrop(&s->so_snd, num)) { -+ s->slirp->cb->notify(s->slirp->opaque); -+ } -+} -diff --git a/slirp/src/socket.h b/slirp/src/socket.h -new file mode 100644 -index 0000000000..a6a1e5e214 ---- /dev/null -+++ b/slirp/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/slirp/src/state.c b/slirp/src/state.c -new file mode 100644 -index 0000000000..22af77b256 ---- /dev/null -+++ b/slirp/src/state.c -@@ -0,0 +1,379 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * libslirp -+ * -+ * Copyright (c) 2004-2008 Fabrice Bellard -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+#include "slirp.h" -+#include "vmstate.h" -+#include "stream.h" -+ -+static int slirp_tcp_post_load(void *opaque, int version) -+{ -+ tcp_template((struct tcpcb *)opaque); -+ -+ return 0; -+} -+ -+static const VMStateDescription vmstate_slirp_tcp = { -+ .name = "slirp-tcp", -+ .version_id = 0, -+ .post_load = slirp_tcp_post_load, -+ .fields = (VMStateField[]){ VMSTATE_INT16(t_state, struct tcpcb), -+ VMSTATE_INT16_ARRAY(t_timer, struct tcpcb, -+ TCPT_NTIMERS), -+ VMSTATE_INT16(t_rxtshift, struct tcpcb), -+ VMSTATE_INT16(t_rxtcur, struct tcpcb), -+ VMSTATE_INT16(t_dupacks, struct tcpcb), -+ VMSTATE_UINT16(t_maxseg, struct tcpcb), -+ VMSTATE_UINT8(t_force, struct tcpcb), -+ VMSTATE_UINT16(t_flags, struct tcpcb), -+ VMSTATE_UINT32(snd_una, struct tcpcb), -+ VMSTATE_UINT32(snd_nxt, struct tcpcb), -+ VMSTATE_UINT32(snd_up, struct tcpcb), -+ VMSTATE_UINT32(snd_wl1, struct tcpcb), -+ VMSTATE_UINT32(snd_wl2, struct tcpcb), -+ VMSTATE_UINT32(iss, struct tcpcb), -+ VMSTATE_UINT32(snd_wnd, struct tcpcb), -+ VMSTATE_UINT32(rcv_wnd, struct tcpcb), -+ VMSTATE_UINT32(rcv_nxt, struct tcpcb), -+ VMSTATE_UINT32(rcv_up, struct tcpcb), -+ VMSTATE_UINT32(irs, struct tcpcb), -+ VMSTATE_UINT32(rcv_adv, struct tcpcb), -+ VMSTATE_UINT32(snd_max, struct tcpcb), -+ VMSTATE_UINT32(snd_cwnd, struct tcpcb), -+ VMSTATE_UINT32(snd_ssthresh, struct tcpcb), -+ VMSTATE_INT16(t_idle, struct tcpcb), -+ VMSTATE_INT16(t_rtt, struct tcpcb), -+ VMSTATE_UINT32(t_rtseq, struct tcpcb), -+ VMSTATE_INT16(t_srtt, struct tcpcb), -+ VMSTATE_INT16(t_rttvar, struct tcpcb), -+ VMSTATE_UINT16(t_rttmin, struct tcpcb), -+ VMSTATE_UINT32(max_sndwnd, struct tcpcb), -+ VMSTATE_UINT8(t_oobflags, struct tcpcb), -+ VMSTATE_UINT8(t_iobc, struct tcpcb), -+ VMSTATE_INT16(t_softerror, struct tcpcb), -+ VMSTATE_UINT8(snd_scale, struct tcpcb), -+ VMSTATE_UINT8(rcv_scale, struct tcpcb), -+ VMSTATE_UINT8(request_r_scale, struct tcpcb), -+ VMSTATE_UINT8(requested_s_scale, struct tcpcb), -+ VMSTATE_UINT32(ts_recent, struct tcpcb), -+ VMSTATE_UINT32(ts_recent_age, struct tcpcb), -+ VMSTATE_UINT32(last_ack_sent, struct tcpcb), -+ VMSTATE_END_OF_LIST() } -+}; -+ -+/* The sbuf has a pair of pointers that are migrated as offsets; -+ * we calculate the offsets and restore the pointers using -+ * pre_save/post_load on a tmp structure. -+ */ -+struct sbuf_tmp { -+ struct sbuf *parent; -+ uint32_t roff, woff; -+}; -+ -+static int sbuf_tmp_pre_save(void *opaque) -+{ -+ struct sbuf_tmp *tmp = opaque; -+ tmp->woff = tmp->parent->sb_wptr - tmp->parent->sb_data; -+ tmp->roff = tmp->parent->sb_rptr - tmp->parent->sb_data; -+ -+ return 0; -+} -+ -+static int sbuf_tmp_post_load(void *opaque, int version) -+{ -+ struct sbuf_tmp *tmp = opaque; -+ uint32_t requested_len = tmp->parent->sb_datalen; -+ -+ /* Allocate the buffer space used by the field after the tmp */ -+ sbreserve(tmp->parent, tmp->parent->sb_datalen); -+ -+ if (tmp->woff >= requested_len || tmp->roff >= requested_len) { -+ g_critical("invalid sbuf offsets r/w=%u/%u len=%u", tmp->roff, -+ tmp->woff, requested_len); -+ return -EINVAL; -+ } -+ -+ tmp->parent->sb_wptr = tmp->parent->sb_data + tmp->woff; -+ tmp->parent->sb_rptr = tmp->parent->sb_data + tmp->roff; -+ -+ return 0; -+} -+ -+ -+static const VMStateDescription vmstate_slirp_sbuf_tmp = { -+ .name = "slirp-sbuf-tmp", -+ .post_load = sbuf_tmp_post_load, -+ .pre_save = sbuf_tmp_pre_save, -+ .version_id = 0, -+ .fields = (VMStateField[]){ VMSTATE_UINT32(woff, struct sbuf_tmp), -+ VMSTATE_UINT32(roff, struct sbuf_tmp), -+ VMSTATE_END_OF_LIST() } -+}; -+ -+static const VMStateDescription vmstate_slirp_sbuf = { -+ .name = "slirp-sbuf", -+ .version_id = 0, -+ .fields = (VMStateField[]){ VMSTATE_UINT32(sb_cc, struct sbuf), -+ VMSTATE_UINT32(sb_datalen, struct sbuf), -+ VMSTATE_WITH_TMP(struct sbuf, struct sbuf_tmp, -+ vmstate_slirp_sbuf_tmp), -+ VMSTATE_VBUFFER_UINT32(sb_data, struct sbuf, 0, -+ NULL, sb_datalen), -+ VMSTATE_END_OF_LIST() } -+}; -+ -+static bool slirp_older_than_v4(void *opaque, int version_id) -+{ -+ return version_id < 4; -+} -+ -+static bool slirp_family_inet(void *opaque, int version_id) -+{ -+ union slirp_sockaddr *ssa = (union slirp_sockaddr *)opaque; -+ return ssa->ss.ss_family == AF_INET; -+} -+ -+static int slirp_socket_pre_load(void *opaque) -+{ -+ struct socket *so = opaque; -+ -+ tcp_attach(so); -+ /* Older versions don't load these fields */ -+ so->so_ffamily = AF_INET; -+ so->so_lfamily = AF_INET; -+ return 0; -+} -+ -+#ifndef _WIN32 -+#define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_UINT32_TEST(f, s, t) -+#else -+/* Win uses u_long rather than uint32_t - but it's still 32bits long */ -+#define VMSTATE_SIN4_ADDR(f, s, t) \ -+ VMSTATE_SINGLE_TEST(f, s, t, 0, slirp_vmstate_info_uint32, u_long) -+#endif -+ -+/* The OS provided ss_family field isn't that portable; it's size -+ * and type varies (16/8 bit, signed, unsigned) -+ * and the values it contains aren't fully portable. -+ */ -+typedef struct SS_FamilyTmpStruct { -+ union slirp_sockaddr *parent; -+ uint16_t portable_family; -+} SS_FamilyTmpStruct; -+ -+#define SS_FAMILY_MIG_IPV4 2 /* Linux, BSD, Win... */ -+#define SS_FAMILY_MIG_IPV6 10 /* Linux */ -+#define SS_FAMILY_MIG_OTHER 0xffff -+ -+static int ss_family_pre_save(void *opaque) -+{ -+ SS_FamilyTmpStruct *tss = opaque; -+ -+ tss->portable_family = SS_FAMILY_MIG_OTHER; -+ -+ if (tss->parent->ss.ss_family == AF_INET) { -+ tss->portable_family = SS_FAMILY_MIG_IPV4; -+ } else if (tss->parent->ss.ss_family == AF_INET6) { -+ tss->portable_family = SS_FAMILY_MIG_IPV6; -+ } -+ -+ return 0; -+} -+ -+static int ss_family_post_load(void *opaque, int version_id) -+{ -+ SS_FamilyTmpStruct *tss = opaque; -+ -+ switch (tss->portable_family) { -+ case SS_FAMILY_MIG_IPV4: -+ tss->parent->ss.ss_family = AF_INET; -+ break; -+ case SS_FAMILY_MIG_IPV6: -+ case 23: /* compatibility: AF_INET6 from mingw */ -+ case 28: /* compatibility: AF_INET6 from FreeBSD sys/socket.h */ -+ tss->parent->ss.ss_family = AF_INET6; -+ break; -+ default: -+ g_critical("invalid ss_family type %x", tss->portable_family); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static const VMStateDescription vmstate_slirp_ss_family = { -+ .name = "slirp-socket-addr/ss_family", -+ .pre_save = ss_family_pre_save, -+ .post_load = ss_family_post_load, -+ .fields = -+ (VMStateField[]){ VMSTATE_UINT16(portable_family, SS_FamilyTmpStruct), -+ VMSTATE_END_OF_LIST() } -+}; -+ -+static const VMStateDescription vmstate_slirp_socket_addr = { -+ .name = "slirp-socket-addr", -+ .version_id = 4, -+ .fields = -+ (VMStateField[]){ -+ VMSTATE_WITH_TMP(union slirp_sockaddr, SS_FamilyTmpStruct, -+ vmstate_slirp_ss_family), -+ VMSTATE_SIN4_ADDR(sin.sin_addr.s_addr, union slirp_sockaddr, -+ slirp_family_inet), -+ VMSTATE_UINT16_TEST(sin.sin_port, union slirp_sockaddr, -+ slirp_family_inet), -+ -+#if 0 -+ /* Untested: Needs checking by someone with IPv6 test */ -+ VMSTATE_BUFFER_TEST(sin6.sin6_addr, union slirp_sockaddr, -+ slirp_family_inet6), -+ VMSTATE_UINT16_TEST(sin6.sin6_port, union slirp_sockaddr, -+ slirp_family_inet6), -+ VMSTATE_UINT32_TEST(sin6.sin6_flowinfo, union slirp_sockaddr, -+ slirp_family_inet6), -+ VMSTATE_UINT32_TEST(sin6.sin6_scope_id, union slirp_sockaddr, -+ slirp_family_inet6), -+#endif -+ -+ VMSTATE_END_OF_LIST() } -+}; -+ -+static const VMStateDescription vmstate_slirp_socket = { -+ .name = "slirp-socket", -+ .version_id = 4, -+ .pre_load = slirp_socket_pre_load, -+ .fields = -+ (VMStateField[]){ -+ VMSTATE_UINT32(so_urgc, struct socket), -+ /* Pre-v4 versions */ -+ VMSTATE_SIN4_ADDR(so_faddr.s_addr, struct socket, -+ slirp_older_than_v4), -+ VMSTATE_SIN4_ADDR(so_laddr.s_addr, struct socket, -+ slirp_older_than_v4), -+ VMSTATE_UINT16_TEST(so_fport, struct socket, slirp_older_than_v4), -+ VMSTATE_UINT16_TEST(so_lport, struct socket, slirp_older_than_v4), -+ /* v4 and newer */ -+ VMSTATE_STRUCT(fhost, struct socket, 4, vmstate_slirp_socket_addr, -+ union slirp_sockaddr), -+ VMSTATE_STRUCT(lhost, struct socket, 4, vmstate_slirp_socket_addr, -+ union slirp_sockaddr), -+ -+ VMSTATE_UINT8(so_iptos, struct socket), -+ VMSTATE_UINT8(so_emu, struct socket), -+ VMSTATE_UINT8(so_type, struct socket), -+ VMSTATE_INT32(so_state, struct socket), -+ VMSTATE_STRUCT(so_rcv, struct socket, 0, vmstate_slirp_sbuf, -+ struct sbuf), -+ VMSTATE_STRUCT(so_snd, struct socket, 0, vmstate_slirp_sbuf, -+ struct sbuf), -+ VMSTATE_STRUCT_POINTER(so_tcpcb, struct socket, vmstate_slirp_tcp, -+ struct tcpcb), -+ VMSTATE_END_OF_LIST() } -+}; -+ -+static const VMStateDescription vmstate_slirp_bootp_client = { -+ .name = "slirp_bootpclient", -+ .fields = (VMStateField[]){ VMSTATE_UINT16(allocated, BOOTPClient), -+ VMSTATE_BUFFER(macaddr, BOOTPClient), -+ VMSTATE_END_OF_LIST() } -+}; -+ -+static const VMStateDescription vmstate_slirp = { -+ .name = "slirp", -+ .version_id = 4, -+ .fields = (VMStateField[]){ VMSTATE_UINT16_V(ip_id, Slirp, 2), -+ VMSTATE_STRUCT_ARRAY( -+ bootp_clients, Slirp, NB_BOOTP_CLIENTS, 3, -+ vmstate_slirp_bootp_client, BOOTPClient), -+ VMSTATE_END_OF_LIST() } -+}; -+ -+void slirp_state_save(Slirp *slirp, SlirpWriteCb write_cb, void *opaque) -+{ -+ struct gfwd_list *ex_ptr; -+ SlirpOStream f = { -+ .write_cb = write_cb, -+ .opaque = opaque, -+ }; -+ -+ for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) -+ if (ex_ptr->write_cb) { -+ struct socket *so; -+ so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr, -+ ntohs(ex_ptr->ex_fport)); -+ if (!so) { -+ continue; -+ } -+ -+ slirp_ostream_write_u8(&f, 42); -+ slirp_vmstate_save_state(&f, &vmstate_slirp_socket, so); -+ } -+ slirp_ostream_write_u8(&f, 0); -+ -+ slirp_vmstate_save_state(&f, &vmstate_slirp, slirp); -+} -+ -+ -+int slirp_state_load(Slirp *slirp, int version_id, SlirpReadCb read_cb, -+ void *opaque) -+{ -+ struct gfwd_list *ex_ptr; -+ SlirpIStream f = { -+ .read_cb = read_cb, -+ .opaque = opaque, -+ }; -+ -+ while (slirp_istream_read_u8(&f)) { -+ int ret; -+ struct socket *so = socreate(slirp); -+ -+ ret = -+ slirp_vmstate_load_state(&f, &vmstate_slirp_socket, so, version_id); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) != -+ slirp->vnetwork_addr.s_addr) { -+ return -EINVAL; -+ } -+ for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { -+ if (ex_ptr->write_cb && -+ so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr && -+ so->so_fport == ex_ptr->ex_fport) { -+ break; -+ } -+ } -+ if (!ex_ptr) { -+ return -EINVAL; -+ } -+ -+ so->guestfwd = ex_ptr; -+ } -+ -+ return slirp_vmstate_load_state(&f, &vmstate_slirp, slirp, version_id); -+} -+ -+int slirp_state_version(void) -+{ -+ return 4; -+} -diff --git a/slirp/src/stream.c b/slirp/src/stream.c -new file mode 100644 -index 0000000000..6cf326f669 ---- /dev/null -+++ b/slirp/src/stream.c -@@ -0,0 +1,120 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * libslirp io streams -+ * -+ * Copyright (c) 2018 Red Hat, Inc. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+#include "stream.h" -+#include -+ -+bool slirp_istream_read(SlirpIStream *f, void *buf, size_t size) -+{ -+ return f->read_cb(buf, size, f->opaque) == size; -+} -+ -+bool slirp_ostream_write(SlirpOStream *f, const void *buf, size_t size) -+{ -+ return f->write_cb(buf, size, f->opaque) == size; -+} -+ -+uint8_t slirp_istream_read_u8(SlirpIStream *f) -+{ -+ uint8_t b; -+ -+ if (slirp_istream_read(f, &b, sizeof(b))) { -+ return b; -+ } -+ -+ return 0; -+} -+ -+bool slirp_ostream_write_u8(SlirpOStream *f, uint8_t b) -+{ -+ return slirp_ostream_write(f, &b, sizeof(b)); -+} -+ -+uint16_t slirp_istream_read_u16(SlirpIStream *f) -+{ -+ uint16_t b; -+ -+ if (slirp_istream_read(f, &b, sizeof(b))) { -+ return GUINT16_FROM_BE(b); -+ } -+ -+ return 0; -+} -+ -+bool slirp_ostream_write_u16(SlirpOStream *f, uint16_t b) -+{ -+ b = GUINT16_TO_BE(b); -+ return slirp_ostream_write(f, &b, sizeof(b)); -+} -+ -+uint32_t slirp_istream_read_u32(SlirpIStream *f) -+{ -+ uint32_t b; -+ -+ if (slirp_istream_read(f, &b, sizeof(b))) { -+ return GUINT32_FROM_BE(b); -+ } -+ -+ return 0; -+} -+ -+bool slirp_ostream_write_u32(SlirpOStream *f, uint32_t b) -+{ -+ b = GUINT32_TO_BE(b); -+ return slirp_ostream_write(f, &b, sizeof(b)); -+} -+ -+int16_t slirp_istream_read_i16(SlirpIStream *f) -+{ -+ int16_t b; -+ -+ if (slirp_istream_read(f, &b, sizeof(b))) { -+ return GINT16_FROM_BE(b); -+ } -+ -+ return 0; -+} -+ -+bool slirp_ostream_write_i16(SlirpOStream *f, int16_t b) -+{ -+ b = GINT16_TO_BE(b); -+ return slirp_ostream_write(f, &b, sizeof(b)); -+} -+ -+int32_t slirp_istream_read_i32(SlirpIStream *f) -+{ -+ int32_t b; -+ -+ if (slirp_istream_read(f, &b, sizeof(b))) { -+ return GINT32_FROM_BE(b); -+ } -+ -+ return 0; -+} -+ -+bool slirp_ostream_write_i32(SlirpOStream *f, int32_t b) -+{ -+ b = GINT32_TO_BE(b); -+ return slirp_ostream_write(f, &b, sizeof(b)); -+} -diff --git a/slirp/src/stream.h b/slirp/src/stream.h -new file mode 100644 -index 0000000000..08bb5b6610 ---- /dev/null -+++ b/slirp/src/stream.h -@@ -0,0 +1,35 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+#ifndef STREAM_H_ -+#define STREAM_H_ -+ -+#include "libslirp.h" -+ -+typedef struct SlirpIStream { -+ SlirpReadCb read_cb; -+ void *opaque; -+} SlirpIStream; -+ -+typedef struct SlirpOStream { -+ SlirpWriteCb write_cb; -+ void *opaque; -+} SlirpOStream; -+ -+bool slirp_istream_read(SlirpIStream *f, void *buf, size_t size); -+bool slirp_ostream_write(SlirpOStream *f, const void *buf, size_t size); -+ -+uint8_t slirp_istream_read_u8(SlirpIStream *f); -+bool slirp_ostream_write_u8(SlirpOStream *f, uint8_t b); -+ -+uint16_t slirp_istream_read_u16(SlirpIStream *f); -+bool slirp_ostream_write_u16(SlirpOStream *f, uint16_t b); -+ -+uint32_t slirp_istream_read_u32(SlirpIStream *f); -+bool slirp_ostream_write_u32(SlirpOStream *f, uint32_t b); -+ -+int16_t slirp_istream_read_i16(SlirpIStream *f); -+bool slirp_ostream_write_i16(SlirpOStream *f, int16_t b); -+ -+int32_t slirp_istream_read_i32(SlirpIStream *f); -+bool slirp_ostream_write_i32(SlirpOStream *f, int32_t b); -+ -+#endif /* STREAM_H_ */ -diff --git a/slirp/src/tcp.h b/slirp/src/tcp.h -new file mode 100644 -index 0000000000..70a9760664 ---- /dev/null -+++ b/slirp/src/tcp.h -@@ -0,0 +1,169 @@ -+/* 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. -+ * -+ * @(#)tcp.h 8.1 (Berkeley) 6/10/93 -+ * tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp -+ */ -+ -+#ifndef TCP_H -+#define TCP_H -+ -+#include -+ -+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 1024 * 128 -+#define TCP_RCVSPACE 1024 * 128 -+#define TCP_MAXSEG_MAX 32768 -+ -+/* -+ * TCP header. -+ * Per RFC 793, September, 1981. -+ */ -+#define tcphdr slirp_tcphdr -+struct tcphdr { -+ uint16_t th_sport; /* source port */ -+ uint16_t th_dport; /* destination port */ -+ tcp_seq th_seq; /* sequence number */ -+ tcp_seq th_ack; /* acknowledgement number */ -+#if G_BYTE_ORDER == G_BIG_ENDIAN -+ uint8_t th_off : 4, /* data offset */ -+ th_x2 : 4; /* (unused) */ -+#else -+ uint8_t th_x2 : 4, /* (unused) */ -+ th_off : 4; /* data offset */ -+#endif -+ uint8_t th_flags; -+ uint16_t th_win; /* window */ -+ uint16_t th_sum; /* checksum */ -+ uint16_t th_urp; /* urgent pointer */ -+}; -+ -+#include "tcp_var.h" -+ -+#ifndef TH_FIN -+#define TH_FIN 0x01 -+#define TH_SYN 0x02 -+#define TH_RST 0x04 -+#define TH_PUSH 0x08 -+#define TH_ACK 0x10 -+#define TH_URG 0x20 -+#endif -+ -+#ifndef TCPOPT_EOL -+#define TCPOPT_EOL 0 -+#define TCPOPT_NOP 1 -+#define TCPOPT_MAXSEG 2 -+#define TCPOPT_WINDOW 3 -+#define TCPOPT_SACK_PERMITTED 4 /* Experimental */ -+#define TCPOPT_SACK 5 /* Experimental */ -+#define TCPOPT_TIMESTAMP 8 -+ -+#define TCPOPT_TSTAMP_HDR \ -+ (TCPOPT_NOP << 24 | TCPOPT_NOP << 16 | TCPOPT_TIMESTAMP << 8 | \ -+ TCPOLEN_TIMESTAMP) -+#endif -+ -+#ifndef TCPOLEN_MAXSEG -+#define TCPOLEN_MAXSEG 4 -+#define TCPOLEN_WINDOW 3 -+#define TCPOLEN_SACK_PERMITTED 2 -+#define TCPOLEN_TIMESTAMP 10 -+#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP + 2) /* appendix A */ -+#endif -+ -+#undef TCP_MAXWIN -+#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ -+ -+#undef TCP_MAX_WINSHIFT -+#define TCP_MAX_WINSHIFT 14 /* maximum window shift */ -+ -+/* -+ * User-settable options (used with setsockopt). -+ * -+ * We don't use the system headers on unix because we have conflicting -+ * local structures. We can't avoid the system definitions on Windows, -+ * so we undefine them. -+ */ -+#undef TCP_NODELAY -+#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ -+#undef TCP_MAXSEG -+ -+/* -+ * TCP FSM state definitions. -+ * Per RFC793, September, 1981. -+ */ -+ -+#define TCP_NSTATES 11 -+ -+#define TCPS_CLOSED 0 /* closed */ -+#define TCPS_LISTEN 1 /* listening for connection */ -+#define TCPS_SYN_SENT 2 /* active, have sent syn */ -+#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ -+/* states < TCPS_ESTABLISHED are those where connections not established */ -+#define TCPS_ESTABLISHED 4 /* established */ -+#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ -+/* states > TCPS_CLOSE_WAIT are those where user has closed */ -+#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ -+#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ -+#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ -+/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ -+#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ -+#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ -+ -+#define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) -+#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) -+#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) -+ -+/* -+ * TCP sequence numbers are 32 bit integers operated -+ * on with modular arithmetic. These macros can be -+ * used to compare such integers. -+ */ -+#define SEQ_LT(a, b) ((int)((a) - (b)) < 0) -+#define SEQ_LEQ(a, b) ((int)((a) - (b)) <= 0) -+#define SEQ_GT(a, b) ((int)((a) - (b)) > 0) -+#define SEQ_GEQ(a, b) ((int)((a) - (b)) >= 0) -+ -+/* -+ * Macros to initialize tcp sequence numbers for -+ * send and receive from initial send and receive -+ * sequence numbers. -+ */ -+#define tcp_rcvseqinit(tp) (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1 -+ -+#define tcp_sendseqinit(tp) \ -+ (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss -+ -+#define TCP_ISSINCR (125 * 1024) /* increment for tcp_iss each second */ -+ -+#endif -diff --git a/slirp/src/tcp_input.c b/slirp/src/tcp_input.c -new file mode 100644 -index 0000000000..d55b0c81dc ---- /dev/null -+++ b/slirp/src/tcp_input.c -@@ -0,0 +1,1539 @@ -+/* 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); -+ tcp_attach(so); -+ -+ 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: -+ * -+ * 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/slirp/src/tcp_output.c b/slirp/src/tcp_output.c -new file mode 100644 -index 0000000000..383fe31dcf ---- /dev/null -+++ b/slirp/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/slirp/src/tcp_subr.c b/slirp/src/tcp_subr.c -new file mode 100644 -index 0000000000..a1016d90df ---- /dev/null -+++ b/slirp/src/tcp_subr.c -@@ -0,0 +1,980 @@ -+/* 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 = g_new0(struct tcpcb, 1); -+ 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); -+ } -+ g_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; -+ tcp_close(tp); -+ return; -+ -+ 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) { -+ ret = slirp_bind_outbound(so, af); -+ if (ret < 0) { -+ // bind failed - close socket -+ closesocket(so->s); -+ so->s = -1; -+ return (ret); -+ } -+ } -+ -+ 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); -+ tcp_attach(so); -+ 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. -+ */ -+void tcp_attach(struct socket *so) -+{ -+ so->so_tcpcb = tcp_newtcpcb(so); -+ insque(so, &so->slirp->tcb); -+} -+ -+/* -+ * 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 If there is more than one command in the packet, the others may -+ * be truncated. -+ * XXX If the command is too long, it may be truncated. -+ * -+ * 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, g_snprintf(NULL, 0, "%d,%d\r\n", n1, n2) + 1); -+ m->m_len = slirp_fmt(m->m_data, M_ROOM(m), "%d,%d\r\n", n1, n2); -+ } 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 += slirp_fmt(bptr, M_FREEROOM(m), -+ "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 += slirp_fmt(bptr, M_FREEROOM(m), -+ "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 = slirp_fmt0(m->m_data, M_ROOM(m), -+ "%d", ntohs(so->so_fport)); -+ 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 += slirp_fmt(bptr, M_FREEROOM(m), -+ "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 += slirp_fmt(bptr, M_FREEROOM(m), -+ "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 += slirp_fmt(bptr, M_FREEROOM(m), -+ "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: -+ if (bptr == m->m_data + m->m_len - 1) -+ return 1; /* We need two bytes */ -+ -+ /* -+ * 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. -+ */ -+ -+ if (bptr == m->m_data + m->m_len - 1) -+ return 1; /* We need two bytes */ -+ -+ 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); -+ if (ex_ptr->ex_unix) -+ return open_unix(so, ex_ptr->ex_unix); -+ else -+ return fork_exec(so, ex_ptr->ex_exec); -+ } -+ } -+ } -+ sb->sb_cc = slirp_fmt(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data), -+ "Error: No application configured.\r\n"); -+ sb->sb_wptr += sb->sb_cc; -+ return 0; -+} -diff --git a/slirp/src/tcp_timer.c b/slirp/src/tcp_timer.c -new file mode 100644 -index 0000000000..102023e7cd ---- /dev/null -+++ b/slirp/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/slirp/src/tcp_timer.h b/slirp/src/tcp_timer.h -new file mode 100644 -index 0000000000..584a5594e4 ---- /dev/null -+++ b/slirp/src/tcp_timer.h -@@ -0,0 +1,130 @@ -+/* 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. -+ * -+ * @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93 -+ * tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp -+ */ -+ -+#ifndef TCP_TIMER_H -+#define TCP_TIMER_H -+ -+/* -+ * Definitions of the TCP timers. These timers are counted -+ * down PR_SLOWHZ times a second. -+ */ -+#define TCPT_NTIMERS 4 -+ -+#define TCPT_REXMT 0 /* retransmit */ -+#define TCPT_PERSIST 1 /* retransmit persistence */ -+#define TCPT_KEEP 2 /* keep alive */ -+#define TCPT_2MSL 3 /* 2*msl quiet time timer */ -+ -+/* -+ * The TCPT_REXMT timer is used to force retransmissions. -+ * The TCP has the TCPT_REXMT timer set whenever segments -+ * have been sent for which ACKs are expected but not yet -+ * received. If an ACK is received which advances tp->snd_una, -+ * then the retransmit timer is cleared (if there are no more -+ * outstanding segments) or reset to the base value (if there -+ * are more ACKs expected). Whenever the retransmit timer goes off, -+ * we retransmit one unacknowledged segment, and do a backoff -+ * on the retransmit timer. -+ * -+ * The TCPT_PERSIST timer is used to keep window size information -+ * flowing even if the window goes shut. If all previous transmissions -+ * have been acknowledged (so that there are no retransmissions in progress), -+ * and the window is too small to bother sending anything, then we start -+ * the TCPT_PERSIST timer. When it expires, if the window is nonzero, -+ * we go to transmit state. Otherwise, at intervals send a single byte -+ * into the peer's window to force him to update our window information. -+ * We do this at most as often as TCPT_PERSMIN time intervals, -+ * but no more frequently than the current estimate of round-trip -+ * packet time. The TCPT_PERSIST timer is cleared whenever we receive -+ * a window update from the peer. -+ * -+ * The TCPT_KEEP timer is used to keep connections alive. If an -+ * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time, -+ * but not yet established, then we drop the connection. Once the connection -+ * is established, if the connection is idle for TCPTV_KEEP_IDLE time -+ * (and keepalives have been enabled on the socket), we begin to probe -+ * the connection. We force the peer to send us a segment by sending: -+ * -+ * This segment is (deliberately) outside the window, and should elicit -+ * an ack segment in response from the peer. If, despite the TCPT_KEEP -+ * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE -+ * amount of time probing, then we drop the connection. -+ */ -+ -+/* -+ * Time constants. -+ */ -+#define TCPTV_MSL (5 * PR_SLOWHZ) /* max seg lifetime (hah!) */ -+ -+#define TCPTV_SRTTBASE \ -+ 0 /* base roundtrip time; \ -+ if 0, no idea yet */ -+#define TCPTV_SRTTDFLT (3 * PR_SLOWHZ) /* assumed RTT if no info */ -+ -+#define TCPTV_PERSMIN (5 * PR_SLOWHZ) /* retransmit persistence */ -+#define TCPTV_PERSMAX (60 * PR_SLOWHZ) /* maximum persist interval */ -+ -+#define TCPTV_KEEP_INIT (75 * PR_SLOWHZ) /* initial connect keep alive */ -+#define TCPTV_KEEP_IDLE (120 * 60 * PR_SLOWHZ) /* dflt time before probing */ -+#define TCPTV_KEEPINTVL (75 * PR_SLOWHZ) /* default probe interval */ -+#define TCPTV_KEEPCNT 8 /* max probes before drop */ -+ -+#define TCPTV_MIN (1 * PR_SLOWHZ) /* minimum allowable value */ -+#define TCPTV_REXMTMAX (12 * PR_SLOWHZ) /* max allowable REXMT value */ -+ -+#define TCP_LINGERTIME 120 /* linger at most 2 minutes */ -+ -+#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ -+ -+ -+/* -+ * Force a time value to be in a certain range. -+ */ -+#define TCPT_RANGESET(tv, value, tvmin, tvmax) \ -+ { \ -+ (tv) = (value); \ -+ if ((tv) < (tvmin)) \ -+ (tv) = (tvmin); \ -+ else if ((tv) > (tvmax)) \ -+ (tv) = (tvmax); \ -+ } -+ -+extern const int tcp_backoff[]; -+ -+struct tcpcb; -+ -+void tcp_fasttimo(Slirp *); -+void tcp_slowtimo(Slirp *); -+void tcp_canceltimers(struct tcpcb *); -+ -+#endif -diff --git a/slirp/src/tcp_var.h b/slirp/src/tcp_var.h -new file mode 100644 -index 0000000000..c8da8cbd16 ---- /dev/null -+++ b/slirp/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/slirp/src/tcpip.h b/slirp/src/tcpip.h -new file mode 100644 -index 0000000000..d3df021493 ---- /dev/null -+++ b/slirp/src/tcpip.h -@@ -0,0 +1,104 @@ -+/* 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. -+ * -+ * @(#)tcpip.h 8.1 (Berkeley) 6/10/93 -+ * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp -+ */ -+ -+#ifndef TCPIP_H -+#define TCPIP_H -+ -+/* -+ * Tcp+ip header, after ip options removed. -+ */ -+struct tcpiphdr { -+ struct mbuf_ptr ih_mbuf; /* backpointer to mbuf */ -+ union { -+ struct { -+ struct in_addr ih_src; /* source internet address */ -+ struct in_addr ih_dst; /* destination internet address */ -+ uint8_t ih_x1; /* (unused) */ -+ uint8_t ih_pr; /* protocol */ -+ } ti_i4; -+ struct { -+ struct in6_addr ih_src; -+ struct in6_addr ih_dst; -+ uint8_t ih_x1; -+ uint8_t ih_nh; -+ } ti_i6; -+ } ti; -+ uint16_t ti_x0; -+ uint16_t ti_len; /* protocol length */ -+ struct tcphdr ti_t; /* tcp header */ -+}; -+#define ti_mbuf ih_mbuf.mptr -+#define ti_pr ti.ti_i4.ih_pr -+#define ti_src ti.ti_i4.ih_src -+#define ti_dst ti.ti_i4.ih_dst -+#define ti_src6 ti.ti_i6.ih_src -+#define ti_dst6 ti.ti_i6.ih_dst -+#define ti_nh6 ti.ti_i6.ih_nh -+#define ti_sport ti_t.th_sport -+#define ti_dport ti_t.th_dport -+#define ti_seq ti_t.th_seq -+#define ti_ack ti_t.th_ack -+#define ti_x2 ti_t.th_x2 -+#define ti_off ti_t.th_off -+#define ti_flags ti_t.th_flags -+#define ti_win ti_t.th_win -+#define ti_sum ti_t.th_sum -+#define ti_urp ti_t.th_urp -+ -+#define tcpiphdr2qlink(T) \ -+ ((struct qlink *)(((char *)(T)) - sizeof(struct qlink))) -+#define qlink2tcpiphdr(Q) \ -+ ((struct tcpiphdr *)(((char *)(Q)) + sizeof(struct qlink))) -+#define tcpiphdr_next(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->next) -+#define tcpiphdr_prev(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->prev) -+#define tcpfrag_list_first(T) qlink2tcpiphdr((T)->seg_next) -+#define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink *)(T)) -+#define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr *)(T)) -+ -+/* This is the difference between the size of a tcpiphdr structure, and the -+ * size of actual ip+tcp headers, rounded up since we need to align data. */ -+#define TCPIPHDR_DELTA \ -+ (MAX(0, (sizeof(struct tcpiphdr) - sizeof(struct ip) - \ -+ sizeof(struct tcphdr) + 3) & \ -+ ~3)) -+ -+/* -+ * Just a clean way to get to the first byte -+ * of the packet -+ */ -+struct tcpiphdr_2 { -+ struct tcpiphdr dummy; -+ char first_char; -+}; -+ -+#endif -diff --git a/slirp/src/tftp.c b/slirp/src/tftp.c -new file mode 100644 -index 0000000000..c6950ee10f ---- /dev/null -+++ b/slirp/src/tftp.c -@@ -0,0 +1,464 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * tftp.c - a simple, read-only tftp server for qemu -+ * -+ * Copyright (c) 2004 Magnus Damm -+ * -+ * 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 -+#include -+#include -+ -+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) { -+ if (lseek(spt->fd, block_nr * spt->block_size, SEEK_SET) == (off_t)-1) { -+ return -1; -+ } -+ -+ 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 += slirp_fmt0(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s", keys[i]); -+ n += slirp_fmt0(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u", values[i]); -+ } -+ -+ m->m_len = G_SIZEOF_MEMBER(struct tftp_t, tp_op) + n; -+ 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 ( -+#ifdef G_OS_WIN32 -+ strstr(req_fname, "..\\") || -+ req_fname[strlen(req_fname) - 1] == '\\' || -+#endif -+ strstr(req_fname, "../") || -+ req_fname[strlen(req_fname) - 1] == '/') { -+ tftp_send_error(spt, 2, "Access violation", tp); -+ return; -+ } -+ -+ /* check if the file exists */ -+ if (tftp_read_data(spt, 0, NULL, 0) < 0) { -+ tftp_send_error(spt, 1, "File not found", tp); -+ return; -+ } -+ -+ if (tp->x.tp_buf[pktlen - 1] != 0) { -+ tftp_send_error(spt, 2, "Access violation", tp); -+ return; -+ } -+ -+ while (k < pktlen && nb_options < G_N_ELEMENTS(option_name)) { -+ const char *key, *value; -+ -+ key = &tp->x.tp_buf[k]; -+ k += strlen(key) + 1; -+ -+ if (k >= pktlen) { -+ tftp_send_error(spt, 2, "Access violation", tp); -+ return; -+ } -+ -+ value = &tp->x.tp_buf[k]; -+ k += strlen(value) + 1; -+ -+ if (strcasecmp(key, "tsize") == 0) { -+ int tsize = atoi(value); -+ struct stat stat_p; -+ -+ if (tsize == 0) { -+ if (stat(spt->filename, &stat_p) == 0) -+ tsize = stat_p.st_size; -+ else { -+ tftp_send_error(spt, 1, "File not found", tp); -+ return; -+ } -+ } -+ -+ option_name[nb_options] = "tsize"; -+ option_value[nb_options] = tsize; -+ nb_options++; -+ } else if (strcasecmp(key, "blksize") == 0) { -+ int blksize = atoi(value); -+ -+ /* Accept blksize up to our maximum size */ -+ if (blksize > 0) { -+ spt->block_size = MIN(blksize, TFTP_BLOCKSIZE_MAX); -+ option_name[nb_options] = "blksize"; -+ option_value[nb_options] = spt->block_size; -+ nb_options++; -+ } -+ } -+ } -+ -+ if (nb_options > 0) { -+ assert(nb_options <= G_N_ELEMENTS(option_name)); -+ tftp_send_oack(spt, option_name, option_value, nb_options, tp); -+ return; -+ } -+ -+ spt->block_nr = 0; -+ tftp_send_next_block(spt, tp); -+} -+ -+static void tftp_handle_ack(Slirp *slirp, struct sockaddr_storage *srcsas, -+ struct tftp_t *tp, int pktlen) -+{ -+ int s; -+ -+ s = tftp_session_find(slirp, srcsas, tp); -+ -+ if (s < 0) { -+ return; -+ } -+ -+ tftp_send_next_block(&slirp->tftp_sessions[s], tp); -+} -+ -+static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas, -+ struct tftp_t *tp, int pktlen) -+{ -+ int s; -+ -+ s = tftp_session_find(slirp, srcsas, tp); -+ -+ if (s < 0) { -+ return; -+ } -+ -+ tftp_session_terminate(&slirp->tftp_sessions[s]); -+} -+ -+void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m) -+{ -+ struct tftp_t *tp = (struct tftp_t *)m->m_data; -+ -+ switch (ntohs(tp->tp_op)) { -+ case TFTP_RRQ: -+ tftp_handle_rrq(m->slirp, srcsas, tp, m->m_len); -+ break; -+ -+ case TFTP_ACK: -+ tftp_handle_ack(m->slirp, srcsas, tp, m->m_len); -+ break; -+ -+ case TFTP_ERROR: -+ tftp_handle_error(m->slirp, srcsas, tp, m->m_len); -+ break; -+ } -+} -diff --git a/slirp/src/tftp.h b/slirp/src/tftp.h -new file mode 100644 -index 0000000000..6d75478e83 ---- /dev/null -+++ b/slirp/src/tftp.h -@@ -0,0 +1,54 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* tftp defines */ -+ -+#ifndef SLIRP_TFTP_H -+#define SLIRP_TFTP_H -+ -+#include "util.h" -+ -+#define TFTP_SESSIONS_MAX 20 -+ -+#define TFTP_SERVER 69 -+ -+#define TFTP_RRQ 1 -+#define TFTP_WRQ 2 -+#define TFTP_DATA 3 -+#define TFTP_ACK 4 -+#define TFTP_ERROR 5 -+#define TFTP_OACK 6 -+ -+#define TFTP_FILENAME_MAX 512 -+#define TFTP_BLOCKSIZE_MAX 1428 -+ -+struct tftp_t { -+ struct udphdr udp; -+ uint16_t tp_op; -+ union { -+ struct { -+ uint16_t tp_block_nr; -+ uint8_t tp_buf[TFTP_BLOCKSIZE_MAX]; -+ } tp_data; -+ struct { -+ uint16_t tp_error_code; -+ uint8_t tp_msg[TFTP_BLOCKSIZE_MAX]; -+ } tp_error; -+ char tp_buf[TFTP_BLOCKSIZE_MAX + 2]; -+ } x; -+} SLIRP_PACKED; -+ -+struct tftp_session { -+ Slirp *slirp; -+ char *filename; -+ int fd; -+ uint16_t block_size; -+ -+ struct sockaddr_storage client_addr; -+ uint16_t client_port; -+ uint32_t block_nr; -+ -+ int timestamp; -+}; -+ -+void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m); -+ -+#endif -diff --git a/slirp/src/udp.c b/slirp/src/udp.c -new file mode 100644 -index 0000000000..0ad44d7c03 ---- /dev/null -+++ b/slirp/src/udp.c -@@ -0,0 +1,365 @@ -+/* 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) -+{ -+ struct socket *so, *so_next; -+ -+ for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) { -+ so_next = so->so_next; -+ 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) { -+ if (slirp_bind_outbound(so, af) != 0) { -+ // bind failed - close socket -+ closesocket(so->s); -+ so->s = -1; -+ return -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); -+ -+ memset(&addr, 0, sizeof(addr)); -+ so = socreate(slirp); -+ so->s = slirp_socket(AF_INET, SOCK_DGRAM, 0); -+ if (so->s < 0) { -+ sofree(so); -+ return NULL; -+ } -+ so->so_expire = curtime + SO_EXPIRE; -+ insque(so, &slirp->udb); -+ -+ addr.sin_family = AF_INET; -+ addr.sin_addr.s_addr = haddr; -+ addr.sin_port = hport; -+ -+ if (bind(so->s, (struct sockaddr *)&addr, addrlen) < 0) { -+ udp_detach(so); -+ return NULL; -+ } -+ slirp_socket_set_fast_reuse(so->s); -+ -+ getsockname(so->s, (struct sockaddr *)&addr, &addrlen); -+ so->fhost.sin = addr; -+ sotranslate_accept(so); -+ so->so_lfamily = AF_INET; -+ so->so_lport = lport; -+ so->so_laddr.s_addr = laddr; -+ if (flags != SS_FACCEPTONCE) -+ so->so_expire = 0; -+ -+ so->so_state &= SS_PERSISTENT_MASK; -+ so->so_state |= SS_ISFCONNECTED | flags; -+ -+ return so; -+} -diff --git a/slirp/src/udp.h b/slirp/src/udp.h -new file mode 100644 -index 0000000000..c3b83fdc56 ---- /dev/null -+++ b/slirp/src/udp.h -@@ -0,0 +1,90 @@ -+/* 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. -+ * -+ * @(#)udp.h 8.1 (Berkeley) 6/10/93 -+ * udp.h,v 1.3 1994/08/21 05:27:41 paul Exp -+ */ -+ -+#ifndef UDP_H -+#define UDP_H -+ -+#define UDP_TTL 0x60 -+#define UDP_UDPDATALEN 16192 -+ -+/* -+ * Udp protocol header. -+ * Per RFC 768, September, 1981. -+ */ -+struct udphdr { -+ uint16_t uh_sport; /* source port */ -+ uint16_t uh_dport; /* destination port */ -+ int16_t uh_ulen; /* udp length */ -+ uint16_t uh_sum; /* udp checksum */ -+}; -+ -+/* -+ * UDP kernel structures and variables. -+ */ -+struct udpiphdr { -+ struct ipovly ui_i; /* overlaid ip structure */ -+ struct udphdr ui_u; /* udp header */ -+}; -+#define ui_mbuf ui_i.ih_mbuf.mptr -+#define ui_x1 ui_i.ih_x1 -+#define ui_pr ui_i.ih_pr -+#define ui_len ui_i.ih_len -+#define ui_src ui_i.ih_src -+#define ui_dst ui_i.ih_dst -+#define ui_sport ui_u.uh_sport -+#define ui_dport ui_u.uh_dport -+#define ui_ulen ui_u.uh_ulen -+#define ui_sum ui_u.uh_sum -+ -+/* -+ * Names for UDP sysctl objects -+ */ -+#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ -+#define UDPCTL_MAXID 2 -+ -+struct mbuf; -+ -+void udp_init(Slirp *); -+void udp_cleanup(Slirp *); -+void udp_input(register struct mbuf *, int); -+int udp_attach(struct socket *, unsigned short af); -+void udp_detach(struct socket *); -+struct socket *udp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned, int); -+int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr, -+ struct sockaddr_in *daddr, int iptos); -+ -+void udp6_input(register struct mbuf *); -+int udp6_output(struct socket *so, struct mbuf *m, struct sockaddr_in6 *saddr, -+ struct sockaddr_in6 *daddr); -+ -+#endif -diff --git a/slirp/src/udp6.c b/slirp/src/udp6.c -new file mode 100644 -index 0000000000..6f9486bbca ---- /dev/null -+++ b/slirp/src/udp6.c -@@ -0,0 +1,173 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * Copyright (c) 2013 -+ * Guillaume Subiron -+ */ -+ -+#include "slirp.h" -+#include "udp.h" -+#include "dhcpv6.h" -+ -+void udp6_input(struct mbuf *m) -+{ -+ Slirp *slirp = m->slirp; -+ struct ip6 *ip, save_ip; -+ struct udphdr *uh; -+ int iphlen = sizeof(struct ip6); -+ int len; -+ struct socket *so; -+ struct sockaddr_in6 lhost; -+ -+ DEBUG_CALL("udp6_input"); -+ DEBUG_ARG("m = %p", m); -+ -+ if (slirp->restricted) { -+ goto bad; -+ } -+ -+ ip = mtod(m, struct ip6 *); -+ m->m_len -= iphlen; -+ m->m_data += iphlen; -+ uh = mtod(m, struct udphdr *); -+ m->m_len += iphlen; -+ m->m_data -= iphlen; -+ -+ if (ip6_cksum(m)) { -+ goto bad; -+ } -+ -+ len = ntohs((uint16_t)uh->uh_ulen); -+ -+ /* -+ * Make mbuf data length reflect UDP length. -+ * If not enough data to reflect UDP length, drop. -+ */ -+ if (ntohs(ip->ip_pl) != len) { -+ if (len > ntohs(ip->ip_pl)) { -+ goto bad; -+ } -+ m_adj(m, len - ntohs(ip->ip_pl)); -+ ip->ip_pl = htons(len); -+ } -+ -+ /* -+ * Save a copy of the IP header in case we want restore it -+ * for sending an ICMP error message in response. -+ */ -+ save_ip = *ip; -+ -+ /* Locate pcb for datagram. */ -+ lhost.sin6_family = AF_INET6; -+ lhost.sin6_addr = ip->ip_src; -+ lhost.sin6_port = uh->uh_sport; -+ -+ /* handle DHCPv6 */ -+ if (ntohs(uh->uh_dport) == DHCPV6_SERVER_PORT && -+ (in6_equal(&ip->ip_dst, &slirp->vhost_addr6) || -+ in6_dhcp_multicast(&ip->ip_dst))) { -+ m->m_data += iphlen; -+ m->m_len -= iphlen; -+ dhcpv6_input(&lhost, m); -+ m->m_data -= iphlen; -+ m->m_len += iphlen; -+ goto bad; -+ } -+ -+ /* handle TFTP */ -+ if (ntohs(uh->uh_dport) == TFTP_SERVER && -+ !memcmp(ip->ip_dst.s6_addr, slirp->vhost_addr6.s6_addr, 16)) { -+ m->m_data += iphlen; -+ m->m_len -= iphlen; -+ tftp_input((struct sockaddr_storage *)&lhost, m); -+ m->m_data -= iphlen; -+ m->m_len += iphlen; -+ goto bad; -+ } -+ -+ so = solookup(&slirp->udp_last_so, &slirp->udb, -+ (struct sockaddr_storage *)&lhost, NULL); -+ -+ if (so == NULL) { -+ /* If there's no socket for this packet, create one. */ -+ so = socreate(slirp); -+ if (udp_attach(so, AF_INET6) == -1) { -+ DEBUG_MISC(" udp6_attach errno = %d-%s", errno, strerror(errno)); -+ sofree(so); -+ goto bad; -+ } -+ -+ /* Setup fields */ -+ so->so_lfamily = AF_INET6; -+ so->so_laddr6 = ip->ip_src; -+ so->so_lport6 = uh->uh_sport; -+ } -+ -+ so->so_ffamily = AF_INET6; -+ so->so_faddr6 = ip->ip_dst; /* XXX */ -+ so->so_fport6 = uh->uh_dport; /* XXX */ -+ -+ iphlen += sizeof(struct udphdr); -+ m->m_len -= iphlen; -+ m->m_data += iphlen; -+ -+ /* -+ * Now we sendto() the packet. -+ */ -+ if (sosendto(so, m) == -1) { -+ m->m_len += iphlen; -+ m->m_data -= iphlen; -+ *ip = save_ip; -+ DEBUG_MISC("udp tx errno = %d-%s", errno, strerror(errno)); -+ icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE); -+ goto bad; -+ } -+ -+ m_free(so->so_m); /* used for ICMP if error on sorecvfrom */ -+ -+ /* restore the orig mbuf packet */ -+ m->m_len += iphlen; -+ m->m_data -= iphlen; -+ *ip = save_ip; -+ so->so_m = m; -+ -+ return; -+bad: -+ m_free(m); -+} -+ -+int udp6_output(struct socket *so, struct mbuf *m, struct sockaddr_in6 *saddr, -+ struct sockaddr_in6 *daddr) -+{ -+ struct ip6 *ip; -+ struct udphdr *uh; -+ -+ DEBUG_CALL("udp6_output"); -+ DEBUG_ARG("so = %p", so); -+ DEBUG_ARG("m = %p", m); -+ -+ /* adjust for header */ -+ m->m_data -= sizeof(struct udphdr); -+ m->m_len += sizeof(struct udphdr); -+ uh = mtod(m, struct udphdr *); -+ m->m_data -= sizeof(struct ip6); -+ m->m_len += sizeof(struct ip6); -+ ip = mtod(m, struct ip6 *); -+ -+ /* Build IP header */ -+ ip->ip_pl = htons(m->m_len - sizeof(struct ip6)); -+ ip->ip_nh = IPPROTO_UDP; -+ ip->ip_src = saddr->sin6_addr; -+ ip->ip_dst = daddr->sin6_addr; -+ -+ /* Build UDP header */ -+ uh->uh_sport = saddr->sin6_port; -+ uh->uh_dport = daddr->sin6_port; -+ uh->uh_ulen = ip->ip_pl; -+ uh->uh_sum = 0; -+ uh->uh_sum = ip6_cksum(m); -+ if (uh->uh_sum == 0) { -+ uh->uh_sum = 0xffff; -+ } -+ -+ return ip6_output(so, m, 0); -+} -diff --git a/slirp/src/util.c b/slirp/src/util.c -new file mode 100644 -index 0000000000..d3ed5faf8b ---- /dev/null -+++ b/slirp/src/util.c -@@ -0,0 +1,428 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * util.c (mostly based on QEMU os-win32.c) -+ * -+ * Copyright (c) 2003-2008 Fabrice Bellard -+ * Copyright (c) 2010-2016 Red Hat, Inc. -+ * -+ * QEMU library functions for win32 which are shared between QEMU and -+ * the QEMU tools. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+#include "util.h" -+ -+#include -+#include -+#include -+ -+#if defined(_WIN32) -+int slirp_inet_aton(const char *cp, struct in_addr *ia) -+{ -+ uint32_t addr = inet_addr(cp); -+ if (addr == 0xffffffff) { -+ return 0; -+ } -+ ia->s_addr = addr; -+ return 1; -+} -+#endif -+ -+void slirp_set_nonblock(int fd) -+{ -+#ifndef _WIN32 -+ int f; -+ f = fcntl(fd, F_GETFL); -+ assert(f != -1); -+ f = fcntl(fd, F_SETFL, f | O_NONBLOCK); -+ assert(f != -1); -+#else -+ unsigned long opt = 1; -+ ioctlsocket(fd, FIONBIO, &opt); -+#endif -+} -+ -+static void slirp_set_cloexec(int fd) -+{ -+#ifndef _WIN32 -+ int f; -+ f = fcntl(fd, F_GETFD); -+ assert(f != -1); -+ f = fcntl(fd, F_SETFD, f | FD_CLOEXEC); -+ assert(f != -1); -+#endif -+} -+ -+/* -+ * Opens a socket with FD_CLOEXEC set -+ */ -+int slirp_socket(int domain, int type, int protocol) -+{ -+ int ret; -+ -+#ifdef SOCK_CLOEXEC -+ ret = socket(domain, type | SOCK_CLOEXEC, protocol); -+ if (ret != -1 || errno != EINVAL) { -+ return ret; -+ } -+#endif -+ ret = socket(domain, type, protocol); -+ if (ret >= 0) { -+ slirp_set_cloexec(ret); -+ } -+ -+ return ret; -+} -+ -+#ifdef _WIN32 -+static int socket_error(void) -+{ -+ switch (WSAGetLastError()) { -+ case 0: -+ return 0; -+ case WSAEINTR: -+ return EINTR; -+ case WSAEINVAL: -+ return EINVAL; -+ case WSA_INVALID_HANDLE: -+ return EBADF; -+ case WSA_NOT_ENOUGH_MEMORY: -+ return ENOMEM; -+ case WSA_INVALID_PARAMETER: -+ return EINVAL; -+ case WSAENAMETOOLONG: -+ return ENAMETOOLONG; -+ case WSAENOTEMPTY: -+ return ENOTEMPTY; -+ case WSAEWOULDBLOCK: -+ /* not using EWOULDBLOCK as we don't want code to have -+ * to check both EWOULDBLOCK and EAGAIN */ -+ return EAGAIN; -+ case WSAEINPROGRESS: -+ return EINPROGRESS; -+ case WSAEALREADY: -+ return EALREADY; -+ case WSAENOTSOCK: -+ return ENOTSOCK; -+ case WSAEDESTADDRREQ: -+ return EDESTADDRREQ; -+ case WSAEMSGSIZE: -+ return EMSGSIZE; -+ case WSAEPROTOTYPE: -+ return EPROTOTYPE; -+ case WSAENOPROTOOPT: -+ return ENOPROTOOPT; -+ case WSAEPROTONOSUPPORT: -+ return EPROTONOSUPPORT; -+ case WSAEOPNOTSUPP: -+ return EOPNOTSUPP; -+ case WSAEAFNOSUPPORT: -+ return EAFNOSUPPORT; -+ case WSAEADDRINUSE: -+ return EADDRINUSE; -+ case WSAEADDRNOTAVAIL: -+ return EADDRNOTAVAIL; -+ case WSAENETDOWN: -+ return ENETDOWN; -+ case WSAENETUNREACH: -+ return ENETUNREACH; -+ case WSAENETRESET: -+ return ENETRESET; -+ case WSAECONNABORTED: -+ return ECONNABORTED; -+ case WSAECONNRESET: -+ return ECONNRESET; -+ case WSAENOBUFS: -+ return ENOBUFS; -+ case WSAEISCONN: -+ return EISCONN; -+ case WSAENOTCONN: -+ return ENOTCONN; -+ case WSAETIMEDOUT: -+ return ETIMEDOUT; -+ case WSAECONNREFUSED: -+ return ECONNREFUSED; -+ case WSAELOOP: -+ return ELOOP; -+ case WSAEHOSTUNREACH: -+ return EHOSTUNREACH; -+ default: -+ return EIO; -+ } -+} -+ -+#undef ioctlsocket -+int slirp_ioctlsocket_wrap(int fd, int req, void *val) -+{ -+ int ret; -+ ret = ioctlsocket(fd, req, val); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+ -+#undef closesocket -+int slirp_closesocket_wrap(int fd) -+{ -+ int ret; -+ ret = closesocket(fd); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+ -+#undef connect -+int slirp_connect_wrap(int sockfd, const struct sockaddr *addr, int addrlen) -+{ -+ int ret; -+ ret = connect(sockfd, addr, addrlen); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+ -+#undef listen -+int slirp_listen_wrap(int sockfd, int backlog) -+{ -+ int ret; -+ ret = listen(sockfd, backlog); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+ -+#undef bind -+int slirp_bind_wrap(int sockfd, const struct sockaddr *addr, int addrlen) -+{ -+ int ret; -+ ret = bind(sockfd, addr, addrlen); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+ -+#undef socket -+int slirp_socket_wrap(int domain, int type, int protocol) -+{ -+ int ret; -+ ret = socket(domain, type, protocol); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+ -+#undef accept -+int slirp_accept_wrap(int sockfd, struct sockaddr *addr, int *addrlen) -+{ -+ int ret; -+ ret = accept(sockfd, addr, addrlen); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+ -+#undef shutdown -+int slirp_shutdown_wrap(int sockfd, int how) -+{ -+ int ret; -+ ret = shutdown(sockfd, how); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+ -+#undef getsockopt -+int slirp_getsockopt_wrap(int sockfd, int level, int optname, void *optval, -+ int *optlen) -+{ -+ int ret; -+ ret = getsockopt(sockfd, level, optname, optval, optlen); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+ -+#undef setsockopt -+int slirp_setsockopt_wrap(int sockfd, int level, int optname, -+ const void *optval, int optlen) -+{ -+ int ret; -+ ret = setsockopt(sockfd, level, optname, optval, optlen); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+ -+#undef getpeername -+int slirp_getpeername_wrap(int sockfd, struct sockaddr *addr, int *addrlen) -+{ -+ int ret; -+ ret = getpeername(sockfd, addr, addrlen); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+ -+#undef getsockname -+int slirp_getsockname_wrap(int sockfd, struct sockaddr *addr, int *addrlen) -+{ -+ int ret; -+ ret = getsockname(sockfd, addr, addrlen); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+ -+#undef send -+ssize_t slirp_send_wrap(int sockfd, const void *buf, size_t len, int flags) -+{ -+ int ret; -+ ret = send(sockfd, buf, len, flags); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+ -+#undef sendto -+ssize_t slirp_sendto_wrap(int sockfd, const void *buf, size_t len, int flags, -+ const struct sockaddr *addr, int addrlen) -+{ -+ int ret; -+ ret = sendto(sockfd, buf, len, flags, addr, addrlen); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+ -+#undef recv -+ssize_t slirp_recv_wrap(int sockfd, void *buf, size_t len, int flags) -+{ -+ int ret; -+ ret = recv(sockfd, buf, len, flags); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+ -+#undef recvfrom -+ssize_t slirp_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags, -+ struct sockaddr *addr, int *addrlen) -+{ -+ int ret; -+ ret = recvfrom(sockfd, buf, len, flags, addr, addrlen); -+ if (ret < 0) { -+ errno = socket_error(); -+ } -+ return ret; -+} -+#endif /* WIN32 */ -+ -+void slirp_pstrcpy(char *buf, int buf_size, const char *str) -+{ -+ int c; -+ char *q = buf; -+ -+ if (buf_size <= 0) -+ return; -+ -+ for (;;) { -+ c = *str++; -+ if (c == 0 || q >= buf + buf_size - 1) -+ break; -+ *q++ = c; -+ } -+ *q = '\0'; -+} -+ -+static int slirp_vsnprintf(char *str, size_t size, -+ const char *format, va_list args) -+{ -+ int rv = g_vsnprintf(str, size, format, args); -+ -+ if (rv < 0) { -+ g_error("g_vsnprintf() failed: %s", g_strerror(errno)); -+ } -+ -+ return rv; -+} -+ -+/* -+ * A snprintf()-like function that: -+ * - returns the number of bytes written (excluding optional \0-ending) -+ * - dies on error -+ * - warn on truncation -+ */ -+int slirp_fmt(char *str, size_t size, const char *format, ...) -+{ -+ va_list args; -+ int rv; -+ -+ va_start(args, format); -+ rv = slirp_vsnprintf(str, size, format, args); -+ va_end(args); -+ -+ if (rv >= size) { -+ g_critical("slirp_fmt() truncation"); -+ } -+ -+ return MIN(rv, size); -+} -+ -+/* -+ * A snprintf()-like function that: -+ * - always \0-end (unless size == 0) -+ * - returns the number of bytes actually written, including \0 ending -+ * - dies on error -+ * - warn on truncation -+ */ -+int slirp_fmt0(char *str, size_t size, const char *format, ...) -+{ -+ va_list args; -+ int rv; -+ -+ va_start(args, format); -+ rv = slirp_vsnprintf(str, size, format, args); -+ va_end(args); -+ -+ if (rv >= size) { -+ g_critical("slirp_fmt0() truncation"); -+ if (size > 0) -+ str[size - 1] = '\0'; -+ rv = size; -+ } else { -+ rv += 1; /* include \0 */ -+ } -+ -+ return rv; -+} -diff --git a/slirp/src/util.h b/slirp/src/util.h -new file mode 100644 -index 0000000000..d67b3d0de9 ---- /dev/null -+++ b/slirp/src/util.h -@@ -0,0 +1,189 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * Copyright (c) 2003-2008 Fabrice Bellard -+ * Copyright (c) 2010-2019 Red Hat, Inc. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+#ifndef UTIL_H_ -+#define UTIL_H_ -+ -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef _WIN32 -+#include -+#include -+#else -+#include -+#include -+#include -+#endif -+ -+#if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__)) -+#define SLIRP_PACKED __attribute__((gcc_struct, packed)) -+#else -+#define SLIRP_PACKED __attribute__((packed)) -+#endif -+ -+#ifndef DIV_ROUND_UP -+#define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d)) -+#endif -+ -+#ifndef container_of -+#define container_of(ptr, type, member) \ -+ __extension__({ \ -+ void *__mptr = (void *)(ptr); \ -+ ((type *)(__mptr - offsetof(type, member))); \ -+ }) -+#endif -+ -+#ifndef G_SIZEOF_MEMBER -+#define G_SIZEOF_MEMBER(type, member) sizeof(((type *)0)->member) -+#endif -+ -+#if defined(_WIN32) /* CONFIG_IOVEC */ -+#if !defined(IOV_MAX) /* XXX: to avoid duplicate with QEMU osdep.h */ -+struct iovec { -+ void *iov_base; -+ size_t iov_len; -+}; -+#endif -+#else -+#include -+#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) -+ -+/* FIXME: remove me when made standalone */ -+#ifdef _WIN32 -+#undef accept -+#undef bind -+#undef closesocket -+#undef connect -+#undef getpeername -+#undef getsockname -+#undef getsockopt -+#undef ioctlsocket -+#undef listen -+#undef recv -+#undef recvfrom -+#undef send -+#undef sendto -+#undef setsockopt -+#undef shutdown -+#undef socket -+#endif -+ -+#ifdef _WIN32 -+#define connect slirp_connect_wrap -+int slirp_connect_wrap(int fd, const struct sockaddr *addr, int addrlen); -+#define listen slirp_listen_wrap -+int slirp_listen_wrap(int fd, int backlog); -+#define bind slirp_bind_wrap -+int slirp_bind_wrap(int fd, const struct sockaddr *addr, int addrlen); -+#define socket slirp_socket_wrap -+int slirp_socket_wrap(int domain, int type, int protocol); -+#define accept slirp_accept_wrap -+int slirp_accept_wrap(int fd, struct sockaddr *addr, int *addrlen); -+#define shutdown slirp_shutdown_wrap -+int slirp_shutdown_wrap(int fd, int how); -+#define getpeername slirp_getpeername_wrap -+int slirp_getpeername_wrap(int fd, struct sockaddr *addr, int *addrlen); -+#define getsockname slirp_getsockname_wrap -+int slirp_getsockname_wrap(int fd, struct sockaddr *addr, int *addrlen); -+#define send slirp_send_wrap -+ssize_t slirp_send_wrap(int fd, const void *buf, size_t len, int flags); -+#define sendto slirp_sendto_wrap -+ssize_t slirp_sendto_wrap(int fd, const void *buf, size_t len, int flags, -+ const struct sockaddr *dest_addr, int addrlen); -+#define recv slirp_recv_wrap -+ssize_t slirp_recv_wrap(int fd, void *buf, size_t len, int flags); -+#define recvfrom slirp_recvfrom_wrap -+ssize_t slirp_recvfrom_wrap(int fd, void *buf, size_t len, int flags, -+ struct sockaddr *src_addr, int *addrlen); -+#define closesocket slirp_closesocket_wrap -+int slirp_closesocket_wrap(int fd); -+#define ioctlsocket slirp_ioctlsocket_wrap -+int slirp_ioctlsocket_wrap(int fd, int req, void *val); -+#define getsockopt slirp_getsockopt_wrap -+int slirp_getsockopt_wrap(int sockfd, int level, int optname, void *optval, -+ int *optlen); -+#define setsockopt slirp_setsockopt_wrap -+int slirp_setsockopt_wrap(int sockfd, int level, int optname, -+ const void *optval, int optlen); -+#define inet_aton slirp_inet_aton -+int slirp_inet_aton(const char *cp, struct in_addr *ia); -+#else -+#define closesocket(s) close(s) -+#define ioctlsocket(s, r, v) ioctl(s, r, v) -+#endif -+ -+int slirp_socket(int domain, int type, int protocol); -+void slirp_set_nonblock(int fd); -+ -+static inline int slirp_socket_set_nodelay(int fd) -+{ -+ int v = 1; -+ return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); -+} -+ -+static inline int slirp_socket_set_fast_reuse(int fd) -+{ -+#ifndef _WIN32 -+ int v = 1; -+ return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)); -+#else -+ /* Enabling the reuse of an endpoint that was used by a socket still in -+ * TIME_WAIT state is usually performed by setting SO_REUSEADDR. On Windows -+ * fast reuse is the default and SO_REUSEADDR does strange things. So we -+ * don't have to do anything here. More info can be found at: -+ * http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621.aspx */ -+ return 0; -+#endif -+} -+ -+void slirp_pstrcpy(char *buf, int buf_size, const char *str); -+ -+int slirp_fmt(char *str, size_t size, const char *format, ...) G_GNUC_PRINTF(3, 4); -+int slirp_fmt0(char *str, size_t size, const char *format, ...) G_GNUC_PRINTF(3, 4); -+ -+#endif -diff --git a/slirp/src/version.c b/slirp/src/version.c -new file mode 100644 -index 0000000000..93e0be9c24 ---- /dev/null -+++ b/slirp/src/version.c -@@ -0,0 +1,8 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+#include "libslirp.h" -+ -+const char * -+slirp_version_string(void) -+{ -+ return SLIRP_VERSION_STRING; -+} -diff --git a/slirp/src/vmstate.c b/slirp/src/vmstate.c -new file mode 100644 -index 0000000000..68cc1729c5 ---- /dev/null -+++ b/slirp/src/vmstate.c -@@ -0,0 +1,444 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * VMState interpreter -+ * -+ * Copyright (c) 2009-2018 Red Hat Inc -+ * -+ * Authors: -+ * Juan Quintela -+ * -+ * 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. -+ */ -+#include -+#include -+#include -+#include -+ -+#include "stream.h" -+#include "vmstate.h" -+ -+static int get_nullptr(SlirpIStream *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ if (slirp_istream_read_u8(f) == VMS_NULLPTR_MARKER) { -+ return 0; -+ } -+ g_warning("vmstate: get_nullptr expected VMS_NULLPTR_MARKER"); -+ return -EINVAL; -+} -+ -+static int put_nullptr(SlirpOStream *f, void *pv, size_t size, -+ const VMStateField *field) -+ -+{ -+ if (pv == NULL) { -+ slirp_ostream_write_u8(f, VMS_NULLPTR_MARKER); -+ return 0; -+ } -+ g_warning("vmstate: put_nullptr must be called with pv == NULL"); -+ return -EINVAL; -+} -+ -+const VMStateInfo slirp_vmstate_info_nullptr = { -+ .name = "uint64", -+ .get = get_nullptr, -+ .put = put_nullptr, -+}; -+ -+/* 8 bit unsigned int */ -+ -+static int get_uint8(SlirpIStream *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ uint8_t *v = pv; -+ *v = slirp_istream_read_u8(f); -+ return 0; -+} -+ -+static int put_uint8(SlirpOStream *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ uint8_t *v = pv; -+ slirp_ostream_write_u8(f, *v); -+ return 0; -+} -+ -+const VMStateInfo slirp_vmstate_info_uint8 = { -+ .name = "uint8", -+ .get = get_uint8, -+ .put = put_uint8, -+}; -+ -+/* 16 bit unsigned int */ -+ -+static int get_uint16(SlirpIStream *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ uint16_t *v = pv; -+ *v = slirp_istream_read_u16(f); -+ return 0; -+} -+ -+static int put_uint16(SlirpOStream *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ uint16_t *v = pv; -+ slirp_ostream_write_u16(f, *v); -+ return 0; -+} -+ -+const VMStateInfo slirp_vmstate_info_uint16 = { -+ .name = "uint16", -+ .get = get_uint16, -+ .put = put_uint16, -+}; -+ -+/* 32 bit unsigned int */ -+ -+static int get_uint32(SlirpIStream *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ uint32_t *v = pv; -+ *v = slirp_istream_read_u32(f); -+ return 0; -+} -+ -+static int put_uint32(SlirpOStream *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ uint32_t *v = pv; -+ slirp_ostream_write_u32(f, *v); -+ return 0; -+} -+ -+const VMStateInfo slirp_vmstate_info_uint32 = { -+ .name = "uint32", -+ .get = get_uint32, -+ .put = put_uint32, -+}; -+ -+/* 16 bit int */ -+ -+static int get_int16(SlirpIStream *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ int16_t *v = pv; -+ *v = slirp_istream_read_i16(f); -+ return 0; -+} -+ -+static int put_int16(SlirpOStream *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ int16_t *v = pv; -+ slirp_ostream_write_i16(f, *v); -+ return 0; -+} -+ -+const VMStateInfo slirp_vmstate_info_int16 = { -+ .name = "int16", -+ .get = get_int16, -+ .put = put_int16, -+}; -+ -+/* 32 bit int */ -+ -+static int get_int32(SlirpIStream *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ int32_t *v = pv; -+ *v = slirp_istream_read_i32(f); -+ return 0; -+} -+ -+static int put_int32(SlirpOStream *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ int32_t *v = pv; -+ slirp_ostream_write_i32(f, *v); -+ return 0; -+} -+ -+const VMStateInfo slirp_vmstate_info_int32 = { -+ .name = "int32", -+ .get = get_int32, -+ .put = put_int32, -+}; -+ -+/* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate -+ * a temporary buffer and the pre_load/pre_save methods in the child vmsd -+ * copy stuff from the parent into the child and do calculations to fill -+ * in fields that don't really exist in the parent but need to be in the -+ * stream. -+ */ -+static int get_tmp(SlirpIStream *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ int ret; -+ const VMStateDescription *vmsd = field->vmsd; -+ int version_id = field->version_id; -+ void *tmp = g_malloc(size); -+ -+ /* Writes the parent field which is at the start of the tmp */ -+ *(void **)tmp = pv; -+ ret = slirp_vmstate_load_state(f, vmsd, tmp, version_id); -+ g_free(tmp); -+ return ret; -+} -+ -+static int put_tmp(SlirpOStream *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ const VMStateDescription *vmsd = field->vmsd; -+ void *tmp = g_malloc(size); -+ int ret; -+ -+ /* Writes the parent field which is at the start of the tmp */ -+ *(void **)tmp = pv; -+ ret = slirp_vmstate_save_state(f, vmsd, tmp); -+ g_free(tmp); -+ -+ return ret; -+} -+ -+const VMStateInfo slirp_vmstate_info_tmp = { -+ .name = "tmp", -+ .get = get_tmp, -+ .put = put_tmp, -+}; -+ -+/* uint8_t buffers */ -+ -+static int get_buffer(SlirpIStream *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ slirp_istream_read(f, pv, size); -+ return 0; -+} -+ -+static int put_buffer(SlirpOStream *f, void *pv, size_t size, -+ const VMStateField *field) -+{ -+ slirp_ostream_write(f, pv, size); -+ return 0; -+} -+ -+const VMStateInfo slirp_vmstate_info_buffer = { -+ .name = "buffer", -+ .get = get_buffer, -+ .put = put_buffer, -+}; -+ -+static int vmstate_n_elems(void *opaque, const VMStateField *field) -+{ -+ int n_elems = 1; -+ -+ if (field->flags & VMS_ARRAY) { -+ n_elems = field->num; -+ } else if (field->flags & VMS_VARRAY_INT32) { -+ n_elems = *(int32_t *)(opaque + field->num_offset); -+ } else if (field->flags & VMS_VARRAY_UINT32) { -+ n_elems = *(uint32_t *)(opaque + field->num_offset); -+ } else if (field->flags & VMS_VARRAY_UINT16) { -+ n_elems = *(uint16_t *)(opaque + field->num_offset); -+ } else if (field->flags & VMS_VARRAY_UINT8) { -+ n_elems = *(uint8_t *)(opaque + field->num_offset); -+ } -+ -+ if (field->flags & VMS_MULTIPLY_ELEMENTS) { -+ n_elems *= field->num; -+ } -+ -+ return n_elems; -+} -+ -+static int vmstate_size(void *opaque, const VMStateField *field) -+{ -+ int size = field->size; -+ -+ if (field->flags & VMS_VBUFFER) { -+ size = *(int32_t *)(opaque + field->size_offset); -+ if (field->flags & VMS_MULTIPLY) { -+ size *= field->size; -+ } -+ } -+ -+ return size; -+} -+ -+static int vmstate_save_state_v(SlirpOStream *f, const VMStateDescription *vmsd, -+ void *opaque, int version_id) -+{ -+ int ret = 0; -+ const VMStateField *field = vmsd->fields; -+ -+ if (vmsd->pre_save) { -+ ret = vmsd->pre_save(opaque); -+ if (ret) { -+ g_warning("pre-save failed: %s", vmsd->name); -+ return ret; -+ } -+ } -+ -+ while (field->name) { -+ if ((field->field_exists && field->field_exists(opaque, version_id)) || -+ (!field->field_exists && field->version_id <= version_id)) { -+ void *first_elem = opaque + field->offset; -+ int i, n_elems = vmstate_n_elems(opaque, field); -+ int size = vmstate_size(opaque, field); -+ -+ if (field->flags & VMS_POINTER) { -+ first_elem = *(void **)first_elem; -+ assert(first_elem || !n_elems || !size); -+ } -+ for (i = 0; i < n_elems; i++) { -+ void *curr_elem = first_elem + size * i; -+ -+ if (field->flags & VMS_ARRAY_OF_POINTER) { -+ assert(curr_elem); -+ curr_elem = *(void **)curr_elem; -+ } -+ if (!curr_elem && size) { -+ /* if null pointer write placeholder and do not follow */ -+ assert(field->flags & VMS_ARRAY_OF_POINTER); -+ ret = slirp_vmstate_info_nullptr.put(f, curr_elem, size, -+ NULL); -+ } else if (field->flags & VMS_STRUCT) { -+ ret = slirp_vmstate_save_state(f, field->vmsd, curr_elem); -+ } else if (field->flags & VMS_VSTRUCT) { -+ ret = vmstate_save_state_v(f, field->vmsd, curr_elem, -+ field->struct_version_id); -+ } else { -+ ret = field->info->put(f, curr_elem, size, field); -+ } -+ if (ret) { -+ g_warning("Save of field %s/%s failed", vmsd->name, -+ field->name); -+ return ret; -+ } -+ } -+ } else { -+ if (field->flags & VMS_MUST_EXIST) { -+ g_warning("Output state validation failed: %s/%s", vmsd->name, -+ field->name); -+ assert(!(field->flags & VMS_MUST_EXIST)); -+ } -+ } -+ field++; -+ } -+ -+ return 0; -+} -+ -+int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd, -+ void *opaque) -+{ -+ return vmstate_save_state_v(f, vmsd, opaque, vmsd->version_id); -+} -+ -+static void vmstate_handle_alloc(void *ptr, VMStateField *field, void *opaque) -+{ -+ if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) { -+ size_t size = vmstate_size(opaque, field); -+ size *= vmstate_n_elems(opaque, field); -+ if (size) { -+ *(void **)ptr = g_malloc(size); -+ } -+ } -+} -+ -+int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd, -+ void *opaque, int version_id) -+{ -+ VMStateField *field = vmsd->fields; -+ int ret = 0; -+ -+ if (version_id > vmsd->version_id) { -+ g_warning("%s: incoming version_id %d is too new " -+ "for local version_id %d", -+ vmsd->name, version_id, vmsd->version_id); -+ return -EINVAL; -+ } -+ if (vmsd->pre_load) { -+ int ret = vmsd->pre_load(opaque); -+ if (ret) { -+ return ret; -+ } -+ } -+ while (field->name) { -+ if ((field->field_exists && field->field_exists(opaque, version_id)) || -+ (!field->field_exists && field->version_id <= version_id)) { -+ void *first_elem = opaque + field->offset; -+ int i, n_elems = vmstate_n_elems(opaque, field); -+ int size = vmstate_size(opaque, field); -+ -+ vmstate_handle_alloc(first_elem, field, opaque); -+ if (field->flags & VMS_POINTER) { -+ first_elem = *(void **)first_elem; -+ assert(first_elem || !n_elems || !size); -+ } -+ for (i = 0; i < n_elems; i++) { -+ void *curr_elem = first_elem + size * i; -+ -+ if (field->flags & VMS_ARRAY_OF_POINTER) { -+ curr_elem = *(void **)curr_elem; -+ } -+ if (!curr_elem && size) { -+ /* if null pointer check placeholder and do not follow */ -+ assert(field->flags & VMS_ARRAY_OF_POINTER); -+ ret = slirp_vmstate_info_nullptr.get(f, curr_elem, size, -+ NULL); -+ } else if (field->flags & VMS_STRUCT) { -+ ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem, -+ field->vmsd->version_id); -+ } else if (field->flags & VMS_VSTRUCT) { -+ ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem, -+ field->struct_version_id); -+ } else { -+ ret = field->info->get(f, curr_elem, size, field); -+ } -+ if (ret < 0) { -+ g_warning("Failed to load %s:%s", vmsd->name, field->name); -+ return ret; -+ } -+ } -+ } else if (field->flags & VMS_MUST_EXIST) { -+ g_warning("Input validation failed: %s/%s", vmsd->name, -+ field->name); -+ return -1; -+ } -+ field++; -+ } -+ if (vmsd->post_load) { -+ ret = vmsd->post_load(opaque, version_id); -+ } -+ return ret; -+} -diff --git a/slirp/src/vmstate.h b/slirp/src/vmstate.h -new file mode 100644 -index 0000000000..94c6a4bc7b ---- /dev/null -+++ b/slirp/src/vmstate.h -@@ -0,0 +1,391 @@ -+/* SPDX-License-Identifier: BSD-3-Clause */ -+/* -+ * QEMU migration/snapshot declarations -+ * -+ * Copyright (c) 2009-2011 Red Hat, Inc. -+ * -+ * Original author: Juan Quintela -+ * -+ * 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 VMSTATE_H_ -+#define VMSTATE_H_ -+ -+#include -+#include -+#include -+#include "slirp.h" -+#include "stream.h" -+ -+#define stringify(s) tostring(s) -+#define tostring(s) #s -+ -+typedef struct VMStateInfo VMStateInfo; -+typedef struct VMStateDescription VMStateDescription; -+typedef struct VMStateField VMStateField; -+ -+int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd, -+ void *opaque); -+int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd, -+ void *opaque, int version_id); -+ -+/* VMStateInfo allows customized migration of objects that don't fit in -+ * any category in VMStateFlags. Additional information is always passed -+ * into get and put in terms of field and vmdesc parameters. However -+ * these two parameters should only be used in cases when customized -+ * handling is needed, such as QTAILQ. For primitive data types such as -+ * integer, field and vmdesc parameters should be ignored inside get/put. -+ */ -+struct VMStateInfo { -+ const char *name; -+ int (*get)(SlirpIStream *f, void *pv, size_t size, -+ const VMStateField *field); -+ int (*put)(SlirpOStream *f, void *pv, size_t size, -+ const VMStateField *field); -+}; -+ -+enum VMStateFlags { -+ /* Ignored */ -+ VMS_SINGLE = 0x001, -+ -+ /* The struct member at opaque + VMStateField.offset is a pointer -+ * to the actual field (e.g. struct a { uint8_t *b; -+ * }). Dereference the pointer before using it as basis for -+ * further pointer arithmetic (see e.g. VMS_ARRAY). Does not -+ * affect the meaning of VMStateField.num_offset or -+ * VMStateField.size_offset; see VMS_VARRAY* and VMS_VBUFFER for -+ * those. */ -+ VMS_POINTER = 0x002, -+ -+ /* The field is an array of fixed size. VMStateField.num contains -+ * the number of entries in the array. The size of each entry is -+ * given by VMStateField.size and / or opaque + -+ * VMStateField.size_offset; see VMS_VBUFFER and -+ * VMS_MULTIPLY. Each array entry will be processed individually -+ * (VMStateField.info.get()/put() if VMS_STRUCT is not set, -+ * recursion into VMStateField.vmsd if VMS_STRUCT is set). May not -+ * be combined with VMS_VARRAY*. */ -+ VMS_ARRAY = 0x004, -+ -+ /* The field is itself a struct, containing one or more -+ * fields. Recurse into VMStateField.vmsd. Most useful in -+ * combination with VMS_ARRAY / VMS_VARRAY*, recursing into each -+ * array entry. */ -+ VMS_STRUCT = 0x008, -+ -+ /* The field is an array of variable size. The int32_t at opaque + -+ * VMStateField.num_offset contains the number of entries in the -+ * array. See the VMS_ARRAY description regarding array handling -+ * in general. May not be combined with VMS_ARRAY or any other -+ * VMS_VARRAY*. */ -+ VMS_VARRAY_INT32 = 0x010, -+ -+ /* Ignored */ -+ VMS_BUFFER = 0x020, -+ -+ /* The field is a (fixed-size or variable-size) array of pointers -+ * (e.g. struct a { uint8_t *b[]; }). Dereference each array entry -+ * before using it. Note: Does not imply any one of VMS_ARRAY / -+ * VMS_VARRAY*; these need to be set explicitly. */ -+ VMS_ARRAY_OF_POINTER = 0x040, -+ -+ /* The field is an array of variable size. The uint16_t at opaque -+ * + VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS) -+ * contains the number of entries in the array. See the VMS_ARRAY -+ * description regarding array handling in general. May not be -+ * combined with VMS_ARRAY or any other VMS_VARRAY*. */ -+ VMS_VARRAY_UINT16 = 0x080, -+ -+ /* The size of the individual entries (a single array entry if -+ * VMS_ARRAY or any of VMS_VARRAY* are set, or the field itself if -+ * neither is set) is variable (i.e. not known at compile-time), -+ * but the same for all entries. Use the int32_t at opaque + -+ * VMStateField.size_offset (subject to VMS_MULTIPLY) to determine -+ * the size of each (and every) entry. */ -+ VMS_VBUFFER = 0x100, -+ -+ /* Multiply the entry size given by the int32_t at opaque + -+ * VMStateField.size_offset (see VMS_VBUFFER description) with -+ * VMStateField.size to determine the number of bytes to be -+ * allocated. Only valid in combination with VMS_VBUFFER. */ -+ VMS_MULTIPLY = 0x200, -+ -+ /* The field is an array of variable size. The uint8_t at opaque + -+ * VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS) -+ * contains the number of entries in the array. See the VMS_ARRAY -+ * description regarding array handling in general. May not be -+ * combined with VMS_ARRAY or any other VMS_VARRAY*. */ -+ VMS_VARRAY_UINT8 = 0x400, -+ -+ /* The field is an array of variable size. The uint32_t at opaque -+ * + VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS) -+ * contains the number of entries in the array. See the VMS_ARRAY -+ * description regarding array handling in general. May not be -+ * combined with VMS_ARRAY or any other VMS_VARRAY*. */ -+ VMS_VARRAY_UINT32 = 0x800, -+ -+ /* Fail loading the serialised VM state if this field is missing -+ * from the input. */ -+ VMS_MUST_EXIST = 0x1000, -+ -+ /* When loading serialised VM state, allocate memory for the -+ * (entire) field. Only valid in combination with -+ * VMS_POINTER. Note: Not all combinations with other flags are -+ * currently supported, e.g. VMS_ALLOC|VMS_ARRAY_OF_POINTER won't -+ * cause the individual entries to be allocated. */ -+ VMS_ALLOC = 0x2000, -+ -+ /* Multiply the number of entries given by the integer at opaque + -+ * VMStateField.num_offset (see VMS_VARRAY*) with VMStateField.num -+ * to determine the number of entries in the array. Only valid in -+ * combination with one of VMS_VARRAY*. */ -+ VMS_MULTIPLY_ELEMENTS = 0x4000, -+ -+ /* A structure field that is like VMS_STRUCT, but uses -+ * VMStateField.struct_version_id to tell which version of the -+ * structure we are referencing to use. */ -+ VMS_VSTRUCT = 0x8000, -+}; -+ -+struct VMStateField { -+ const char *name; -+ size_t offset; -+ size_t size; -+ size_t start; -+ int num; -+ size_t num_offset; -+ size_t size_offset; -+ const VMStateInfo *info; -+ enum VMStateFlags flags; -+ const VMStateDescription *vmsd; -+ int version_id; -+ int struct_version_id; -+ bool (*field_exists)(void *opaque, int version_id); -+}; -+ -+struct VMStateDescription { -+ const char *name; -+ int version_id; -+ int (*pre_load)(void *opaque); -+ int (*post_load)(void *opaque, int version_id); -+ int (*pre_save)(void *opaque); -+ VMStateField *fields; -+}; -+ -+ -+extern const VMStateInfo slirp_vmstate_info_int16; -+extern const VMStateInfo slirp_vmstate_info_int32; -+extern const VMStateInfo slirp_vmstate_info_uint8; -+extern const VMStateInfo slirp_vmstate_info_uint16; -+extern const VMStateInfo slirp_vmstate_info_uint32; -+ -+/** Put this in the stream when migrating a null pointer.*/ -+#define VMS_NULLPTR_MARKER (0x30U) /* '0' */ -+extern const VMStateInfo slirp_vmstate_info_nullptr; -+ -+extern const VMStateInfo slirp_vmstate_info_buffer; -+extern const VMStateInfo slirp_vmstate_info_tmp; -+ -+#define type_check_array(t1, t2, n) ((t1(*)[n])0 - (t2 *)0) -+#define type_check_pointer(t1, t2) ((t1 **)0 - (t2 *)0) -+#define typeof_field(type, field) typeof(((type *)0)->field) -+#define type_check(t1, t2) ((t1 *)0 - (t2 *)0) -+ -+#define vmstate_offset_value(_state, _field, _type) \ -+ (offsetof(_state, _field) + type_check(_type, typeof_field(_state, _field))) -+ -+#define vmstate_offset_pointer(_state, _field, _type) \ -+ (offsetof(_state, _field) + \ -+ type_check_pointer(_type, typeof_field(_state, _field))) -+ -+#define vmstate_offset_array(_state, _field, _type, _num) \ -+ (offsetof(_state, _field) + \ -+ type_check_array(_type, typeof_field(_state, _field), _num)) -+ -+#define vmstate_offset_buffer(_state, _field) \ -+ vmstate_offset_array(_state, _field, uint8_t, \ -+ sizeof(typeof_field(_state, _field))) -+ -+/* In the macros below, if there is a _version, that means the macro's -+ * field will be processed only if the version being received is >= -+ * the _version specified. In general, if you add a new field, you -+ * would increment the structure's version and put that version -+ * number into the new field so it would only be processed with the -+ * new version. -+ * -+ * In particular, for VMSTATE_STRUCT() and friends the _version does -+ * *NOT* pick the version of the sub-structure. It works just as -+ * specified above. The version of the top-level structure received -+ * is passed down to all sub-structures. This means that the -+ * sub-structures must have version that are compatible with all the -+ * structures that use them. -+ * -+ * If you want to specify the version of the sub-structure, use -+ * VMSTATE_VSTRUCT(), which allows the specific sub-structure version -+ * to be directly specified. -+ */ -+ -+#define VMSTATE_SINGLE_TEST(_field, _state, _test, _version, _info, _type) \ -+ { \ -+ .name = (stringify(_field)), .version_id = (_version), \ -+ .field_exists = (_test), .size = sizeof(_type), .info = &(_info), \ -+ .flags = VMS_SINGLE, \ -+ .offset = vmstate_offset_value(_state, _field, _type), \ -+ } -+ -+#define VMSTATE_ARRAY(_field, _state, _num, _version, _info, _type) \ -+ { \ -+ .name = (stringify(_field)), .version_id = (_version), .num = (_num), \ -+ .info = &(_info), .size = sizeof(_type), .flags = VMS_ARRAY, \ -+ .offset = vmstate_offset_array(_state, _field, _type, _num), \ -+ } -+ -+#define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) \ -+ { \ -+ .name = (stringify(_field)), .version_id = (_version), \ -+ .field_exists = (_test), .vmsd = &(_vmsd), .size = sizeof(_type), \ -+ .flags = VMS_STRUCT, \ -+ .offset = vmstate_offset_value(_state, _field, _type), \ -+ } -+ -+#define VMSTATE_STRUCT_POINTER_V(_field, _state, _version, _vmsd, _type) \ -+ { \ -+ .name = (stringify(_field)), .version_id = (_version), \ -+ .vmsd = &(_vmsd), .size = sizeof(_type *), \ -+ .flags = VMS_STRUCT | VMS_POINTER, \ -+ .offset = vmstate_offset_pointer(_state, _field, _type), \ -+ } -+ -+#define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, \ -+ _vmsd, _type) \ -+ { \ -+ .name = (stringify(_field)), .num = (_num), .field_exists = (_test), \ -+ .version_id = (_version), .vmsd = &(_vmsd), .size = sizeof(_type), \ -+ .flags = VMS_STRUCT | VMS_ARRAY, \ -+ .offset = vmstate_offset_array(_state, _field, _type, _num), \ -+ } -+ -+#define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) \ -+ { \ -+ .name = (stringify(_field)), .version_id = (_version), \ -+ .field_exists = (_test), .size = (_size - _start), \ -+ .info = &slirp_vmstate_info_buffer, .flags = VMS_BUFFER, \ -+ .offset = vmstate_offset_buffer(_state, _field) + _start, \ -+ } -+ -+#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _field_size) \ -+ { \ -+ .name = (stringify(_field)), .version_id = (_version), \ -+ .field_exists = (_test), \ -+ .size_offset = vmstate_offset_value(_state, _field_size, uint32_t), \ -+ .info = &slirp_vmstate_info_buffer, \ -+ .flags = VMS_VBUFFER | VMS_POINTER, \ -+ .offset = offsetof(_state, _field), \ -+ } -+ -+#define QEMU_BUILD_BUG_ON_STRUCT(x) \ -+ struct { \ -+ int : (x) ? -1 : 1; \ -+ } -+ -+#define QEMU_BUILD_BUG_ON_ZERO(x) \ -+ (sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)) - sizeof(QEMU_BUILD_BUG_ON_STRUCT(x))) -+ -+/* Allocate a temporary of type 'tmp_type', set tmp->parent to _state -+ * and execute the vmsd on the temporary. Note that we're working with -+ * the whole of _state here, not a field within it. -+ * We compile time check that: -+ * That _tmp_type contains a 'parent' member that's a pointer to the -+ * '_state' type -+ * That the pointer is right at the start of _tmp_type. -+ */ -+#define VMSTATE_WITH_TMP(_state, _tmp_type, _vmsd) \ -+ { \ -+ .name = "tmp", \ -+ .size = sizeof(_tmp_type) + \ -+ QEMU_BUILD_BUG_ON_ZERO(offsetof(_tmp_type, parent) != 0) + \ -+ type_check_pointer(_state, typeof_field(_tmp_type, parent)), \ -+ .vmsd = &(_vmsd), .info = &slirp_vmstate_info_tmp, \ -+ } -+ -+#define VMSTATE_SINGLE(_field, _state, _version, _info, _type) \ -+ VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type) -+ -+#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type) \ -+ VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type) -+ -+#define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type) \ -+ VMSTATE_STRUCT_POINTER_V(_field, _state, 0, _vmsd, _type) -+ -+#define VMSTATE_STRUCT_ARRAY(_field, _state, _num, _version, _vmsd, _type) \ -+ VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version, _vmsd, \ -+ _type) -+ -+#define VMSTATE_INT16_V(_f, _s, _v) \ -+ VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_int16, int16_t) -+#define VMSTATE_INT32_V(_f, _s, _v) \ -+ VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_int32, int32_t) -+ -+#define VMSTATE_UINT8_V(_f, _s, _v) \ -+ VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint8, uint8_t) -+#define VMSTATE_UINT16_V(_f, _s, _v) \ -+ VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint16, uint16_t) -+#define VMSTATE_UINT32_V(_f, _s, _v) \ -+ VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint32, uint32_t) -+ -+#define VMSTATE_INT16(_f, _s) VMSTATE_INT16_V(_f, _s, 0) -+#define VMSTATE_INT32(_f, _s) VMSTATE_INT32_V(_f, _s, 0) -+ -+#define VMSTATE_UINT8(_f, _s) VMSTATE_UINT8_V(_f, _s, 0) -+#define VMSTATE_UINT16(_f, _s) VMSTATE_UINT16_V(_f, _s, 0) -+#define VMSTATE_UINT32(_f, _s) VMSTATE_UINT32_V(_f, _s, 0) -+ -+#define VMSTATE_UINT16_TEST(_f, _s, _t) \ -+ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, slirp_vmstate_info_uint16, uint16_t) -+ -+#define VMSTATE_UINT32_TEST(_f, _s, _t) \ -+ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, slirp_vmstate_info_uint32, uint32_t) -+ -+#define VMSTATE_INT16_ARRAY_V(_f, _s, _n, _v) \ -+ VMSTATE_ARRAY(_f, _s, _n, _v, slirp_vmstate_info_int16, int16_t) -+ -+#define VMSTATE_INT16_ARRAY(_f, _s, _n) VMSTATE_INT16_ARRAY_V(_f, _s, _n, 0) -+ -+#define VMSTATE_BUFFER_V(_f, _s, _v) \ -+ VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, 0, sizeof(typeof_field(_s, _f))) -+ -+#define VMSTATE_BUFFER(_f, _s) VMSTATE_BUFFER_V(_f, _s, 0) -+ -+#define VMSTATE_END_OF_LIST() \ -+ { \ -+ } -+ -+#endif --- -2.18.4 - diff --git a/0004-Initial-redhat-build.patch b/0004-Initial-redhat-build.patch new file mode 100644 index 0000000..a697dd3 --- /dev/null +++ b/0004-Initial-redhat-build.patch @@ -0,0 +1,230 @@ +From 431955e872aa010376b1f94665908c2ba8194b44 Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Fri, 12 Oct 2018 07:31:11 +0200 +Subject: Initial redhat build + +This patch introduces redhat build structure in redhat subdirectory. In addition, +several issues are fixed in QEMU tree: + + - Change of app name for sasl_server_init in VNC code from qemu to qemu-kvm + - As we use qemu-kvm as name in all places, this is updated to be consistent + - Man page renamed from qemu to qemu-kvm + - man page is installed using make install so we have to fix it in qemu tree + +We disable make check due to issues with some of the tests. + +This rebase is based on qemu-kvm-5.2.0-16.el9 + +Signed-off-by: Miroslav Rezanina + +Merged patches (6.0.0): +- 605758c902 Limit build on Power to qemu-img and qemu-ga only +--- + .gitignore | 1 + + README.systemtap | 43 + + configure | 5 - + hw/remote/memory.c | 2 +- + hw/remote/proxy.c | 2 +- + meson.build | 8 +- + redhat/Makefile | 90 + + redhat/Makefile.common | 50 + + redhat/README.tests | 39 + + redhat/qemu-kvm.spec.template | 3609 +++++++++++++++++++++++ + redhat/scripts/extract_build_cmd.py | 5 +- + redhat/scripts/process-patches.sh | 20 +- + redhat/udev-kvm-check.c | 19 +- + scripts/qemu-guest-agent/fsfreeze-hook | 2 +- + scripts/systemtap/conf.d/qemu_kvm.conf | 4 + + scripts/systemtap/script.d/qemu_kvm.stp | 1 + + tests/check-block.sh | 2 + + ui/vnc.c | 2 +- + 18 files changed, 3860 insertions(+), 44 deletions(-) + create mode 100644 README.systemtap + create mode 100644 redhat/Makefile + create mode 100644 redhat/Makefile.common + create mode 100644 redhat/README.tests + create mode 100644 redhat/qemu-kvm.spec.template + create mode 100644 scripts/systemtap/conf.d/qemu_kvm.conf + create mode 100644 scripts/systemtap/script.d/qemu_kvm.stp + +diff --git a/README.systemtap b/README.systemtap +new file mode 100644 +index 0000000000..ad913fc990 +--- /dev/null ++++ b/README.systemtap +@@ -0,0 +1,43 @@ ++QEMU tracing using systemtap-initscript ++--------------------------------------- ++ ++You can capture QEMU trace data all the time using systemtap-initscript. This ++uses SystemTap's flight recorder mode to trace all running guests to a ++fixed-size buffer on the host. Old trace entries are overwritten by new ++entries when the buffer size wraps. ++ ++1. Install the systemtap-initscript package: ++ # yum install systemtap-initscript ++ ++2. Install the systemtap scripts and the conf file: ++ # cp /usr/share/qemu-kvm/systemtap/script.d/qemu_kvm.stp /etc/systemtap/script.d/ ++ # cp /usr/share/qemu-kvm/systemtap/conf.d/qemu_kvm.conf /etc/systemtap/conf.d/ ++ ++The set of trace events to enable is given in qemu_kvm.stp. This SystemTap ++script can be customized to add or remove trace events provided in ++/usr/share/systemtap/tapset/qemu-kvm-simpletrace.stp. ++ ++SystemTap customizations can be made to qemu_kvm.conf to control the flight ++recorder buffer size and whether to store traces in memory only or disk too. ++See stap(1) for option documentation. ++ ++3. Start the systemtap service. ++ # service systemtap start qemu_kvm ++ ++4. Make the service start at boot time. ++ # chkconfig systemtap on ++ ++5. Confirm that the service works. ++ # service systemtap status qemu_kvm ++ qemu_kvm is running... ++ ++When you want to inspect the trace buffer, perform the following steps: ++ ++1. Dump the trace buffer. ++ # staprun -A qemu_kvm >/tmp/trace.log ++ ++2. Start the systemtap service because the preceding step stops the service. ++ # service systemtap start qemu_kvm ++ ++3. Translate the trace record to readable format. ++ # /usr/share/qemu-kvm/simpletrace.py --no-header /usr/share/qemu-kvm/trace-events /tmp/trace.log +diff --git a/configure b/configure +index 4f374b4889..53b2fa583a 100755 +--- a/configure ++++ b/configure +@@ -6383,10 +6383,6 @@ fi + mv $cross config-meson.cross + + rm -rf meson-private meson-info meson-logs +-unset staticpic +-if ! version_ge "$($meson --version)" 0.56.0; then +- staticpic=$(if test "$pie" = yes; then echo true; else echo false; fi) +-fi + NINJA=$ninja $meson setup \ + --prefix "$prefix" \ + --libdir "$libdir" \ +@@ -6406,7 +6402,6 @@ NINJA=$ninja $meson setup \ + -Dwerror=$(if test "$werror" = yes; then echo true; else echo false; fi) \ + -Dstrip=$(if test "$strip_opt" = yes; then echo true; else echo false; fi) \ + -Db_pie=$(if test "$pie" = yes; then echo true; else echo false; fi) \ +- ${staticpic:+-Db_staticpic=$staticpic} \ + -Db_coverage=$(if test "$gcov" = yes; then echo true; else echo false; fi) \ + -Db_lto=$lto -Dcfi=$cfi -Dcfi_debug=$cfi_debug \ + -Dmalloc=$malloc -Dmalloc_trim=$malloc_trim -Dsparse=$sparse \ +diff --git a/hw/remote/memory.c b/hw/remote/memory.c +index 32085b1e05..bf0047a81b 100644 +--- a/hw/remote/memory.c ++++ b/hw/remote/memory.c +@@ -43,7 +43,7 @@ void remote_sysmem_reconfig(MPQemuMsg *msg, Error **errp) + remote_sysmem_reset(); + + for (region = 0; region < msg->num_fds; region++) { +- g_autofree char *name; ++ g_autofree char *name = NULL; + subregion = g_new(MemoryRegion, 1); + name = g_strdup_printf("remote-mem-%u", suffix++); + memory_region_init_ram_from_fd(subregion, NULL, +diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c +index 4fa4be079d..253c1aa7ec 100644 +--- a/hw/remote/proxy.c ++++ b/hw/remote/proxy.c +@@ -347,7 +347,7 @@ static void probe_pci_info(PCIDevice *dev, Error **errp) + PCI_BASE_ADDRESS_SPACE_IO : PCI_BASE_ADDRESS_SPACE_MEMORY; + + if (size) { +- g_autofree char *name; ++ g_autofree char *name = NULL; + pdev->region[i].dev = pdev; + pdev->region[i].present = true; + if (type == PCI_BASE_ADDRESS_SPACE_MEMORY) { +diff --git a/meson.build b/meson.build +index c6f4b0cf5e..06c15bd6d2 100644 +--- a/meson.build ++++ b/meson.build +@@ -1,6 +1,6 @@ + project('qemu', ['c'], meson_version: '>=0.55.0', +- default_options: ['warning_level=1', 'c_std=gnu99', 'cpp_std=gnu++11', 'b_colorout=auto'] + +- (meson.version().version_compare('>=0.56.0') ? [ 'b_staticpic=false' ] : []), ++ default_options: ['warning_level=1', 'c_std=gnu99', 'cpp_std=gnu++11', 'b_colorout=auto', ++ 'b_staticpic=false' ], + version: run_command('head', meson.source_root() / 'VERSION').stdout().strip()) + + not_found = dependency('', required: false) +@@ -1482,7 +1482,9 @@ if capstone_opt == 'internal' + # Include all configuration defines via a header file, which will wind up + # as a dependency on the object file, and thus changes here will result + # in a rebuild. +- '-include', 'capstone-defs.h' ++ '-include', 'capstone-defs.h', ++ ++ '-Wp,-D_GLIBCXX_ASSERTIONS', + ] + + libcapstone = static_library('capstone', +diff --git a/scripts/qemu-guest-agent/fsfreeze-hook b/scripts/qemu-guest-agent/fsfreeze-hook +index 13aafd4845..e9b84ec028 100755 +--- a/scripts/qemu-guest-agent/fsfreeze-hook ++++ b/scripts/qemu-guest-agent/fsfreeze-hook +@@ -8,7 +8,7 @@ + # request, it is issued with "thaw" argument after filesystem is thawed. + + LOGFILE=/var/log/qga-fsfreeze-hook.log +-FSFREEZE_D=$(dirname -- "$0")/fsfreeze-hook.d ++FSFREEZE_D=$(dirname -- "$(realpath $0)")/fsfreeze-hook.d + + # Check whether file $1 is a backup or rpm-generated file and should be ignored + is_ignored_file() { +diff --git a/scripts/systemtap/conf.d/qemu_kvm.conf b/scripts/systemtap/conf.d/qemu_kvm.conf +new file mode 100644 +index 0000000000..372d8160a4 +--- /dev/null ++++ b/scripts/systemtap/conf.d/qemu_kvm.conf +@@ -0,0 +1,4 @@ ++# Force load uprobes (see BZ#1118352) ++stap -e 'probe process("/usr/libexec/qemu-kvm").function("main") { printf("") }' -c true ++ ++qemu_kvm_OPT="-s4" # per-CPU buffer size, in megabytes +diff --git a/scripts/systemtap/script.d/qemu_kvm.stp b/scripts/systemtap/script.d/qemu_kvm.stp +new file mode 100644 +index 0000000000..c04abf9449 +--- /dev/null ++++ b/scripts/systemtap/script.d/qemu_kvm.stp +@@ -0,0 +1 @@ ++probe qemu.kvm.simpletrace.handle_qmp_command,qemu.kvm.simpletrace.monitor_protocol_*,qemu.kvm.simpletrace.migrate_set_state {} +diff --git a/tests/check-block.sh b/tests/check-block.sh +index f86cb863de..6d38340d49 100755 +--- a/tests/check-block.sh ++++ b/tests/check-block.sh +@@ -69,6 +69,8 @@ else + fi + fi + ++exit 0 ++ + cd tests/qemu-iotests + + # QEMU_CHECK_BLOCK_AUTO is used to disable some unstable sub-tests +diff --git a/ui/vnc.c b/ui/vnc.c +index 456db47d71..97ae92b181 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -4146,7 +4146,7 @@ void vnc_display_open(const char *id, Error **errp) + + #ifdef CONFIG_VNC_SASL + if (sasl) { +- int saslErr = sasl_server_init(NULL, "qemu"); ++ int saslErr = sasl_server_init(NULL, "qemu-kvm"); + + if (saslErr != SASL_OK) { + error_setg(errp, "Failed to initialize SASL auth: %s", +-- +2.27.0 + diff --git a/0006-Enable-disable-devices-for-RHEL.patch b/0005-Enable-disable-devices-for-RHEL.patch similarity index 73% rename from 0006-Enable-disable-devices-for-RHEL.patch rename to 0005-Enable-disable-devices-for-RHEL.patch index 0827288..d80a533 100644 --- a/0006-Enable-disable-devices-for-RHEL.patch +++ b/0005-Enable-disable-devices-for-RHEL.patch @@ -1,4 +1,4 @@ -From 0ad3e82af785512a5a77373d2ad95c63dfedeaba Mon Sep 17 00:00:00 2001 +From f46ca4c7e719e0a70f8e0ffe3de882c017c216e7 Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Wed, 2 Sep 2020 09:11:07 +0200 Subject: Enable/disable devices for RHEL @@ -6,125 +6,49 @@ Subject: Enable/disable devices for RHEL This commit adds all changes related to changes in supported devices. Signed-off-by: Miroslav Rezanina - -Rebase notes (qemu 3.1.0) -- spapr_rng disabled in default_config -- new hyperv.mak in default configs -- Move changes from x86_64-softmmu.mak to i386-softmmu.mak -- Added CONFIG_VIRTIO_MMIO to aarch64-softmmu.mak -- Removed config_vga_isa.c changes as no longer needed -- Removed new devices - -Rebase notes (4.0.0): -- Added CONFIG_PCI_EXPRESS_GENERIC_BRIDGE for aarch64-softmmu.mak -- Added CONFIG_ARM_VIRT for aarch64-softmmu.mak -- Switch to KConfig (upstream) - - Using device whitelist + without-defualt-devices option - -Rebase notes (4.1.0): -- Added CONFIG_USB_OHCI_PCI for ppc64 -- Added CONFIG_XIVE_KVM for ppc64 -- Added CONFIG_ACPI_PCI for x86_64 -- Added CONFIG_SEMIHOSTING for aarch64 -- Cleanup aarch64 devices -- Do not build a15mpcore.c -- Removed ide-isa.c stub file -- Use CONFIG_USB_EHCI_PCI on x86_64 (new upstream) - -Rebase notes (4.2.0-rc0): -- Use conditional build for isa-superio.c (upstream change) -- Rename PCI_PIIX to PCI_I440FX (upstream change) - -Rebase notes (4.2.0-rc3): -- Disabled ccid-card-emulated (patch 92566) -- Disabled vfio-pci-igd-lpc-bridge (patch 92565) - -Rebase notes (5.1.0): -- added CONFIG_PCI_EXPRESS on ppc64 (due to upstream dependency) -- Added CONFIG_NVDIMM -- updated cortex-15 disabling to upstream code -- Add CONFIG_ACPI_APEI for aarch64 -- removed obsolete hw/bt/Makefile.objs chunk -- removed unnecessary changes in target/i386/cpu.c - -Rebase notes (5.2.0 rc0): -- Added CONFIG_USB_XHCI_PCI on aarch64 ppc64 and x86_64 -- remove vl.c hack for no hpet -- Enable CONFIG_PTIMER for aarch64 -- Do not package hw-display-virtio-gpu.so on s390x - -Rebase notes (5.2.0 rc1): -- Added CONFIG_ARM_GIC for aarch64 (required for build) - -Merged patches (qemu 3.1.0): -- d51e082 Re-enable CONFIG_HYPERV_TESTDEV -- 4b889f3 Declare cirrus-vga as deprecated -- b579d32 Do not build bluetooth support -- 3eef52a Disable CONFIG_IPMI and CONFIG_I2C for ppc64 -- 9caf292 Disable CONFIG_CAN_BUS and CONFIG_CAN_SJA1000 - -Merged patches (4.1.0): -- 20a51f6 fdc: Revert downstream disablement of device "floppy" -- f869cc0 fdc: Restrict floppy controllers to RHEL-7 machine types -- 5909721 aarch64: Compile out IOH3420 -- 27b7c44 rh: set CONFIG_BOCHS_DISPLAY=y for x86 (partial) -- 495a27d x86_64-rh-devices: add missing TPM passthrough -- e1fe9fe x86_64-rh-devices: enable TPM emulation (partial) - -Merged patches (4.2.0): -- f7587dd RHEL: disable hostmem-memfd - -Merged patches (5.1.0): -- 4543a3c i386: Remove cpu64-rhel6 CPU model -- 96533 aarch64: Remove tcg cpu types (pjw commit) -- 559d589 Revert "RHEL: disable hostmem-memfd" -- 441128e enable ramfb - -Merged patches (5.2.0 rc0): -- f70eb50 RHEL-only: Enable vTPM for POWER in downstream configs -- 69d8ae7 redhat: fix 5.0 rebase missing ISA TPM TIS -- 8310f89 RHEL-only: Enable vTPM for ARM in downstream configs -- 4a8ccfd Disable TPM passthrough backend on ARM --- - .../devices/aarch64-rh-devices.mak | 27 +++++ + .../devices/aarch64-rh-devices.mak | 28 +++++ default-configs/devices/aarch64-softmmu.mak | 10 +- - default-configs/devices/ppc64-rh-devices.mak | 38 +++++++ + default-configs/devices/ppc64-rh-devices.mak | 36 ++++++ default-configs/devices/ppc64-softmmu.mak | 10 +- default-configs/devices/rh-virtio.mak | 10 ++ - default-configs/devices/s390x-rh-devices.mak | 15 +++ + default-configs/devices/s390x-rh-devices.mak | 16 +++ default-configs/devices/s390x-softmmu.mak | 4 +- - default-configs/devices/x86_64-rh-devices.mak | 101 ++++++++++++++++++ - default-configs/devices/x86_64-softmmu.mak | 4 +- + default-configs/devices/x86_64-rh-devices.mak | 104 ++++++++++++++++++ + default-configs/devices/x86_64-softmmu.mak | 10 +- + .../devices/x86_64-upstream-devices.mak | 4 + hw/acpi/ich9.c | 4 +- hw/arm/meson.build | 2 +- hw/block/fdc.c | 10 ++ + hw/char/parallel.c | 9 ++ hw/cpu/meson.build | 5 +- hw/display/cirrus_vga.c | 3 + hw/ide/piix.c | 5 +- hw/input/pckbd.c | 2 + hw/net/e1000.c | 2 + hw/ppc/spapr_cpu_core.c | 2 + + hw/timer/hpet.c | 8 ++ hw/usb/meson.build | 2 +- qemu-options.hx | 4 - - redhat/qemu-kvm.spec.template | 10 +- - target/arm/cpu.c | 4 +- - target/arm/cpu_tcg.c | 3 + + redhat/qemu-kvm.spec.template | 5 +- + target/arm/cpu_tcg.c | 10 ++ target/ppc/cpu-models.c | 10 ++ target/s390x/cpu_models.c | 3 + target/s390x/kvm.c | 8 ++ - 26 files changed, 273 insertions(+), 25 deletions(-) + 28 files changed, 304 insertions(+), 22 deletions(-) create mode 100644 default-configs/devices/aarch64-rh-devices.mak create mode 100644 default-configs/devices/ppc64-rh-devices.mak create mode 100644 default-configs/devices/rh-virtio.mak create mode 100644 default-configs/devices/s390x-rh-devices.mak create mode 100644 default-configs/devices/x86_64-rh-devices.mak + create mode 100644 default-configs/devices/x86_64-upstream-devices.mak diff --git a/default-configs/devices/aarch64-rh-devices.mak b/default-configs/devices/aarch64-rh-devices.mak new file mode 100644 -index 0000000000..98319407de +index 0000000000..a4d67274c0 --- /dev/null +++ b/default-configs/devices/aarch64-rh-devices.mak -@@ -0,0 +1,27 @@ +@@ -0,0 +1,28 @@ +include rh-virtio.mak + +CONFIG_ARM_GIC_KVM=y @@ -152,6 +76,7 @@ index 0000000000..98319407de +CONFIG_TPM_EMULATOR=y +CONFIG_TPM_TIS_SYSBUS=y +CONFIG_PTIMER=y ++CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/default-configs/devices/aarch64-softmmu.mak b/default-configs/devices/aarch64-softmmu.mak index 958b1e08e4..8f6867d48a 100644 --- a/default-configs/devices/aarch64-softmmu.mak @@ -173,10 +98,10 @@ index 958b1e08e4..8f6867d48a 100644 +include aarch64-rh-devices.mak diff --git a/default-configs/devices/ppc64-rh-devices.mak b/default-configs/devices/ppc64-rh-devices.mak new file mode 100644 -index 0000000000..467a16bdc2 +index 0000000000..5b01b7fac0 --- /dev/null +++ b/default-configs/devices/ppc64-rh-devices.mak -@@ -0,0 +1,38 @@ +@@ -0,0 +1,36 @@ +include rh-virtio.mak + +CONFIG_DIMM=y @@ -195,6 +120,8 @@ index 0000000000..467a16bdc2 +CONFIG_USB_OHCI_PCI=y +CONFIG_USB_SMARTCARD=y +CONFIG_USB_STORAGE_BOT=y ++CONFIG_USB_STORAGE_CORE=y ++CONFIG_USB_STORAGE_CLASSIC=y +CONFIG_USB_XHCI=y +CONFIG_USB_XHCI_NEC=y +CONFIG_USB_XHCI_PCI=y @@ -207,11 +134,7 @@ index 0000000000..467a16bdc2 +CONFIG_VIRTIO_VGA=y +CONFIG_WDT_IB6300ESB=y +CONFIG_XICS=y -+CONFIG_XICS_KVM=y -+CONFIG_XICS_SPAPR=y +CONFIG_XIVE=y -+CONFIG_XIVE_SPAPR=y -+CONFIG_XIVE_KVM=y +CONFIG_TPM_SPAPR=y +CONFIG_TPM_EMULATOR=y +CONFIG_TPM_PASSTHROUGH=y @@ -255,10 +178,10 @@ index 0000000000..94ede1b5f6 +CONFIG_VIRTIO_SERIAL=y diff --git a/default-configs/devices/s390x-rh-devices.mak b/default-configs/devices/s390x-rh-devices.mak new file mode 100644 -index 0000000000..c3c73fe752 +index 0000000000..08a15f3e01 --- /dev/null +++ b/default-configs/devices/s390x-rh-devices.mak -@@ -0,0 +1,15 @@ +@@ -0,0 +1,16 @@ +include rh-virtio.mak + +CONFIG_PCI=y @@ -270,6 +193,7 @@ index 0000000000..c3c73fe752 +CONFIG_TERMINAL3270=y +CONFIG_VFIO=y +CONFIG_VFIO_AP=y ++CONFIG_VFIO_CCW=y +CONFIG_VFIO_PCI=y +CONFIG_VHOST_USER=y +CONFIG_VIRTIO_CCW=y @@ -288,10 +212,10 @@ index f2287a133f..3e2e388e91 100644 +include s390x-rh-devices.mak diff --git a/default-configs/devices/x86_64-rh-devices.mak b/default-configs/devices/x86_64-rh-devices.mak new file mode 100644 -index 0000000000..e80877d4e2 +index 0000000000..9f41400530 --- /dev/null +++ b/default-configs/devices/x86_64-rh-devices.mak -@@ -0,0 +1,101 @@ +@@ -0,0 +1,104 @@ +include rh-virtio.mak + +CONFIG_AC97=y @@ -351,7 +275,7 @@ index 0000000000..e80877d4e2 +CONFIG_PC_ACPI=y +CONFIG_PC_PCI=y +CONFIG_PFLASH_CFI01=y -+CONFIG_PVPANIC=y ++CONFIG_PVPANIC_ISA=y +CONFIG_PXB=y +CONFIG_Q35=y +CONFIG_QXL=y @@ -371,6 +295,8 @@ index 0000000000..e80877d4e2 +CONFIG_USB_EHCI_PCI=y +CONFIG_USB_SMARTCARD=y +CONFIG_USB_STORAGE_BOT=y ++CONFIG_USB_STORAGE_CORE=y ++CONFIG_USB_STORAGE_CLASSIC=y +CONFIG_USB_UHCI=y +CONFIG_USB_XHCI=y +CONFIG_USB_XHCI_NEC=y @@ -381,6 +307,7 @@ index 0000000000..e80877d4e2 +CONFIG_VGA_CIRRUS=y +CONFIG_VGA_PCI=y +CONFIG_VHOST_USER=y ++CONFIG_VHOST_USER_BLK=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_VGA=y +CONFIG_VMMOUSE=y @@ -394,18 +321,34 @@ index 0000000000..e80877d4e2 +CONFIG_TPM_EMULATOR=y +CONFIG_TPM_PASSTHROUGH=y diff --git a/default-configs/devices/x86_64-softmmu.mak b/default-configs/devices/x86_64-softmmu.mak -index 64b2ee2960..b5de7e5279 100644 +index 64b2ee2960..e57bcff7d9 100644 --- a/default-configs/devices/x86_64-softmmu.mak +++ b/default-configs/devices/x86_64-softmmu.mak -@@ -1,3 +1,5 @@ +@@ -1,3 +1,11 @@ # Default configuration for x86_64-softmmu -include i386-softmmu.mak +#include i386-softmmu.mak + +include x86_64-rh-devices.mak ++ ++# ++# RHEL: this is for the limited upstream machine type support, so to export ++# some more devices than what RHEL machines have. ++# ++include x86_64-upstream-devices.mak +diff --git a/default-configs/devices/x86_64-upstream-devices.mak b/default-configs/devices/x86_64-upstream-devices.mak +new file mode 100644 +index 0000000000..2cd20f54d2 +--- /dev/null ++++ b/default-configs/devices/x86_64-upstream-devices.mak +@@ -0,0 +1,4 @@ ++# We need "isa-parallel" ++CONFIG_PARALLEL=y ++# We need "hpet" ++CONFIG_HPET=y diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c -index 5ff4e01c36..ac45ca4acb 100644 +index 853447cf9d..7f01fad64c 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -374,8 +374,8 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm) @@ -433,10 +376,10 @@ index be39117b9b..6fcc5ede50 100644 arm_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx.c', 'pxa2xx_gpio.c', 'pxa2xx_pic.c')) arm_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic.c')) diff --git a/hw/block/fdc.c b/hw/block/fdc.c -index 4c2c35e223..e9eb7b8279 100644 +index a825c2acba..c62927bb3a 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c -@@ -48,6 +48,8 @@ +@@ -49,6 +49,8 @@ #include "trace.h" #include "qom/object.h" @@ -445,8 +388,8 @@ index 4c2c35e223..e9eb7b8279 100644 /********************************************************/ /* debug Floppy devices */ -@@ -2621,6 +2623,14 @@ static void fdctrl_realize_common(DeviceState *dev, FDCtrl *fdctrl, - int i, j; +@@ -2554,6 +2556,14 @@ static void fdctrl_realize_common(DeviceState *dev, FDCtrl *fdctrl, + FDrive *drive; static int command_tables_inited = 0; + /* Restricted for Red Hat Enterprise Linux: */ @@ -460,6 +403,33 @@ index 4c2c35e223..e9eb7b8279 100644 if (fdctrl->fallback == FLOPPY_DRIVE_TYPE_AUTO) { error_setg(errp, "Cannot choose a fallback FDrive type of 'auto'"); return; +diff --git a/hw/char/parallel.c b/hw/char/parallel.c +index b45e67bfbb..e5f108211b 100644 +--- a/hw/char/parallel.c ++++ b/hw/char/parallel.c +@@ -29,6 +29,7 @@ + #include "chardev/char-parallel.h" + #include "chardev/char-fe.h" + #include "hw/acpi/aml-build.h" ++#include "hw/boards.h" + #include "hw/irq.h" + #include "hw/isa/isa.h" + #include "hw/qdev-properties.h" +@@ -534,6 +535,14 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp) + int base; + uint8_t dummy; + ++ /* Restricted for Red Hat Enterprise Linux */ ++ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); ++ if (strstr(mc->name, "rhel")) { ++ error_setg(errp, "Device %s is not supported with machine type %s", ++ object_get_typename(OBJECT(dev)), mc->name); ++ return; ++ } ++ + if (!qemu_chr_fe_backend_connected(&s->chr)) { + error_setg(errp, "Can't create parallel device, empty char device"); + return; diff --git a/hw/cpu/meson.build b/hw/cpu/meson.build index 9e52fee9e7..bb71c9f3e7 100644 --- a/hw/cpu/meson.build @@ -525,10 +495,10 @@ index dde85ba6c6..62cf60c9c9 100644 static const TypeInfo i8042_info = { diff --git a/hw/net/e1000.c b/hw/net/e1000.c -index d7d05ae30a..aaea06d29c 100644 +index 4f75b44cfc..6f075fe235 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c -@@ -1796,6 +1796,7 @@ static const E1000Info e1000_devices[] = { +@@ -1797,6 +1797,7 @@ static const E1000Info e1000_devices[] = { .revision = 0x03, .phy_id2 = E1000_PHY_ID2_8254xx_DEFAULT, }, @@ -536,7 +506,7 @@ index d7d05ae30a..aaea06d29c 100644 { .name = "e1000-82544gc", .device_id = E1000_DEV_ID_82544GC_COPPER, -@@ -1808,6 +1809,7 @@ static const E1000Info e1000_devices[] = { +@@ -1809,6 +1810,7 @@ static const E1000Info e1000_devices[] = { .revision = 0x03, .phy_id2 = E1000_PHY_ID2_8254xx_DEFAULT, }, @@ -545,10 +515,10 @@ index d7d05ae30a..aaea06d29c 100644 static void e1000_register_types(void) diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c -index 2f7dc3c23d..55d36e0069 100644 +index 4f316a6f9d..64178f0f9a 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c -@@ -376,10 +376,12 @@ static const TypeInfo spapr_cpu_core_type_infos[] = { +@@ -370,10 +370,12 @@ static const TypeInfo spapr_cpu_core_type_infos[] = { .instance_size = sizeof(SpaprCpuCore), .class_size = sizeof(SpaprCpuCoreClass), }, @@ -561,11 +531,30 @@ index 2f7dc3c23d..55d36e0069 100644 DEFINE_SPAPR_CPU_CORE_TYPE("power7_v2.3"), DEFINE_SPAPR_CPU_CORE_TYPE("power7+_v2.1"), DEFINE_SPAPR_CPU_CORE_TYPE("power8_v2.0"), +diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c +index 9520471be2..202e032524 100644 +--- a/hw/timer/hpet.c ++++ b/hw/timer/hpet.c +@@ -733,6 +733,14 @@ static void hpet_realize(DeviceState *dev, Error **errp) + int i; + HPETTimer *timer; + ++ /* Restricted for Red Hat Enterprise Linux */ ++ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); ++ if (strstr(mc->name, "rhel")) { ++ error_setg(errp, "Device %s is not supported with machine type %s", ++ object_get_typename(OBJECT(dev)), mc->name); ++ return; ++ } ++ + if (!s->intcap) { + warn_report("Hpet's intcap not initialized"); + } diff --git a/hw/usb/meson.build b/hw/usb/meson.build -index 934e4fa675..e3abba548a 100644 +index fb7a74e73a..674993aa4f 100644 --- a/hw/usb/meson.build +++ b/hw/usb/meson.build -@@ -48,7 +48,7 @@ softmmu_ss.add(when: 'CONFIG_USB_SMARTCARD', if_true: files('dev-smartcard-reade +@@ -55,7 +55,7 @@ softmmu_ss.add(when: 'CONFIG_USB_SMARTCARD', if_true: files('dev-smartcard-reade if config_host.has_key('CONFIG_SMARTCARD') usbsmartcard_ss = ss.source_set() usbsmartcard_ss.add(when: 'CONFIG_USB_SMARTCARD', @@ -575,10 +564,10 @@ index 934e4fa675..e3abba548a 100644 endif diff --git a/qemu-options.hx b/qemu-options.hx -index 104632ea34..363a15b4e8 100644 +index fd21002bd6..0d4fb61bf7 100644 --- a/qemu-options.hx +++ b/qemu-options.hx -@@ -2251,10 +2251,6 @@ ERST +@@ -2327,10 +2327,6 @@ ERST DEF("no-hpet", 0, QEMU_OPTION_no_hpet, "-no-hpet disable HPET\n", QEMU_ARCH_I386) @@ -589,35 +578,84 @@ index 104632ea34..363a15b4e8 100644 DEF("acpitable", HAS_ARG, QEMU_OPTION_acpitable, "-acpitable [sig=str][,rev=n][,oem_id=str][,oem_table_id=str][,oem_rev=n][,asl_compiler_id=str][,asl_compiler_rev=n][,{data|file}=file1[:file2]...]\n" -diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index 07492e9f9a..a0487148e8 100644 ---- a/target/arm/cpu.c -+++ b/target/arm/cpu.c -@@ -2358,7 +2358,9 @@ static void arm_cpu_register_types(void) - - type_register_static(&idau_interface_type_info); - for (i = 0; i < cpu_count; ++i) { -- arm_cpu_register(&arm_cpus[i]); -+ /* RHEL specific: Filter out unsupported cpu models */ -+ if (!strcmp(arm_cpus[i].name, "cortex-a15")) -+ arm_cpu_register(&arm_cpus[i]); - } - } - } diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c -index 0013e25412..6540046128 100644 +index 046e476f65..c3cd0ca039 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c -@@ -679,6 +679,9 @@ static void arm_tcg_cpu_register_types(void) - { - size_t i; +@@ -22,6 +22,7 @@ + /* CPU models. These are not needed for the AArch64 linux-user build. */ + #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) -+ /* Disable TCG cpu types for Red Hat Enterprise Linux */ -+ return; -+ - for (i = 0; i < ARRAY_SIZE(arm_tcg_cpus); ++i) { - arm_cpu_register(&arm_tcg_cpus[i]); - } ++#if 0 /* Disabled for Red Hat Enterprise Linux */ + #ifdef CONFIG_TCG + static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request) + { +@@ -375,6 +376,7 @@ static void cortex_a9_initfn(Object *obj) + cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */ + define_arm_cp_regs(cpu, cortexa9_cp_reginfo); + } ++#endif /* disabled for RHEL */ + + #ifndef CONFIG_USER_ONLY + static uint64_t a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) +@@ -400,6 +402,7 @@ static const ARMCPRegInfo cortexa15_cp_reginfo[] = { + REGINFO_SENTINEL + }; + ++#if 0 /* Disabled for Red Hat Enterprise Linux */ + static void cortex_a7_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); +@@ -445,6 +448,7 @@ static void cortex_a7_initfn(Object *obj) + cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ + define_arm_cp_regs(cpu, cortexa15_cp_reginfo); /* Same as A15 */ + } ++#endif /* disabled for RHEL */ + + static void cortex_a15_initfn(Object *obj) + { +@@ -488,6 +492,7 @@ static void cortex_a15_initfn(Object *obj) + define_arm_cp_regs(cpu, cortexa15_cp_reginfo); + } + ++#if 0 /* Disabled for Red Hat Enterprise Linux */ + static void cortex_m0_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); +@@ -927,6 +932,7 @@ static void arm_v7m_class_init(ObjectClass *oc, void *data) + + cc->gdb_core_xml_file = "arm-m-profile.xml"; + } ++#endif /* disabled for RHEL */ + + #ifndef TARGET_AARCH64 + /* +@@ -1004,6 +1010,7 @@ static void arm_max_initfn(Object *obj) + #endif /* !TARGET_AARCH64 */ + + static const ARMCPUInfo arm_tcg_cpus[] = { ++#if 0 /* Disabled for Red Hat Enterprise Linux */ + { .name = "arm926", .initfn = arm926_initfn }, + { .name = "arm946", .initfn = arm946_initfn }, + { .name = "arm1026", .initfn = arm1026_initfn }, +@@ -1019,7 +1026,9 @@ static const ARMCPUInfo arm_tcg_cpus[] = { + { .name = "cortex-a7", .initfn = cortex_a7_initfn }, + { .name = "cortex-a8", .initfn = cortex_a8_initfn }, + { .name = "cortex-a9", .initfn = cortex_a9_initfn }, ++#endif /* disabled for RHEL */ + { .name = "cortex-a15", .initfn = cortex_a15_initfn }, ++#if 0 /* Disabled for Red Hat Enterprise Linux */ + { .name = "cortex-m0", .initfn = cortex_m0_initfn, + .class_init = arm_v7m_class_init }, + { .name = "cortex-m3", .initfn = cortex_m3_initfn, +@@ -1050,6 +1059,7 @@ static const ARMCPUInfo arm_tcg_cpus[] = { + { .name = "pxa270-b1", .initfn = pxa270b1_initfn }, + { .name = "pxa270-c0", .initfn = pxa270c0_initfn }, + { .name = "pxa270-c5", .initfn = pxa270c5_initfn }, ++#endif /* disabled for RHEL */ + #ifndef TARGET_AARCH64 + { .name = "max", .initfn = arm_max_initfn }, + #endif diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c index 87e4228614..6eaa65efff 100644 --- a/target/ppc/cpu-models.c @@ -689,10 +727,10 @@ index 87e4228614..6eaa65efff 100644 { NULL, NULL } }; diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c -index b5abff8bef..abe09d73c2 100644 +index 050dcf2d42..9254ff46bf 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c -@@ -408,6 +408,9 @@ static void check_unavailable_features(const S390CPUModel *max_model, +@@ -430,6 +430,9 @@ static void check_unavailable_features(const S390CPUModel *max_model, (max_model->def->gen == model->def->gen && max_model->def->ec_ga < model->def->ec_ga)) { list_add_feat("type", unavailable); @@ -703,10 +741,10 @@ index b5abff8bef..abe09d73c2 100644 /* detect missing features if any to properly report them */ diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c -index b8385e6b95..1839cc6648 100644 +index 4fb3bbfef5..6c69d84b84 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c -@@ -2552,6 +2552,14 @@ void kvm_s390_apply_cpu_model(const S390CPUModel *model, Error **errp) +@@ -2516,6 +2516,14 @@ void kvm_s390_apply_cpu_model(const S390CPUModel *model, Error **errp) error_setg(errp, "KVM doesn't support CPU models"); return; } @@ -722,5 +760,5 @@ index b8385e6b95..1839cc6648 100644 prop.ibc = s390_ibc_from_cpu_model(model); /* configure cpu features indicated via STFL(e) */ -- -2.18.4 +2.27.0 diff --git a/0005-Initial-redhat-build.patch b/0005-Initial-redhat-build.patch deleted file mode 100644 index fb98b03..0000000 --- a/0005-Initial-redhat-build.patch +++ /dev/null @@ -1,307 +0,0 @@ -From e4cd78dda8017f181fa94bbad1f0f015a99271db Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Fri, 12 Oct 2018 07:31:11 +0200 -Subject: Initial redhat build - -This patch introduces redhat build structure in redhat subdirectory. In addition, -several issues are fixed in QEMU tree: - - - Change of app name for sasl_server_init in VNC code from qemu to qemu-kvm - - As we use qemu-kvm as name in all places, this is updated to be consistent - - Man page renamed from qemu to qemu-kvm - - man page is installed using make install so we have to fix it in qemu tree - -This rebase includes changes up to qemu-kvm-5.1.0-16.el8 - -Rebase notes (3.1.0): -- added new configure options - -Rebase notes (4.0.0): -- Added dependency to perl-Test-Harness (upstream) -- Added dependency to python3-sphinx (upstream) -- Change location of icons (upstream) -- Remove .desktop file (added upstream) -- Added qemu-trace-stap (added upstream) -- Removed elf2dmp (added upstream) -- Remove .buildinfo -- Added pvh.bin rom (added upstream) -- Added interop documentation files -- Use python module instead of qemu.py (upstream) - -Rebase notes (4.1.0): -- Remove edk2 files generated by build -- Switch to rhel-8.1-candidate build target -- Remove specs documentation -- Switched from libssh2 to libssh -- Add rc0 tarball usage hacks -- Added BuildRequires for wget, rpm-build and python3-sphinx -- Removed new unpacked files -- Update configure line to use new options - -Rebase notes (4.2.0): -- Disable iotest run during make check -- README renamed to README.rst (upstream) -- Removed ui-spice-app.so -- Added relevant changes from "505f7f4 redhat: Adding slirp to the exploded tree" -- Removed qemu-ga.8 install from spec file - installed by make -- Removed spapr-rtas.bin (upstream) -- Require newer SLOF (20191022) - -Rebase notes (5.1.0): -- Use python3 for virtio_seg_max_adjust.py test -- Removed qemu-trace-stap shebang from spec file -- Added virtiofsd.1 (upstream) -- Use out-of-tree build -- New documentation structure (upstream) -- Update local build -- Removing installed qemu-storage-daemon (added upstream) -- Removing opensbi-riscv32-sifive_u-fw_jump.bin (added upstream) -- Disable iotests (moved from Enable make check commit) -- Added missing configure options -- Reorder configure options -- qemu-pr-helper moved to /usr/libexec/ (upstream) -- Added submodules for usb-redir, smartcard-reader and qxl display (upstream) -- Added setting rc version in Makefile for build -- removed --disable-vxhs configure option (removed upstream) -- bumped required libusbx-devel version to 1.0.23 -- bumped libfdt version to 1.6.0 - -Rebase notes (5.2.0 rc0): -- Move libfdt dependency to qemu-kvm-core -- Move manpage rename from Makefile to spec file -- rename with-confsuffix configure option to with-suffix (upstream) -- Bump libusbx Requires version to 1.0.234 -- Manual copy of keymaps in spec file (BZ 1875217) -- Removed /usr/share/qemu-kvm/npcm7xx_bootrom.bin, considering it - unpackaged for now. -- Removed /usr/share/qemu-kvm/qboot.rom, considering unpackaged. -- Added build dependency for meson and ninja-build -- hw/s390/s390-pci-vfio.c hack - set NULL for g_autofree variables -- Removed Chanelog (upstream) -- Fix in directory used for docs (upstream add %name so we do not pass it in configure) -- Package various .so as part of qemu-kvm-core package. - -Rebase notes (5.2.0 rc2): -- Added fix for dtrace build on RHEL 8.4.0 - -Rebase notes (5.2.0 rc3): -- Added man page for qemu-pr-helper -- Added new configure options -- Update qemu-kiwi patches to v4 - -Merged patches (3.1.0): -- 01f0c9f RHEL8: Add disable configure options to qemu spec file -- Spec file cleanups - -Merged patches (4.0.0): -- aa4297c Add edk2 Requires to qemu-kvm -- d124ff5779 Fixing brew build target -- eb204b5 Introduce the qemu-kvm-tests rpm -- 223cf0c Load kvm module during boot (partial) - -Merged patches (4.1.0): -- ebb6e97 redhat: Fix LOCALVERSION creation -- b0ab0cc redhat: enable tpmdev passthrough (not disabling tests) -- 7cb3c4a Enable libpmem to support nvdimm -- 8943607 qemu-kvm.spec: bump libseccomp >= 2.4.0 -- 27b7c44 rh: set CONFIG_BOCHS_DISPLAY=y for x86 (partial) -- e1fe9fe x86_64-rh-devices: enable TPM emulation (partial) - -Merged patches (4.2.0): -- 69e1fb2 enable virgla -- d4f6115 enable virgl, for real this time ... - -Merged patches (5.1.0): -- 5edf6bd Add support for rh-brew-module -- f77d52d redhat: ship virtiofsd vhost-user device backend -- 63f12d4 redhat: Always use module build target for rh-brew (modified) -- 9b1e140 redhat: updating the modular target -- 44b8bd0 spec: Fix python shenigans for tests - -Merged patches (5.2.0 rc0): -- 9238ce7 Add support for simpletrace -- 5797cff Remove explicit glusterfs-api dependency -- fd62478 disable virgl -- 0205018 redhat: link /etc/qemu-ga/fsfreeze-hook to /etc/qemu-kvm/ -- 3645097 redhat: Make all generated so files executable (not only block-*) - -Merged patches (5.2.0 rc2): -- pjw 99657 redhat: introduces disable_everything macro into the configure call -- pjw 99659 redhat: scripts/extract_build_cmd.py - Avoid listing empty lines -- pjw 99658 redhat: Fixing rh-local build -- pjw 99660 redhat: Add qemu-kiwi subpackage -- d2e59ce redhat: add (un/pre)install systemd hooks for qemu-ga - -Merged patches (5.2.0 rc3): -- pjw 99887 - redhat: allow Makefile rh-prep builddep to fail -- pjw 99885 - redhat: adding rh-rpm target ---- - .gitignore | 1 + - README.systemtap | 43 + - hw/s390x/s390-pci-vfio.c | 4 +- - meson.build | 4 +- - redhat/Makefile | 90 + - redhat/Makefile.common | 53 + - redhat/README.tests | 39 + - redhat/qemu-kvm.spec.template | 3402 +++++++++++++++++++++++ - redhat/scripts/extract_build_cmd.py | 5 +- - redhat/scripts/process-patches.sh | 17 +- - scripts/qemu-guest-agent/fsfreeze-hook | 2 +- - scripts/systemtap/conf.d/qemu_kvm.conf | 4 + - scripts/systemtap/script.d/qemu_kvm.stp | 1 + - tests/check-block.sh | 2 + - ui/vnc.c | 2 +- - 15 files changed, 3653 insertions(+), 16 deletions(-) - create mode 100644 README.systemtap - create mode 100644 redhat/Makefile - create mode 100644 redhat/Makefile.common - create mode 100644 redhat/README.tests - create mode 100644 redhat/qemu-kvm.spec.template - create mode 100644 scripts/systemtap/conf.d/qemu_kvm.conf - create mode 100644 scripts/systemtap/script.d/qemu_kvm.stp - -diff --git a/README.systemtap b/README.systemtap -new file mode 100644 -index 0000000000..ad913fc990 ---- /dev/null -+++ b/README.systemtap -@@ -0,0 +1,43 @@ -+QEMU tracing using systemtap-initscript -+--------------------------------------- -+ -+You can capture QEMU trace data all the time using systemtap-initscript. This -+uses SystemTap's flight recorder mode to trace all running guests to a -+fixed-size buffer on the host. Old trace entries are overwritten by new -+entries when the buffer size wraps. -+ -+1. Install the systemtap-initscript package: -+ # yum install systemtap-initscript -+ -+2. Install the systemtap scripts and the conf file: -+ # cp /usr/share/qemu-kvm/systemtap/script.d/qemu_kvm.stp /etc/systemtap/script.d/ -+ # cp /usr/share/qemu-kvm/systemtap/conf.d/qemu_kvm.conf /etc/systemtap/conf.d/ -+ -+The set of trace events to enable is given in qemu_kvm.stp. This SystemTap -+script can be customized to add or remove trace events provided in -+/usr/share/systemtap/tapset/qemu-kvm-simpletrace.stp. -+ -+SystemTap customizations can be made to qemu_kvm.conf to control the flight -+recorder buffer size and whether to store traces in memory only or disk too. -+See stap(1) for option documentation. -+ -+3. Start the systemtap service. -+ # service systemtap start qemu_kvm -+ -+4. Make the service start at boot time. -+ # chkconfig systemtap on -+ -+5. Confirm that the service works. -+ # service systemtap status qemu_kvm -+ qemu_kvm is running... -+ -+When you want to inspect the trace buffer, perform the following steps: -+ -+1. Dump the trace buffer. -+ # staprun -A qemu_kvm >/tmp/trace.log -+ -+2. Start the systemtap service because the preceding step stops the service. -+ # service systemtap start qemu_kvm -+ -+3. Translate the trace record to readable format. -+ # /usr/share/qemu-kvm/simpletrace.py --no-header /usr/share/qemu-kvm/trace-events /tmp/trace.log -diff --git a/hw/s390x/s390-pci-vfio.c b/hw/s390x/s390-pci-vfio.c -index 9296e1bb6e..f70c5a8946 100644 ---- a/hw/s390x/s390-pci-vfio.c -+++ b/hw/s390x/s390-pci-vfio.c -@@ -28,7 +28,7 @@ - */ - bool s390_pci_update_dma_avail(int fd, unsigned int *avail) - { -- g_autofree struct vfio_iommu_type1_info *info; -+ g_autofree struct vfio_iommu_type1_info *info = NULL; - uint32_t argsz; - - assert(avail); -@@ -229,7 +229,7 @@ static void s390_pci_read_pfip(S390PCIBusDevice *pbdev, - */ - void s390_pci_get_clp_info(S390PCIBusDevice *pbdev) - { -- g_autofree struct vfio_device_info *info; -+ g_autofree struct vfio_device_info *info = NULL; - VFIOPCIDevice *vfio_pci; - uint32_t argsz; - int fd; -diff --git a/meson.build b/meson.build -index e3386196ba..8c38b2ea36 100644 ---- a/meson.build -+++ b/meson.build -@@ -1148,7 +1148,9 @@ if capstone_opt == 'internal' - # Include all configuration defines via a header file, which will wind up - # as a dependency on the object file, and thus changes here will result - # in a rebuild. -- '-include', 'capstone-defs.h' -+ '-include', 'capstone-defs.h', -+ -+ '-Wp,-D_GLIBCXX_ASSERTIONS', - ] - - libcapstone = static_library('capstone', -diff --git a/scripts/qemu-guest-agent/fsfreeze-hook b/scripts/qemu-guest-agent/fsfreeze-hook -index 13aafd4845..e9b84ec028 100755 ---- a/scripts/qemu-guest-agent/fsfreeze-hook -+++ b/scripts/qemu-guest-agent/fsfreeze-hook -@@ -8,7 +8,7 @@ - # request, it is issued with "thaw" argument after filesystem is thawed. - - LOGFILE=/var/log/qga-fsfreeze-hook.log --FSFREEZE_D=$(dirname -- "$0")/fsfreeze-hook.d -+FSFREEZE_D=$(dirname -- "$(realpath $0)")/fsfreeze-hook.d - - # Check whether file $1 is a backup or rpm-generated file and should be ignored - is_ignored_file() { -diff --git a/scripts/systemtap/conf.d/qemu_kvm.conf b/scripts/systemtap/conf.d/qemu_kvm.conf -new file mode 100644 -index 0000000000..372d8160a4 ---- /dev/null -+++ b/scripts/systemtap/conf.d/qemu_kvm.conf -@@ -0,0 +1,4 @@ -+# Force load uprobes (see BZ#1118352) -+stap -e 'probe process("/usr/libexec/qemu-kvm").function("main") { printf("") }' -c true -+ -+qemu_kvm_OPT="-s4" # per-CPU buffer size, in megabytes -diff --git a/scripts/systemtap/script.d/qemu_kvm.stp b/scripts/systemtap/script.d/qemu_kvm.stp -new file mode 100644 -index 0000000000..c04abf9449 ---- /dev/null -+++ b/scripts/systemtap/script.d/qemu_kvm.stp -@@ -0,0 +1 @@ -+probe qemu.kvm.simpletrace.handle_qmp_command,qemu.kvm.simpletrace.monitor_protocol_*,qemu.kvm.simpletrace.migrate_set_state {} -diff --git a/tests/check-block.sh b/tests/check-block.sh -index f6b1bda7b9..645b550af8 100755 ---- a/tests/check-block.sh -+++ b/tests/check-block.sh -@@ -58,6 +58,8 @@ if ! (sed --version | grep 'GNU sed') > /dev/null 2>&1 ; then - fi - fi - -+exit 0 -+ - cd tests/qemu-iotests - - # QEMU_CHECK_BLOCK_AUTO is used to disable some unstable sub-tests -diff --git a/ui/vnc.c b/ui/vnc.c -index 49235056f7..eb5520ed73 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -3982,7 +3982,7 @@ void vnc_display_open(const char *id, Error **errp) - - #ifdef CONFIG_VNC_SASL - if (sasl) { -- int saslErr = sasl_server_init(NULL, "qemu"); -+ int saslErr = sasl_server_init(NULL, "qemu-kvm"); - - if (saslErr != SASL_OK) { - error_setg(errp, "Failed to initialize SASL auth: %s", --- -2.18.4 - diff --git a/0007-Machine-type-related-general-changes.patch b/0006-Machine-type-related-general-changes.patch similarity index 78% rename from 0007-Machine-type-related-general-changes.patch rename to 0006-Machine-type-related-general-changes.patch index a6f8696..5c503bc 100644 --- a/0007-Machine-type-related-general-changes.patch +++ b/0006-Machine-type-related-general-changes.patch @@ -1,4 +1,4 @@ -From b97fdd8e425f1c9a156ebdfbdce986d9351c0d19 Mon Sep 17 00:00:00 2001 +From 80e9b92048e6fe7c7aef0e64cbc0f855bd3a6272 Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Fri, 11 Jan 2019 09:54:45 +0100 Subject: Machine type related general changes @@ -8,68 +8,36 @@ split to allow easier review. It contains changes not related to any architecture. Signed-off-by: Miroslav Rezanina - -Rebase changes (4.0.0): -- Remove e1000 device duplication changes to reflect upstream solution -- Rewrite machine compat properties to upstream solution - -Rebase changes (4.1.0): -- Removed optional flag for machine compat properties (upstream) -- Remove c3e002cb chunk from hw/net/e1000.c -- Reorder compat structures -- Use one format for compat scructures -- Added compat for virtio-balloon-pci.any_layout for rhel71 - -Merged patches (4.0.0): -- d4c0957 compat: Generic HW_COMPAT_RHEL7_6 -- cbac773 virtio: Make disable-legacy/disable-modern compat properties optional - -Merged patches (4.1.0): -- 479ad30 redhat: fix cut'n'paste garbage in hw_compat comments -- f19738e compat: Generic hw_compat_rhel_8_0 - -Merged patches (4.2.0): -- 9f2bfaa machine types: Update hw_compat_rhel_8_0 from hw_compat_4_0 -- ca4a5e8 virtio: Make disable-legacy/disable-modern compat properties optional -- compat: Generic hw_compat_rhel_8_1 (patch 93040/92956) - -Merged patches (5.1.0): -- e6c3fbf hw/smbios: set new default SMBIOS fields for Windows driver support (partialy) -- 8f9f4d8 compat: disable 'edid' for virtio-gpu-ccw - -Merged patches (5.2.0 rc0): -- 8348642 redhat: define hw_compat_8_2 -- 45b8402 redhat: define hw_compat_8_2 -- 4effa71 redhat: Update hw_compat_8_2 -- 0e84dff virtio: skip legacy support check on machine types less than 5.1 (partialy) --- hw/acpi/ich9.c | 15 +++ hw/acpi/piix4.c | 5 +- hw/arm/virt.c | 2 +- hw/char/serial.c | 16 +++ - hw/core/machine.c | 213 +++++++++++++++++++++++++++++++++++ + hw/core/machine.c | 251 +++++++++++++++++++++++++++++++++++ hw/display/vga-isa.c | 2 +- hw/i386/pc_piix.c | 2 + hw/i386/pc_q35.c | 2 + - hw/net/e1000e.c | 21 ++++ + hw/net/e1000e.c | 21 +++ hw/net/rtl8139.c | 4 +- hw/rtc/mc146818rtc.c | 6 + - hw/smbios/smbios.c | 46 +++++++- + hw/smbios/smbios.c | 46 ++++++- hw/timer/i8254_common.c | 2 +- hw/usb/hcd-uhci.c | 4 +- - hw/usb/hcd-xhci.c | 20 ++++ + hw/usb/hcd-xhci-pci.c | 59 ++++++-- + hw/usb/hcd-xhci-pci.h | 1 + + hw/usb/hcd-xhci.c | 20 +++ hw/usb/hcd-xhci.h | 2 + include/hw/acpi/ich9.h | 3 + - include/hw/boards.h | 27 +++++ + include/hw/boards.h | 33 +++++ include/hw/firmware/smbios.h | 5 +- include/hw/i386/pc.h | 3 + - include/hw/usb.h | 4 + + include/hw/usb.h | 3 + migration/migration.c | 2 + migration/migration.h | 5 + - 23 files changed, 400 insertions(+), 11 deletions(-) + 25 files changed, 489 insertions(+), 25 deletions(-) diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c -index ac45ca4acb..0b35b35b28 100644 +index 7f01fad64c..33b0c6e33c 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -369,6 +369,18 @@ static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp) @@ -102,10 +70,10 @@ index ac45ca4acb..0b35b35b28 100644 &pm->disable_s3, OBJ_PROP_FLAG_READWRITE); object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S4_DISABLED, diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c -index 669be5bbf6..2063131bcc 100644 +index 8f8b0e95e5..9865d1a349 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c -@@ -277,6 +277,7 @@ static const VMStateDescription vmstate_acpi = { +@@ -278,6 +278,7 @@ static const VMStateDescription vmstate_acpi = { .name = "piix4_pm", .version_id = 3, .minimum_version_id = 3, @@ -113,7 +81,7 @@ index 669be5bbf6..2063131bcc 100644 .post_load = vmstate_acpi_post_load, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(parent_obj, PIIX4PMState), -@@ -633,8 +634,8 @@ static void piix4_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) +@@ -643,8 +644,8 @@ static void piix4_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) static Property piix4_pm_properties[] = { DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0), @@ -125,10 +93,10 @@ index 669be5bbf6..2063131bcc 100644 DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState, use_acpi_hotplug_bridge, true), diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 27dbeb549e..c908b5fcf4 100644 +index 9f01d9041b..f904d3e98e 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -1441,7 +1441,7 @@ static void virt_build_smbios(VirtMachineState *vms) +@@ -1522,7 +1522,7 @@ static void virt_build_smbios(VirtMachineState *vms) smbios_set_defaults("QEMU", product, vmc->smbios_old_sys_ver ? "1.0" : mc->name, false, @@ -138,18 +106,18 @@ index 27dbeb549e..c908b5fcf4 100644 smbios_get_tables(MACHINE(vms), NULL, 0, &smbios_tables, &smbios_tables_len, &smbios_anchor, &smbios_anchor_len); diff --git a/hw/char/serial.c b/hw/char/serial.c -index 97f71879ff..aeb207ef73 100644 +index bc2e322970..cc378142a3 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c -@@ -35,6 +35,7 @@ - #include "qemu/error-report.h" +@@ -37,6 +37,7 @@ #include "trace.h" #include "hw/qdev-properties.h" + #include "hw/qdev-properties-system.h" +#include "migration/migration.h" #define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ -@@ -691,6 +692,9 @@ static int serial_post_load(void *opaque, int version_id) +@@ -689,6 +690,9 @@ static int serial_post_load(void *opaque, int version_id) static bool serial_thr_ipending_needed(void *opaque) { SerialState *s = opaque; @@ -159,7 +127,7 @@ index 97f71879ff..aeb207ef73 100644 if (s->ier & UART_IER_THRI) { bool expected_value = ((s->iir & UART_IIR_ID) == UART_IIR_THRI); -@@ -772,6 +776,10 @@ static const VMStateDescription vmstate_serial_xmit_fifo = { +@@ -770,6 +774,10 @@ static const VMStateDescription vmstate_serial_xmit_fifo = { static bool serial_fifo_timeout_timer_needed(void *opaque) { SerialState *s = (SerialState *)opaque; @@ -170,7 +138,7 @@ index 97f71879ff..aeb207ef73 100644 return timer_pending(s->fifo_timeout_timer); } -@@ -789,6 +797,10 @@ static const VMStateDescription vmstate_serial_fifo_timeout_timer = { +@@ -787,6 +795,10 @@ static const VMStateDescription vmstate_serial_fifo_timeout_timer = { static bool serial_timeout_ipending_needed(void *opaque) { SerialState *s = (SerialState *)opaque; @@ -181,7 +149,7 @@ index 97f71879ff..aeb207ef73 100644 return s->timeout_ipending != 0; } -@@ -806,6 +818,10 @@ static const VMStateDescription vmstate_serial_timeout_ipending = { +@@ -804,6 +816,10 @@ static const VMStateDescription vmstate_serial_timeout_ipending = { static bool serial_poll_needed(void *opaque) { SerialState *s = (SerialState *)opaque; @@ -193,13 +161,49 @@ index 97f71879ff..aeb207ef73 100644 } diff --git a/hw/core/machine.c b/hw/core/machine.c -index d0408049b5..19d50dde45 100644 +index 40def78183..848e7fdff6 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c -@@ -28,6 +28,219 @@ - #include "hw/mem/nvdimm.h" - #include "migration/vmstate.h" +@@ -36,6 +36,257 @@ + #include "hw/virtio/virtio.h" + #include "hw/virtio/virtio-pci.h" ++/* ++ * Mostly the same as hw_compat_5_2 ++ */ ++GlobalProperty hw_compat_rhel_8_4[] = { ++ /* hw_compat_rhel_8_4 from hw_compat_5_2 */ ++ { "ICH9-LPC", "smm-compat", "on"}, ++ /* hw_compat_rhel_8_4 from hw_compat_5_2 */ ++ { "PIIX4_PM", "smm-compat", "on"}, ++}; ++const size_t hw_compat_rhel_8_4_len = G_N_ELEMENTS(hw_compat_rhel_8_4); ++ ++/* ++ * Mostly the same as hw_compat_5_1 ++ */ ++GlobalProperty hw_compat_rhel_8_3[] = { ++ /* hw_compat_rhel_8_3 from hw_compat_5_1 */ ++ { "vhost-scsi", "num_queues", "1"}, ++ /* hw_compat_rhel_8_3 from hw_compat_5_1 */ ++ { "vhost-user-blk", "num-queues", "1"}, ++ /* hw_compat_rhel_8_3 from hw_compat_5_1 */ ++ { "vhost-user-scsi", "num_queues", "1"}, ++ /* hw_compat_rhel_8_3 from hw_compat_5_1 */ ++ { "virtio-blk-device", "num-queues", "1"}, ++ /* hw_compat_rhel_8_3 from hw_compat_5_1 */ ++ { "virtio-scsi-device", "num_queues", "1"}, ++ /* hw_compat_rhel_8_3 from hw_compat_5_1 */ ++ { "nvme", "use-intel-id", "on"}, ++ /* hw_compat_rhel_8_3 from hw_compat_5_1 */ ++ { "pvpanic", "events", "1"}, /* PVPANIC_PANICKED */ ++ /* hw_compat_rhel_8_3 bz 1912846 */ ++ { "pci-xhci", "x-rh-late-msi-cap", "off" }, ++ /* hw_compat_rhel_8_3 from hw_compat_5_1 */ ++ { "virtio-pci", "x-ats-page-aligned", "off"}, ++}; ++const size_t hw_compat_rhel_8_3_len = G_N_ELEMENTS(hw_compat_rhel_8_3); ++ +/* + * The same as hw_compat_4_2 + hw_compat_5_0 + */ @@ -226,6 +230,8 @@ index d0408049b5..19d50dde45 100644 + { "qxl-vga", "revision", "4" }, + /* hw_compat_rhel_8_2 from hw_compat_4_2 */ + { "fw_cfg", "acpi-mr-restore", "false" }, ++ /* hw_compat_rhel_8_2 from hw_compat_4_2 */ ++ { "virtio-device", "use-disabled-flag", "false" }, + /* hw_compat_rhel_8_2 from hw_compat_5_0 */ + { "pci-host-bridge", "x-config-reg-migration-enabled", "off" }, + /* hw_compat_rhel_8_2 from hw_compat_5_0 */ @@ -413,9 +419,9 @@ index d0408049b5..19d50dde45 100644 +}; +const size_t hw_compat_rhel_7_1_len = G_N_ELEMENTS(hw_compat_rhel_7_1); + - GlobalProperty hw_compat_5_1[] = { - { "vhost-scsi", "num_queues", "1"}, - { "vhost-user-blk", "num-queues", "1"}, + GlobalProperty hw_compat_5_2[] = { + { "ICH9-LPC", "smm-compat", "on"}, + { "PIIX4_PM", "smm-compat", "on"}, diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c index 90851e730b..a91c5d7467 100644 --- a/hw/display/vga-isa.c @@ -430,7 +436,7 @@ index 90851e730b..a91c5d7467 100644 }; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c -index 13d1628f13..9fcc5aaf69 100644 +index 46cc951073..62433d8022 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -179,6 +179,8 @@ static void pc_init1(MachineState *machine, @@ -443,7 +449,7 @@ index 13d1628f13..9fcc5aaf69 100644 } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c -index a3f4959c43..f6c2ef4e43 100644 +index 53450190f5..fce52ca70b 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -198,6 +198,8 @@ static void pc_q35_init(MachineState *machine) @@ -530,7 +536,7 @@ index a8a77eca95..6d39c1f1c4 100644 e1000e_prop_disable_vnet, bool), DEFINE_PROP_SIGNED("subsys_ven", E1000EState, subsys_ven, diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c -index ba5ace1ab7..a2e6e83522 100644 +index 90b4fc63ce..3ffb9dd22c 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -3179,7 +3179,7 @@ static int rtl8139_pre_save(void *opaque) @@ -553,10 +559,10 @@ index ba5ace1ab7..a2e6e83522 100644 VMSTATE_UINT16(tally_counters.TxUndrn, RTL8139State), diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c -index 7a38540cb9..377d861913 100644 +index 5d0fcacd0c..4a2e52031b 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c -@@ -43,6 +43,7 @@ +@@ -44,6 +44,7 @@ #include "qapi/visitor.h" #include "exec/address-spaces.h" #include "hw/rtc/mc146818rtc_regs.h" @@ -564,7 +570,7 @@ index 7a38540cb9..377d861913 100644 #ifdef TARGET_I386 #include "qapi/qapi-commands-misc-target.h" -@@ -821,6 +822,11 @@ static int rtc_post_load(void *opaque, int version_id) +@@ -822,6 +823,11 @@ static int rtc_post_load(void *opaque, int version_id) static bool rtc_irq_reinject_on_ack_count_needed(void *opaque) { RTCState *s = (RTCState *)opaque; @@ -577,7 +583,7 @@ index 7a38540cb9..377d861913 100644 } diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c -index 6a3d39793b..232fd61bf8 100644 +index f22c4f5b73..a305a4bcea 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -56,6 +56,9 @@ static bool smbios_legacy = true; @@ -672,10 +678,10 @@ index 050875b497..32935da46c 100644 vmstate_pit_channel, PITChannelState), VMSTATE_INT64(channels[0].next_transition_time, diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c -index 27ca237d71..eb24e39b81 100644 +index 0cb02a6432..962a9622e5 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c -@@ -1221,12 +1221,14 @@ static void usb_uhci_common_realize(PCIDevice *dev, Error **errp) +@@ -1167,12 +1167,14 @@ void usb_uhci_common_realize(PCIDevice *dev, Error **errp) UHCIState *s = UHCI(dev); uint8_t *pci_conf = s->dev.config; int i; @@ -691,11 +697,122 @@ index 27ca237d71..eb24e39b81 100644 if (s->masterbus) { USBPort *ports[NB_PORTS]; +diff --git a/hw/usb/hcd-xhci-pci.c b/hw/usb/hcd-xhci-pci.c +index 9421734d0f..9bfe236a7d 100644 +--- a/hw/usb/hcd-xhci-pci.c ++++ b/hw/usb/hcd-xhci-pci.c +@@ -101,6 +101,33 @@ static int xhci_pci_vmstate_post_load(void *opaque, int version_id) + return 0; + } + ++/* RH bz 1912846 */ ++static bool usb_xhci_pci_add_msi(struct PCIDevice *dev, Error **errp) ++{ ++ int ret; ++ Error *err = NULL; ++ XHCIPciState *s = XHCI_PCI(dev); ++ ++ ret = msi_init(dev, 0x70, s->xhci.numintrs, true, false, &err); ++ /* ++ * Any error other than -ENOTSUP(board's MSI support is broken) ++ * is a programming error ++ */ ++ assert(!ret || ret == -ENOTSUP); ++ if (ret && s->msi == ON_OFF_AUTO_ON) { ++ /* Can't satisfy user's explicit msi=on request, fail */ ++ error_append_hint(&err, "You have to use msi=auto (default) or " ++ "msi=off with this machine type.\n"); ++ error_propagate(errp, err); ++ return true; ++ } ++ assert(!err || s->msi == ON_OFF_AUTO_AUTO); ++ /* With msi=auto, we fall back to MSI off silently */ ++ error_free(err); ++ ++ return false; ++} ++ + static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp) + { + int ret; +@@ -122,23 +149,12 @@ static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp) + s->xhci.nec_quirks = true; + } + +- if (s->msi != ON_OFF_AUTO_OFF) { +- ret = msi_init(dev, 0x70, s->xhci.numintrs, true, false, &err); +- /* +- * Any error other than -ENOTSUP(board's MSI support is broken) +- * is a programming error +- */ +- assert(!ret || ret == -ENOTSUP); +- if (ret && s->msi == ON_OFF_AUTO_ON) { +- /* Can't satisfy user's explicit msi=on request, fail */ +- error_append_hint(&err, "You have to use msi=auto (default) or " +- "msi=off with this machine type.\n"); ++ if (s->msi != ON_OFF_AUTO_OFF && s->rh_late_msi_cap) { ++ /* This gives the behaviour from 5.2.0 onwards, lspci shows 90,a0,70 */ ++ if (usb_xhci_pci_add_msi(dev, &err)) { + error_propagate(errp, err); + return; + } +- assert(!err || s->msi == ON_OFF_AUTO_AUTO); +- /* With msi=auto, we fall back to MSI off silently */ +- error_free(err); + } + pci_register_bar(dev, 0, + PCI_BASE_ADDRESS_SPACE_MEMORY | +@@ -151,6 +167,14 @@ static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp) + assert(ret > 0); + } + ++ /* RH bz 1912846 */ ++ if (s->msi != ON_OFF_AUTO_OFF && !s->rh_late_msi_cap) { ++ /* This gives the older RH machine behaviour, lspci shows 90,70,a0 */ ++ if (usb_xhci_pci_add_msi(dev, &err)) { ++ error_propagate(errp, err); ++ return; ++ } ++ } + if (s->msix != ON_OFF_AUTO_OFF) { + /* TODO check for errors, and should fail when msix=on */ + msix_init(dev, s->xhci.numintrs, +@@ -195,11 +219,18 @@ static void xhci_instance_init(Object *obj) + qdev_alias_all_properties(DEVICE(&s->xhci), obj); + } + ++static Property xhci_pci_properties[] = { ++ /* RH bz 1912846 */ ++ DEFINE_PROP_BOOL("x-rh-late-msi-cap", XHCIPciState, rh_late_msi_cap, true), ++ DEFINE_PROP_END_OF_LIST() ++}; ++ + static void xhci_class_init(ObjectClass *klass, void *data) + { + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + ++ device_class_set_props(dc, xhci_pci_properties); + dc->reset = xhci_pci_reset; + dc->vmsd = &vmstate_xhci_pci; + set_bit(DEVICE_CATEGORY_USB, dc->categories); +diff --git a/hw/usb/hcd-xhci-pci.h b/hw/usb/hcd-xhci-pci.h +index c193f79443..086a1feb1e 100644 +--- a/hw/usb/hcd-xhci-pci.h ++++ b/hw/usb/hcd-xhci-pci.h +@@ -39,6 +39,7 @@ typedef struct XHCIPciState { + XHCIState xhci; + OnOffAuto msi; + OnOffAuto msix; ++ bool rh_late_msi_cap; /* bz 1912846 */ + } XHCIPciState; + + #endif diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 9ce7ca706e..0af661ce1d 100644 +index 46212b1e69..6d1f278aad 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c -@@ -3491,9 +3491,27 @@ static const VMStateDescription vmstate_xhci_slot = { +@@ -3490,9 +3490,27 @@ static const VMStateDescription vmstate_xhci_slot = { } }; @@ -723,7 +840,7 @@ index 9ce7ca706e..0af661ce1d 100644 .fields = (VMStateField[]) { VMSTATE_UINT32(type, XHCIEvent), VMSTATE_UINT32(ccode, XHCIEvent), -@@ -3502,6 +3520,8 @@ static const VMStateDescription vmstate_xhci_event = { +@@ -3501,6 +3519,8 @@ static const VMStateDescription vmstate_xhci_event = { VMSTATE_UINT32(flags, XHCIEvent), VMSTATE_UINT8(slotid, XHCIEvent), VMSTATE_UINT8(epid, XHCIEvent), @@ -733,7 +850,7 @@ index 9ce7ca706e..0af661ce1d 100644 } }; diff --git a/hw/usb/hcd-xhci.h b/hw/usb/hcd-xhci.h -index 02ebd76450..dfda04b125 100644 +index 7bba361f3b..f450ffd13b 100644 --- a/hw/usb/hcd-xhci.h +++ b/hw/usb/hcd-xhci.h @@ -149,6 +149,8 @@ typedef struct XHCIEvent { @@ -746,11 +863,11 @@ index 02ebd76450..dfda04b125 100644 typedef struct XHCIInterrupter { diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h -index 54571c77e0..b3369dab9e 100644 +index df519e40b5..e1ecfbaf1f 100644 --- a/include/hw/acpi/ich9.h +++ b/include/hw/acpi/ich9.h -@@ -61,6 +61,9 @@ typedef struct ICH9LPCPMRegs { - uint8_t smm_enabled; +@@ -62,6 +62,9 @@ typedef struct ICH9LPCPMRegs { + bool smm_compat; bool enable_tco; TCOIORegs tco_regs; + @@ -760,13 +877,19 @@ index 54571c77e0..b3369dab9e 100644 #define ACPI_PM_PROP_TCO_ENABLED "enable_tco" diff --git a/include/hw/boards.h b/include/hw/boards.h -index a49e3a6b44..dd18c9e94d 100644 +index ad6c8fd537..2d7a65724a 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h -@@ -367,4 +367,31 @@ extern const size_t hw_compat_2_2_len; +@@ -413,4 +413,37 @@ extern const size_t hw_compat_2_2_len; extern GlobalProperty hw_compat_2_1[]; extern const size_t hw_compat_2_1_len; ++extern GlobalProperty hw_compat_rhel_8_4[]; ++extern const size_t hw_compat_rhel_8_4_len; ++ ++extern GlobalProperty hw_compat_rhel_8_3[]; ++extern const size_t hw_compat_rhel_8_3_len; ++ +extern GlobalProperty hw_compat_rhel_8_2[]; +extern const size_t hw_compat_rhel_8_2_len; + @@ -812,10 +935,10 @@ index 02a0ced0a0..67e38a1b13 100644 void smbios_get_tables(MachineState *ms, const struct smbios_phys_mem_area *mem_array, diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h -index 911e460097..ae6bf1d209 100644 +index dcf060b791..93c012ac95 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h -@@ -104,6 +104,9 @@ struct PCMachineClass { +@@ -107,6 +107,9 @@ struct PCMachineClass { bool smbios_defaults; bool smbios_legacy_mode; bool smbios_uuid_encoded; @@ -826,25 +949,24 @@ index 911e460097..ae6bf1d209 100644 /* RAM / address space compat: */ bool gigabyte_align; diff --git a/include/hw/usb.h b/include/hw/usb.h -index a70a72e917..78b90436c9 100644 +index 436e07b304..edb2cd94b6 100644 --- a/include/hw/usb.h +++ b/include/hw/usb.h -@@ -570,4 +570,8 @@ int usb_get_quirks(uint16_t vendor_id, uint16_t product_id, - uint8_t interface_class, uint8_t interface_subclass, - uint8_t interface_protocol); +@@ -577,4 +577,7 @@ void usb_pcap_init(FILE *fp); + void usb_pcap_ctrl(USBPacket *p, bool setup); + void usb_pcap_data(USBPacket *p, bool setup); -+ +/* hcd-xhci.c -- rhel7.0.0 machine type compatibility */ +extern bool migrate_cve_2014_5263_xhci_fields; + #endif diff --git a/migration/migration.c b/migration/migration.c -index 87a9b59f83..1bb8d012e6 100644 +index 8ca034136b..4afc6069b6 100644 --- a/migration/migration.c +++ b/migration/migration.c -@@ -134,6 +134,8 @@ enum mig_rp_message_type { - MIG_RP_MSG_MAX - }; +@@ -167,6 +167,8 @@ INITIALIZE_MIGRATE_CAPS_SET(check_caps_background_snapshot, + MIGRATION_CAPABILITY_X_COLO, + MIGRATION_CAPABILITY_VALIDATE_UUID); +bool migrate_pre_2_2; + @@ -852,10 +974,10 @@ index 87a9b59f83..1bb8d012e6 100644 migrations at once. For now we don't need to add dynamic creation of migration */ diff --git a/migration/migration.h b/migration/migration.h -index d096b77f74..6134a534b3 100644 +index db6708326b..1b6c69751c 100644 --- a/migration/migration.h +++ b/migration/migration.h -@@ -364,6 +364,11 @@ bool check_dirty_bitmap_mig_alias_map(const BitmapMigrationNodeAliasList *bbm, +@@ -368,6 +368,11 @@ bool check_dirty_bitmap_mig_alias_map(const BitmapMigrationNodeAliasList *bbm, void migrate_add_address(SocketAddress *address); int foreach_not_ignored_block(RAMBlockIterFunc func, void *opaque); @@ -868,5 +990,5 @@ index d096b77f74..6134a534b3 100644 #define qemu_ram_foreach_block \ #warning "Use foreach_not_ignored_block in migration code" -- -2.18.4 +2.27.0 diff --git a/0008-Add-aarch64-machine-types.patch b/0007-Add-aarch64-machine-types.patch similarity index 73% rename from 0008-Add-aarch64-machine-types.patch rename to 0007-Add-aarch64-machine-types.patch index e252a3c..ae95071 100644 --- a/0008-Add-aarch64-machine-types.patch +++ b/0007-Add-aarch64-machine-types.patch @@ -1,4 +1,4 @@ -From fcf44f2334a6d82709b9c64d45fa2ab1aec595b9 Mon Sep 17 00:00:00 2001 +From ee8aeb6b79bde21b581090c479faf10e716a7e6d Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Fri, 19 Oct 2018 12:53:31 +0200 Subject: Add aarch64 machine types @@ -6,59 +6,16 @@ Subject: Add aarch64 machine types Adding changes to add RHEL machine types for aarch64 architecture. Signed-off-by: Miroslav Rezanina - -Rebase notes (4.0.0): -- Use upstream compat handling - -Rebase notes (4.1.0-rc0): -- Removed a15memmap (upstream) -- Use virt_flash_create in rhel800_virt_instance_init - -Rebase notes (4.2.0-rc0): -- Set numa_mem_supported - -Rebase notes (4.2.0-rc3): -- aarch64: Add virt-rhel8.2.0 machine type for ARM (patch 92246) -- aarch64: virt: Allow more than 1TB of RAM (patch 92249) -- aarch64: virt: Allow PCDIMM instantiation (patch 92247) -- aarch64: virt: Enhance the comment related to gic-version (patch 92248) - -Rebase notes (5.0.0): -- Set default_ram_id in rhel_machine_class_init -- Added setting acpi properties - -Rebase notes (5.1.0): -- Added ras property -- Added to virt_machine_device_unplug_cb to machine type (upstream) -- added mte property (upstream) - -Merged patches (4.0.0): -- 7bfdb4c aarch64: Add virt-rhel8.0.0 machine type for ARM -- 3433e69 aarch64: Set virt-rhel8.0.0 max_cpus to 512 -- 4d20863 aarch64: Use 256MB ECAM region by default - -Merged patches (4.1.0): -- c3e39ef aarch64: Add virt-rhel8.1.0 machine type for ARM -- 59a46d1 aarch64: Allow ARM VIRT iommu option in RHEL8.1 machine - -Merged patches (5.2.0 rc0): -- 12990ad hw/arm: Changes to rhel820 machine -- 46d5a79 hw/arm: Introduce rhel_virt_instance_init() helper -- 098954a hw/arm: Add rhel830 machine type -- ee8e99d arm: Set correct max_cpus value on virt-rhel* machine types -- e5edd38 RHEL-only: arm/virt: Allow the TPM_TIS_SYSBUS device dynamic allocation in machvirt -- 6d7ba66 machine types/numa: set numa_mem_supported on old machine types (partialy) -- 25c5644 machine_types/numa: compatibility for auto_enable_numa_with_memdev (partialy) --- - hw/arm/virt.c | 191 +++++++++++++++++++++++++++++++++++++++++- + hw/arm/virt.c | 211 +++++++++++++++++++++++++++++++++++++++++- include/hw/arm/virt.h | 8 ++ - 2 files changed, 196 insertions(+), 3 deletions(-) + 2 files changed, 218 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index c908b5fcf4..21e0485ac5 100644 +index f904d3e98e..080cf54ef1 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -79,6 +79,7 @@ +@@ -80,6 +80,7 @@ #include "hw/char/pl011.h" #include "qemu/guest-random.h" @@ -66,7 +23,7 @@ index c908b5fcf4..21e0485ac5 100644 #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ void *data) \ -@@ -105,7 +106,49 @@ +@@ -106,7 +107,48 @@ DEFINE_VIRT_MACHINE_LATEST(major, minor, true) #define DEFINE_VIRT_MACHINE(major, minor) \ DEFINE_VIRT_MACHINE_LATEST(major, minor, false) @@ -88,7 +45,6 @@ index c908b5fcf4..21e0485ac5 100644 + static const TypeInfo rhel##m##n##s##_machvirt_info = { \ + .name = MACHINE_TYPE_NAME("virt-rhel" # m "." # n "." # s), \ + .parent = TYPE_RHEL_MACHINE, \ -+ .instance_init = rhel##m##n##s##_virt_instance_init, \ + .class_init = rhel##m##n##s##_virt_class_init, \ + }; \ + static void rhel##m##n##s##_machvirt_init(void) \ @@ -117,7 +73,7 @@ index c908b5fcf4..21e0485ac5 100644 /* Number of external interrupt lines to configure the GIC with */ #define NUM_IRQS 256 -@@ -2027,6 +2070,7 @@ static void machvirt_init(MachineState *machine) +@@ -2113,6 +2155,7 @@ static void machvirt_init(MachineState *machine) qemu_add_machine_init_done_notifier(&vms->machine_done); } @@ -125,15 +81,15 @@ index c908b5fcf4..21e0485ac5 100644 static bool virt_get_secure(Object *obj, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(obj); -@@ -2055,6 +2099,7 @@ static void virt_set_virt(Object *obj, bool value, Error **errp) +@@ -2140,6 +2183,7 @@ static void virt_set_virt(Object *obj, bool value, Error **errp) + vms->virt = value; } - +#endif /* disabled for RHEL */ + static bool virt_get_highmem(Object *obj, Error **errp) { - VirtMachineState *vms = VIRT_MACHINE(obj); -@@ -2108,6 +2153,7 @@ static void virt_set_acpi(Object *obj, Visitor *v, const char *name, +@@ -2237,6 +2281,7 @@ static void virt_set_acpi(Object *obj, Visitor *v, const char *name, visit_type_OnOffAuto(v, name, &vms->acpi, errp); } @@ -141,40 +97,23 @@ index c908b5fcf4..21e0485ac5 100644 static bool virt_get_ras(Object *obj, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(obj); -@@ -2121,13 +2167,14 @@ static void virt_set_ras(Object *obj, bool value, Error **errp) - - vms->ras = value; - } -- -+#if 0 /* Disabled for Red Hat Enterprise Linux */ - static bool virt_get_mte(Object *obj, Error **errp) - { - VirtMachineState *vms = VIRT_MACHINE(obj); - - return vms->mte; - } -+#endif /* disabled for RHEL */ - - static void virt_set_mte(Object *obj, bool value, Error **errp) - { -@@ -2135,7 +2182,7 @@ static void virt_set_mte(Object *obj, bool value, Error **errp) +@@ -2264,6 +2309,7 @@ static void virt_set_mte(Object *obj, bool value, Error **errp) vms->mte = value; } -- -+#endif ++#endif /* disabled for RHEL */ + static char *virt_get_gic_version(Object *obj, Error **errp) { - VirtMachineState *vms = VIRT_MACHINE(obj); -@@ -2442,6 +2489,7 @@ static int virt_kvm_type(MachineState *ms, const char *type_str) - return requested_pa_size > 40 ? requested_pa_size : 0; +@@ -2584,6 +2630,7 @@ static int virt_kvm_type(MachineState *ms, const char *type_str) + return fixed_ipa ? 0 : requested_pa_size; } +#if 0 /* Disabled for Red Hat Enterprise Linux */ static void virt_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); -@@ -2730,3 +2778,140 @@ static void virt_machine_2_6_options(MachineClass *mc) +@@ -2910,3 +2957,165 @@ static void virt_machine_2_6_options(MachineClass *mc) vmc->no_pmu = true; } DEFINE_VIRT_MACHINE(2, 6) @@ -216,26 +155,24 @@ index c908b5fcf4..21e0485ac5 100644 + NULL, NULL); + object_class_property_set_description(oc, "acpi", + "Enable ACPI"); -+} + -+static const TypeInfo rhel_machine_info = { -+ .name = TYPE_RHEL_MACHINE, -+ .parent = TYPE_MACHINE, -+ .abstract = true, -+ .instance_size = sizeof(VirtMachineState), -+ .class_size = sizeof(VirtMachineClass), -+ .class_init = rhel_machine_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { TYPE_HOTPLUG_HANDLER }, -+ { } -+ }, -+}; ++ object_class_property_add_str(oc, "x-oem-id", ++ virt_get_oem_id, ++ virt_set_oem_id); ++ object_class_property_set_description(oc, "x-oem-id", ++ "Override the default value of field OEMID " ++ "in ACPI table header." ++ "The string may be up to 6 bytes in size"); + -+static void rhel_machine_init(void) -+{ -+ type_register_static(&rhel_machine_info); ++ ++ object_class_property_add_str(oc, "x-oem-table-id", ++ virt_get_oem_table_id, ++ virt_set_oem_table_id); ++ object_class_property_set_description(oc, "x-oem-table-id", ++ "Override the default value of field OEM Table ID " ++ "in ACPI table header." ++ "The string may be up to 8 bytes in size"); +} -+type_init(rhel_machine_init); + +static void rhel_virt_instance_init(Object *obj) +{ @@ -244,22 +181,23 @@ index c908b5fcf4..21e0485ac5 100644 + + /* EL3 is disabled by default and non-configurable for RHEL */ + vms->secure = false; ++ + /* EL2 is disabled by default and non-configurable for RHEL */ + vms->virt = false; -+ /* High memory is enabled by default for RHEL */ ++ ++ /* High memory is enabled by default */ + vms->highmem = true; + object_property_add_bool(obj, "highmem", virt_get_highmem, + virt_set_highmem); + object_property_set_description(obj, "highmem", + "Set on/off to enable/disable using " + "physical address space above 32 bits"); -+ + vms->gic_version = VIRT_GIC_VERSION_NOSEL; + object_property_add_str(obj, "gic-version", virt_get_gic_version, + virt_set_gic_version); + object_property_set_description(obj, "gic-version", + "Set GIC version. " -+ "Valid values are 2, 3 and host"); ++ "Valid values are 2, 3, host and max"); + + vms->highmem_ecam = !vmc->no_highmem_ecam; + @@ -282,44 +220,70 @@ index c908b5fcf4..21e0485ac5 100644 + "Set the IOMMU type. " + "Valid values are none and smmuv3"); + ++ /* Default disallows RAS instantiation and is non-configurable for RHEL */ + vms->ras = false; -+ /* MTE is disabled by default. */ ++ ++ /* MTE is disabled by default and non-configurable for RHEL */ + vms->mte = false; + -+ vms->irqmap=a15irqmap; ++ vms->irqmap = a15irqmap; ++ + virt_flash_create(vms); ++ vms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6); ++ vms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); ++ +} + -+static void rhel830_virt_instance_init(Object *obj) ++static const TypeInfo rhel_machine_info = { ++ .name = TYPE_RHEL_MACHINE, ++ .parent = TYPE_MACHINE, ++ .abstract = true, ++ .instance_size = sizeof(VirtMachineState), ++ .class_size = sizeof(VirtMachineClass), ++ .class_init = rhel_machine_class_init, ++ .instance_init = rhel_virt_instance_init, ++ .interfaces = (InterfaceInfo[]) { ++ { TYPE_HOTPLUG_HANDLER }, ++ { } ++ }, ++}; ++ ++static void rhel_machine_init(void) +{ -+ rhel_virt_instance_init(obj); ++ type_register_static(&rhel_machine_info); +} ++type_init(rhel_machine_init); ++ ++static void rhel840_virt_options(MachineClass *mc) ++{ ++ compat_props_add(mc->compat_props, arm_rhel_compat, arm_rhel_compat_len); ++ compat_props_add(mc->compat_props, hw_compat_rhel_8_4, hw_compat_rhel_8_4_len); ++} ++DEFINE_RHEL_MACHINE_AS_LATEST(8, 4, 0) + +static void rhel830_virt_options(MachineClass *mc) +{ -+ compat_props_add(mc->compat_props, arm_rhel_compat, arm_rhel_compat_len); -+} -+DEFINE_RHEL_MACHINE_AS_LATEST(8, 3, 0) ++ VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc)); + -+static void rhel820_virt_instance_init(Object *obj) -+{ -+ rhel_virt_instance_init(obj); ++ rhel840_virt_options(mc); ++ compat_props_add(mc->compat_props, hw_compat_rhel_8_3, hw_compat_rhel_8_3_len); ++ vmc->no_kvm_steal_time = true; +} ++DEFINE_RHEL_MACHINE(8, 3, 0) + +static void rhel820_virt_options(MachineClass *mc) +{ + rhel830_virt_options(mc); -+ compat_props_add(mc->compat_props, hw_compat_rhel_8_2, -+ hw_compat_rhel_8_2_len); ++ compat_props_add(mc->compat_props, hw_compat_rhel_8_2, hw_compat_rhel_8_2_len); + mc->numa_mem_supported = true; + mc->auto_enable_numa_with_memdev = false; +} +DEFINE_RHEL_MACHINE(8, 2, 0) diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h -index aad6d69841..745b76b186 100644 +index 921416f918..6c34864a0a 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h -@@ -167,9 +167,17 @@ struct VirtMachineState { +@@ -170,9 +170,17 @@ struct VirtMachineState { #define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM) @@ -338,5 +302,5 @@ index aad6d69841..745b76b186 100644 bool virt_is_acpi_enabled(VirtMachineState *vms); -- -2.18.4 +2.27.0 diff --git a/0009-Add-ppc64-machine-types.patch b/0008-Add-ppc64-machine-types.patch similarity index 84% rename from 0009-Add-ppc64-machine-types.patch rename to 0008-Add-ppc64-machine-types.patch index bee2ba9..4504703 100644 --- a/0009-Add-ppc64-machine-types.patch +++ b/0008-Add-ppc64-machine-types.patch @@ -1,4 +1,4 @@ -From 06a8855e3b36996d4478219c008986877a253674 Mon Sep 17 00:00:00 2001 +From d70214aa1d8bf7aae9ef3a6bbc04f01735722e3c Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Fri, 19 Oct 2018 13:27:13 +0200 Subject: Add ppc64 machine types @@ -6,56 +6,23 @@ Subject: Add ppc64 machine types Adding changes to add RHEL machine types for ppc64 architecture. Signed-off-by: Miroslav Rezanina - -Rebase changes (4.0.0): -- remove instance options and use upstream solution -- Use upstream compat handling -- Replace SPAPR_PCI_2_7_MMIO_WIN_SIZE with value (changed upstream) -- re-add handling of instance_options (removed upstream) -- Use p8 as default for rhel machine types (p9 default upstream) -- sPAPRMachineClass renamed to SpaprMachineClass (upstream) - -Rebase changes (4.1.0): -- Update format for compat structures - -Merged patches (4.0.0): -- 467d59a redhat: define pseries-rhel8.0.0 machine type - -Merged patches (4.1.0): -- f21757edc target/ppc/spapr: Enable mitigations by default for pseries-4.0 machine type -- 2511c63 redhat: sync pseries-rhel7.6.0 with rhel-av-8.0.1 -- 89f01da redhat: define pseries-rhel8.1.0 machine type - -Merged patches (4.2.0): -- bcba728 redhat: update pseries-rhel8.1.0 machine type -- redhat: update pseries-rhel-7.6.0 machine type (patch 93039) -- redhat: define pseries-rhel8.2.0 machine type (patch 93041) - -Merged patches (5.1.0): -- eb121ff spapr: Enable DD2.3 accelerated count cache flush in pseries-5.0 machine (partial) - -Merged patches (5.2.0 rc0): -- 311a20f redhat: define pseries-rhel8.3.0 machine type -- 1284167 ppc: Set correct max_cpus value on spapr-rhel* machine types -- 1ab8783 redhat: update pseries-rhel8.2.0 machine type -- b162af531a target/ppc: Add experimental option for enabling secure guests --- - hw/ppc/spapr.c | 337 ++++++++++++++++++++++++++++++++++++++++ + hw/ppc/spapr.c | 368 ++++++++++++++++++++++++++++++++++++++++ hw/ppc/spapr_cpu_core.c | 13 ++ include/hw/ppc/spapr.h | 4 + target/ppc/compat.c | 13 +- target/ppc/cpu.h | 1 + - target/ppc/kvm.c | 27 ++++ + target/ppc/kvm.c | 27 +++ target/ppc/kvm_ppc.h | 13 ++ - 7 files changed, 407 insertions(+), 1 deletion(-) + 7 files changed, 438 insertions(+), 1 deletion(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 12a012d9dd..4a838cc955 100644 +index e4be00b732..f9e8dfdfc9 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c -@@ -1585,6 +1585,9 @@ static void spapr_machine_reset(MachineState *machine) +@@ -1568,6 +1568,9 @@ static void spapr_machine_reset(MachineState *machine) - kvmppc_svm_off(&error_fatal); + pef_kvm_reset(machine->cgs, &error_fatal); spapr_caps_apply(spapr); + if (spapr->svm_allowed) { + kvmppc_svm_allow(&error_fatal); @@ -63,7 +30,7 @@ index 12a012d9dd..4a838cc955 100644 first_ppc_cpu = POWERPC_CPU(first_cpu); if (kvm_enabled() && kvmppc_has_cap_mmu_radix() && -@@ -3266,6 +3269,20 @@ static void spapr_set_host_serial(Object *obj, const char *value, Error **errp) +@@ -3254,6 +3257,20 @@ static void spapr_set_host_serial(Object *obj, const char *value, Error **errp) spapr->host_serial = g_strdup(value); } @@ -84,7 +51,7 @@ index 12a012d9dd..4a838cc955 100644 static void spapr_instance_init(Object *obj) { SpaprMachineState *spapr = SPAPR_MACHINE(obj); -@@ -3321,6 +3338,12 @@ static void spapr_instance_init(Object *obj) +@@ -3327,6 +3344,12 @@ static void spapr_instance_init(Object *obj) spapr_get_host_serial, spapr_set_host_serial); object_property_set_description(obj, "host-serial", "Host serial number to advertise in guest device tree"); @@ -97,7 +64,7 @@ index 12a012d9dd..4a838cc955 100644 } static void spapr_machine_finalizefn(Object *obj) -@@ -4459,6 +4482,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) +@@ -4554,6 +4577,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) smc->smp_threads_vsmt = true; smc->nr_xirqs = SPAPR_NR_XIRQS; xfc->match_nvt = spapr_match_nvt; @@ -105,15 +72,15 @@ index 12a012d9dd..4a838cc955 100644 } static const TypeInfo spapr_machine_info = { -@@ -4509,6 +4533,7 @@ static void spapr_machine_latest_class_options(MachineClass *mc) +@@ -4604,6 +4628,7 @@ static void spapr_machine_latest_class_options(MachineClass *mc) } \ type_init(spapr_machine_register_##suffix) +#if 0 /* Disabled for Red Hat Enterprise Linux */ /* - * pseries-5.2 + * pseries-6.0 */ -@@ -4588,6 +4613,7 @@ static void spapr_machine_4_1_class_options(MachineClass *mc) +@@ -4694,6 +4719,7 @@ static void spapr_machine_4_1_class_options(MachineClass *mc) } DEFINE_SPAPR_MACHINE(4_1, "4.1", false); @@ -121,36 +88,63 @@ index 12a012d9dd..4a838cc955 100644 /* * pseries-4.0 -@@ -4604,6 +4630,7 @@ static void phb_placement_4_0(SpaprMachineState *spapr, uint32_t index, +@@ -4713,6 +4739,8 @@ static bool phb_placement_4_0(SpaprMachineState *spapr, uint32_t index, *nv2atsd = 0; + return true; } - ++ +#if 0 /* Disabled for Red Hat Enterprise Linux */ static void spapr_machine_4_0_class_options(MachineClass *mc) { SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc); -@@ -4762,6 +4789,7 @@ DEFINE_SPAPR_MACHINE(2_8, "2.8", false); +@@ -4871,6 +4899,7 @@ DEFINE_SPAPR_MACHINE(2_8, "2.8", false); /* * pseries-2.7 */ +#endif - static void phb_placement_2_7(SpaprMachineState *spapr, uint32_t index, + static bool phb_placement_2_7(SpaprMachineState *spapr, uint32_t index, uint64_t *buid, hwaddr *pio, -@@ -4816,6 +4844,7 @@ static void phb_placement_2_7(SpaprMachineState *spapr, uint32_t index, - *nv2atsd = 0; +@@ -4926,6 +4955,7 @@ static bool phb_placement_2_7(SpaprMachineState *spapr, uint32_t index, + return true; } +#if 0 /* Disabled for Red Hat Enterprise Linux */ static void spapr_machine_2_7_class_options(MachineClass *mc) { SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc); -@@ -4930,6 +4959,314 @@ static void spapr_machine_2_1_class_options(MachineClass *mc) +@@ -5040,6 +5070,344 @@ static void spapr_machine_2_1_class_options(MachineClass *mc) compat_props_add(mc->compat_props, hw_compat_2_1, hw_compat_2_1_len); } DEFINE_SPAPR_MACHINE(2_1, "2.1", false); +#endif + ++static void spapr_machine_rhel_default_class_options(MachineClass *mc) ++{ ++ /* ++ * Defaults for the latest behaviour inherited from the base class ++ * can be overriden here for all pseries-rhel* machines. ++ */ ++ ++ /* Maximum supported VCPU count */ ++ mc->max_cpus = 384; ++} ++ ++/* ++ * pseries-rhel8.4.0 ++ * like pseries-5.2 ++ */ ++ ++static void spapr_machine_rhel840_class_options(MachineClass *mc) ++{ ++ /* The default machine type must apply the RHEL specific defaults */ ++ spapr_machine_rhel_default_class_options(mc); ++ compat_props_add(mc->compat_props, hw_compat_rhel_8_4, ++ hw_compat_rhel_8_4_len); ++} ++ ++DEFINE_SPAPR_MACHINE(rhel840, "rhel8.4.0", true); ++ +/* + * pseries-rhel8.3.0 + * like pseries-5.1 @@ -158,13 +152,17 @@ index 12a012d9dd..4a838cc955 100644 + +static void spapr_machine_rhel830_class_options(MachineClass *mc) +{ -+ /* Defaults for the latest behaviour inherited from the base class */ ++ SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc); + -+ /* Maximum supported VCPU count for all pseries-rhel* machines */ -+ mc->max_cpus = 384; ++ spapr_machine_rhel840_class_options(mc); ++ compat_props_add(mc->compat_props, hw_compat_rhel_8_3, ++ hw_compat_rhel_8_3_len); ++ ++ /* from pseries-5.1 */ ++ smc->pre_5_2_numa_associativity = true; +} + -+DEFINE_SPAPR_MACHINE(rhel830, "rhel8.3.0", true); ++DEFINE_SPAPR_MACHINE(rhel830, "rhel8.3.0", false); + +/* + * pseries-rhel8.2.0 @@ -461,7 +459,7 @@ index 12a012d9dd..4a838cc955 100644 static void spapr_machine_register_types(void) { diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c -index 55d36e0069..008074bae0 100644 +index 64178f0f9a..2bff13a6ab 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -24,6 +24,7 @@ @@ -499,18 +497,18 @@ index 55d36e0069..008074bae0 100644 qdev_unrealize(DEVICE(cpu)); return false; diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index 2e89e36cfb..ba2d81404b 100644 +index bf7cab7a2c..54cdde8980 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h -@@ -140,6 +140,7 @@ struct SpaprMachineClass { +@@ -143,6 +143,7 @@ struct SpaprMachineClass { bool pre_5_1_assoc_refpoints; bool pre_5_2_numa_associativity; + bool has_power9_support; - void (*phb_placement)(SpaprMachineState *spapr, uint32_t index, - uint64_t *buid, hwaddr *pio, + bool (*phb_placement)(SpaprMachineState *spapr, uint32_t index, + uint64_t *buid, hwaddr *pio, hwaddr *mmio32, hwaddr *mmio64, -@@ -220,6 +221,9 @@ struct SpaprMachineState { +@@ -223,6 +224,9 @@ struct SpaprMachineState { int fwnmi_machine_check_interlock; QemuCond fwnmi_machine_check_interlock_cond; @@ -546,7 +544,7 @@ index 7949a24f5a..f207a9ba01 100644 const CompatInfo *compat = compat_by_pvr(compat_pvr); const CompatInfo *min = compat_by_pvr(min_compat_pvr); diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h -index 2609e4082e..21c63b5360 100644 +index e73416da68..4eb427a601 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1347,6 +1347,7 @@ static inline int cpu_mmu_index(CPUPPCState *env, bool ifetch) @@ -558,7 +556,7 @@ index 2609e4082e..21c63b5360 100644 uint32_t min_compat_pvr, uint32_t max_compat_pvr); bool ppc_type_check_compat(const char *cputype, uint32_t compat_pvr, diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c -index daf690a678..9bf3449adb 100644 +index 104a308abb..cb0fb67383 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -89,6 +89,7 @@ static int cap_ppc_count_cache_flush_assist; @@ -577,7 +575,7 @@ index daf690a678..9bf3449adb 100644 cap_large_decr = kvmppc_get_dec_bits(); cap_fwnmi = kvm_vm_check_extension(s, KVM_CAP_PPC_FWNMI); /* -@@ -2538,6 +2540,16 @@ int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable) +@@ -2551,6 +2553,16 @@ int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable) return 0; } @@ -594,9 +592,9 @@ index daf690a678..9bf3449adb 100644 PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void) { uint32_t host_pvr = mfpvr(); -@@ -2947,3 +2959,18 @@ void kvmppc_svm_off(Error **errp) - error_setg_errno(errp, -rc, "KVM_PPC_SVM_OFF ioctl failed"); - } +@@ -2947,3 +2959,18 @@ bool kvm_arch_cpu_check_are_resettable(void) + { + return true; } + +void kvmppc_svm_allow(Error **errp) @@ -614,18 +612,18 @@ index daf690a678..9bf3449adb 100644 + } +} diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h -index 73ce2bc951..1239b841fd 100644 +index 989f61ace0..2e7a5d3fc1 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h -@@ -40,6 +40,7 @@ target_ulong kvmppc_configure_v3_mmu(PowerPCCPU *cpu, +@@ -39,6 +39,7 @@ int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu); + target_ulong kvmppc_configure_v3_mmu(PowerPCCPU *cpu, bool radix, bool gtse, uint64_t proc_tbl); - void kvmppc_svm_off(Error **errp); +void kvmppc_svm_allow(Error **errp); #ifndef CONFIG_USER_ONLY bool kvmppc_spapr_use_multitce(void); int kvmppc_spapr_enable_inkernel_multitce(void); -@@ -73,6 +74,8 @@ int kvmppc_set_cap_nested_kvm_hv(int enable); +@@ -72,6 +73,8 @@ int kvmppc_set_cap_nested_kvm_hv(int enable); int kvmppc_get_cap_large_decr(void); int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable); int kvmppc_enable_hwrng(void); @@ -634,7 +632,7 @@ index 73ce2bc951..1239b841fd 100644 int kvmppc_put_books_sregs(PowerPCCPU *cpu); PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void); void kvmppc_check_papr_resize_hpt(Error **errp); -@@ -387,6 +390,16 @@ static inline int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable) +@@ -381,6 +384,16 @@ static inline int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable) return -1; } @@ -652,5 +650,5 @@ index 73ce2bc951..1239b841fd 100644 { return -1; -- -2.18.4 +2.27.0 diff --git a/0010-Add-s390x-machine-types.patch b/0009-Add-s390x-machine-types.patch similarity index 76% rename from 0010-Add-s390x-machine-types.patch rename to 0009-Add-s390x-machine-types.patch index 606a004..c768dd7 100644 --- a/0010-Add-s390x-machine-types.patch +++ b/0009-Add-s390x-machine-types.patch @@ -1,4 +1,4 @@ -From 36540969ad3b08f1964c71406f1fc14c0e5b47de Mon Sep 17 00:00:00 2001 +From 09eba380295aef0a27d3fbcdda43019ab2898e08 Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Fri, 19 Oct 2018 13:47:32 +0200 Subject: Add s390x machine types @@ -6,29 +6,15 @@ Subject: Add s390x machine types Adding changes to add RHEL machine types for s390x architecture. Signed-off-by: Miroslav Rezanina - -Rebase changes (weekly-4.1.0): -- Use upstream compat handling - -Merged patches (3.1.0): -- 29df663 s390x/cpumodel: default enable bpb and ppa15 for z196 and later - -Merged patches (4.1.0): -- 6c200d665b hw/s390x/s390-virtio-ccw: Add machine types for RHEL8.0.0 - -Merged patches (4.2.0): -- fb192e5 redhat: s390x: Rename s390-ccw-virtio-rhel8.0.0 to s390-ccw-virtio-rhel8.1.0 -- a9b22e8 redhat: s390x: Add proper compatibility options for the -rhel7.6.0 machine -- hw/s390x: Add the s390-ccw-virtio-rhel8.2.0 machine types (patch 92954) --- - hw/s390x/s390-virtio-ccw.c | 71 +++++++++++++++++++++++++++++++++++++- - 1 file changed, 70 insertions(+), 1 deletion(-) + hw/s390x/s390-virtio-ccw.c | 87 +++++++++++++++++++++++++++++++++++++- + 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c -index 4e140bbead..b8dde7e4e1 100644 +index 2972b607f3..8df6dd1c71 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c -@@ -765,7 +765,7 @@ bool css_migration_enabled(void) +@@ -771,7 +771,7 @@ bool css_migration_enabled(void) { \ MachineClass *mc = MACHINE_CLASS(oc); \ ccw_machine_##suffix##_class_options(mc); \ @@ -37,29 +23,44 @@ index 4e140bbead..b8dde7e4e1 100644 if (latest) { \ mc->alias = "s390-ccw-virtio"; \ mc->is_default = true; \ -@@ -789,6 +789,7 @@ bool css_migration_enabled(void) +@@ -795,6 +795,7 @@ bool css_migration_enabled(void) } \ type_init(ccw_machine_register_##suffix) +#if 0 /* Disabled for Red Hat Enterprise Linux */ - static void ccw_machine_5_2_instance_options(MachineState *machine) + static void ccw_machine_6_0_instance_options(MachineState *machine) { } -@@ -1053,6 +1054,74 @@ static void ccw_machine_2_4_class_options(MachineClass *mc) +@@ -1071,6 +1072,90 @@ static void ccw_machine_2_4_class_options(MachineClass *mc) compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); } DEFINE_CCW_MACHINE(2_4, "2.4", false); +#endif + ++static void ccw_machine_rhel840_instance_options(MachineState *machine) ++{ ++} ++ ++static void ccw_machine_rhel840_class_options(MachineClass *mc) ++{ ++ compat_props_add(mc->compat_props, hw_compat_rhel_8_4, hw_compat_rhel_8_4_len); ++} ++DEFINE_CCW_MACHINE(rhel840, "rhel8.4.0", true); ++ +static void ccw_machine_rhel820_instance_options(MachineState *machine) +{ ++ ccw_machine_rhel840_instance_options(machine); +} + +static void ccw_machine_rhel820_class_options(MachineClass *mc) +{ ++ ccw_machine_rhel840_class_options(mc); + mc->fixup_ram_size = s390_fixup_ram_size; ++ /* we did not publish a rhel8.3.0 machine */ ++ compat_props_add(mc->compat_props, hw_compat_rhel_8_3, hw_compat_rhel_8_3_len); ++ compat_props_add(mc->compat_props, hw_compat_rhel_8_2, hw_compat_rhel_8_2_len); +} -+DEFINE_CCW_MACHINE(rhel820, "rhel8.2.0", true); ++DEFINE_CCW_MACHINE(rhel820, "rhel8.2.0", false); + +static void ccw_machine_rhel760_instance_options(MachineState *machine) +{ @@ -81,6 +82,7 @@ index 4e140bbead..b8dde7e4e1 100644 +{ + ccw_machine_rhel820_class_options(mc); + /* We never published the s390x version of RHEL-AV 8.0 and 8.1, so add this here */ ++ compat_props_add(mc->compat_props, hw_compat_rhel_8_1, hw_compat_rhel_8_1_len); + compat_props_add(mc->compat_props, hw_compat_rhel_8_0, hw_compat_rhel_8_0_len); + compat_props_add(mc->compat_props, hw_compat_rhel_7_6, hw_compat_rhel_7_6_len); +} @@ -121,5 +123,5 @@ index 4e140bbead..b8dde7e4e1 100644 static void ccw_machine_register_types(void) { -- -2.18.4 +2.27.0 diff --git a/0011-Add-x86_64-machine-types.patch b/0010-Add-x86_64-machine-types.patch similarity index 88% rename from 0011-Add-x86_64-machine-types.patch rename to 0010-Add-x86_64-machine-types.patch index 63656ab..28de463 100644 --- a/0011-Add-x86_64-machine-types.patch +++ b/0010-Add-x86_64-machine-types.patch @@ -1,4 +1,4 @@ -From 004d31cf0e8bb83374a85ecab59eb22683a1e361 Mon Sep 17 00:00:00 2001 +From a082c53cc14afcd2ad77262575af50e164e75649 Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Fri, 19 Oct 2018 13:10:31 +0200 Subject: Add x86_64 machine types @@ -6,63 +6,23 @@ Subject: Add x86_64 machine types Adding changes to add RHEL machine types for x86_64 architecture. Signed-off-by: Miroslav Rezanina - -Rebase changes (qemu-4.0.0): -- Use upstream compat handling - -Rebase notes (3.1.0): -- Removed xsave changes - -Rebase notes (4.1.0): -- Updated format for compat structures - -Rebase notes (4.2.0-rc2): -- Use X86MachineClass for save_tsc_khz (upstream change) - -Merged patches (4.1.0): -- f4dc802 pc: 7.5 compat entries -- 456ed3e pc: PC_RHEL7_6_COMPAT -- 04119ee pc: Add compat for pc-i440fx-rhel7.6.0 machine type -- b3b3687 pc: Add pc-q35-8.0.0 machine type -- 8d46fc6 pc: Add x-migrate-smi-count=off to PC_RHEL7_6_COMPAT -- 1de7949 kvm: clear out KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT for older machine types -- 18cf0d7 target/i386: Disable MPX support on named CPU models (partialy) -- 2660667 rhel: Set host-phys-bits-limit=48 on rhel machine-types - -Merged patches (4.2.0): -- 7d5c2ef pc: Don't make die-id mandatory unless necessary -- e42808c x86 machine types: pc_rhel_8_0_compat -- 9de83a8 x86 machine types: q35: Fixup units_per_default_bus -- 6df1559 x86 machine types: Fixup dynamic sysbus entries -- 0784125 x86 machine types: add pc-q35-rhel8.1.0 -- machines/x86: Add rhel 8.2 machine type (patch 92959) - -Merged patches (5.1.0): -- 481357e RHEL: hw/i386: disable nested PERF_GLOBAL_CTRL MSR support -- e6c3fbf hw/smbios: set new default SMBIOS fields for Windows driver support (partialy) - -Merged patches (5.2.0 rc0): -- b02c9f5 x86: Add 8.3.0 x86_64 machine type -- f2edc4f q35: Set max_cpus to 512 -- 6d7ba66 machine types/numa: set numa_mem_supported on old machine types (partialy) -- 25c5644 machine_types/numa: compatibility for auto_enable_numa_with_memdev (partialy) -- e2d3209 x86: lpc9: let firmware negotiate 'CPU hotplug with SMI' features (partialy) --- - hw/i386/acpi-build.c | 3 + - hw/i386/pc.c | 273 ++++++++++++++++++++++++++++++++++++++++++- - hw/i386/pc_piix.c | 215 +++++++++++++++++++++++++++++++++- - hw/i386/pc_q35.c | 185 ++++++++++++++++++++++++++++- - include/hw/boards.h | 2 + - include/hw/i386/pc.h | 36 ++++++ - target/i386/cpu.c | 3 +- - target/i386/kvm.c | 4 + - 8 files changed, 714 insertions(+), 7 deletions(-) + hw/i386/acpi-build.c | 3 + + hw/i386/pc.c | 277 ++++++++++++++++++++++++++++++++++++- + hw/i386/pc_piix.c | 225 +++++++++++++++++++++++++++++- + hw/i386/pc_q35.c | 214 +++++++++++++++++++++++++++- + include/hw/boards.h | 2 + + include/hw/i386/pc.h | 39 ++++++ + target/i386/cpu.c | 3 +- + target/i386/kvm/kvm.c | 4 + + tests/qtest/pvpanic-test.c | 5 +- + 9 files changed, 763 insertions(+), 9 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c -index 1f5c211245..b1082bd412 100644 +index de98750aef..7bd67f7877 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c -@@ -217,6 +217,9 @@ static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm) +@@ -231,6 +231,9 @@ static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm) pm->fadt.reset_reg = r; pm->fadt.reset_val = 0xf; pm->fadt.flags |= 1 << ACPI_FADT_F_RESET_REG_SUP; @@ -73,10 +33,10 @@ index 1f5c211245..b1082bd412 100644 pm->smi_on_cpuhp = !!(smi_features & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT)); diff --git a/hw/i386/pc.c b/hw/i386/pc.c -index 17b514d1da..f3fc695fe2 100644 +index 8a84b25a03..edc02a68ca 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c -@@ -352,6 +352,271 @@ GlobalProperty pc_compat_1_4[] = { +@@ -355,6 +355,275 @@ GlobalProperty pc_compat_1_4[] = { }; const size_t pc_compat_1_4_len = G_N_ELEMENTS(pc_compat_1_4); @@ -91,11 +51,15 @@ index 17b514d1da..f3fc695fe2 100644 + { TYPE_X86_CPU, "vmx-exit-load-perf-global-ctrl", "off" }, + /* bz 1508330 */ + { "vfio-pci", "x-no-geforce-quirks", "on" }, -+ /* BZ 1846886 */ -+ { "ICH9-LPC", "x-smi-cpu-hotplug", "off" }, +}; +const size_t pc_rhel_compat_len = G_N_ELEMENTS(pc_rhel_compat); + ++GlobalProperty pc_rhel_8_3_compat[] = { ++ /* pc_rhel_8_3_compat from pc_compat_5_1 */ ++ { "ICH9-LPC", "x-smi-cpu-hotplug", "off" }, ++}; ++const size_t pc_rhel_8_3_compat_len = G_N_ELEMENTS(pc_rhel_8_3_compat); ++ +GlobalProperty pc_rhel_8_2_compat[] = { + /* pc_rhel_8_2_compat from pc_compat_4_2 */ + { "mch", "smbase-smram", "off" }, @@ -348,7 +312,7 @@ index 17b514d1da..f3fc695fe2 100644 GSIState *pc_gsi_create(qemu_irq **irqs, bool pci_enabled) { GSIState *s; -@@ -970,7 +1235,8 @@ void pc_memory_init(PCMachineState *pcms, +@@ -952,7 +1221,8 @@ void pc_memory_init(PCMachineState *pcms, option_rom_mr = g_malloc(sizeof(*option_rom_mr)); memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE, &error_fatal); @@ -358,7 +322,7 @@ index 17b514d1da..f3fc695fe2 100644 memory_region_set_readonly(option_rom_mr, true); } memory_region_add_subregion_overlap(rom_memory, -@@ -1674,6 +1940,8 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) +@@ -1702,6 +1972,8 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) pcmc->pvh_enabled = true; pcmc->kvmclock_create_always = true; assert(!mc->get_hotplug_handler); @@ -367,7 +331,7 @@ index 17b514d1da..f3fc695fe2 100644 mc->get_hotplug_handler = pc_get_hotplug_handler; mc->hotplug_allowed = pc_hotplug_allowed; mc->cpu_index_to_instance_props = x86_cpu_index_to_props; -@@ -1685,7 +1953,8 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) +@@ -1713,7 +1985,8 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) mc->default_boot_order = "cad"; mc->smp_parse = pc_smp_parse; mc->block_default_type = IF_IDE; @@ -378,7 +342,7 @@ index 17b514d1da..f3fc695fe2 100644 mc->wakeup = pc_machine_wakeup; hc->pre_plug = pc_machine_device_pre_plug_cb; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c -index 9fcc5aaf69..815da79108 100644 +index 62433d8022..d9c5df16d8 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -54,6 +54,7 @@ @@ -408,7 +372,7 @@ index 9fcc5aaf69..815da79108 100644 static void pc_compat_2_3_fn(MachineState *machine) { X86MachineState *x86ms = X86_MACHINE(machine); -@@ -1007,3 +1009,212 @@ static void xenfv_3_1_machine_options(MachineClass *m) +@@ -927,3 +929,222 @@ static void xenfv_3_1_machine_options(MachineClass *m) DEFINE_PC_MACHINE(xenfv, "xenfv-3.1", pc_xen_hvm_init, xenfv_3_1_machine_options); #endif @@ -421,8 +385,9 @@ index 9fcc5aaf69..815da79108 100644 +{ + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + m->family = "pc_piix_Y"; -+ m->default_machine_opts = "firmware=bios-256k.bin"; ++ m->default_machine_opts = "firmware=bios-256k.bin,hpet=off"; + pcmc->default_nic_model = "e1000"; ++ pcmc->pci_root_uid = 0; + m->default_display = "std"; + m->no_parallel = 1; + m->numa_mem_supported = true; @@ -448,6 +413,15 @@ index 9fcc5aaf69..815da79108 100644 + m->smbus_no_migration_support = true; + pcmc->pvh_enabled = false; + pcmc->default_cpu_version = CPU_VERSION_LEGACY; ++ pcmc->kvmclock_create_always = false; ++ /* From pc_i440fx_5_1_machine_options() */ ++ pcmc->pci_root_uid = 1; ++ compat_props_add(m->compat_props, hw_compat_rhel_8_4, ++ hw_compat_rhel_8_4_len); ++ compat_props_add(m->compat_props, hw_compat_rhel_8_3, ++ hw_compat_rhel_8_3_len); ++ compat_props_add(m->compat_props, pc_rhel_8_3_compat, ++ pc_rhel_8_3_compat_len); + compat_props_add(m->compat_props, hw_compat_rhel_8_2, + hw_compat_rhel_8_2_len); + compat_props_add(m->compat_props, pc_rhel_8_2_compat, @@ -622,7 +596,7 @@ index 9fcc5aaf69..815da79108 100644 +DEFINE_PC_MACHINE(rhel700, "pc-i440fx-rhel7.0.0", pc_init_rhel700, + pc_machine_rhel700_options); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c -index f6c2ef4e43..3340008c00 100644 +index fce52ca70b..44109e4876 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -195,8 +195,8 @@ static void pc_q35_init(MachineState *machine) @@ -644,7 +618,7 @@ index f6c2ef4e43..3340008c00 100644 static void pc_q35_machine_options(MachineClass *m) { PCMachineClass *pcmc = PC_MACHINE_CLASS(m); -@@ -568,3 +569,183 @@ static void pc_q35_2_4_machine_options(MachineClass *m) +@@ -581,3 +582,212 @@ static void pc_q35_2_4_machine_options(MachineClass *m) DEFINE_Q35_MACHINE(v2_4, "pc-q35-2.4", NULL, pc_q35_2_4_machine_options); @@ -657,9 +631,10 @@ index f6c2ef4e43..3340008c00 100644 +{ + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pcmc->default_nic_model = "e1000e"; ++ pcmc->pci_root_uid = 0; + m->family = "pc_q35_Z"; + m->units_per_default_bus = 1; -+ m->default_machine_opts = "firmware=bios-256k.bin"; ++ m->default_machine_opts = "firmware=bios-256k.bin,hpet=off"; + m->default_display = "std"; + m->no_floppy = 1; + m->no_parallel = 1; @@ -668,10 +643,30 @@ index f6c2ef4e43..3340008c00 100644 + machine_class_allow_dynamic_sysbus_dev(m, TYPE_INTEL_IOMMU_DEVICE); + machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE); + m->alias = "q35"; -+ m->max_cpus = 512; ++ m->max_cpus = 710; + compat_props_add(m->compat_props, pc_rhel_compat, pc_rhel_compat_len); +} + ++static void pc_q35_init_rhel840(MachineState *machine) ++{ ++ pc_q35_init(machine); ++} ++ ++static void pc_q35_machine_rhel840_options(MachineClass *m) ++{ ++ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); ++ pc_q35_machine_rhel_options(m); ++ m->desc = "RHEL-8.4.0 PC (Q35 + ICH9, 2009)"; ++ pcmc->smbios_stream_product = "RHEL-AV"; ++ pcmc->smbios_stream_version = "8.4.0"; ++ compat_props_add(m->compat_props, hw_compat_rhel_8_4, ++ hw_compat_rhel_8_4_len); ++} ++ ++DEFINE_PC_MACHINE(q35_rhel840, "pc-q35-rhel8.4.0", pc_q35_init_rhel840, ++ pc_q35_machine_rhel840_options); ++ ++ +static void pc_q35_init_rhel830(MachineState *machine) +{ + pc_q35_init(machine); @@ -680,10 +675,19 @@ index f6c2ef4e43..3340008c00 100644 +static void pc_q35_machine_rhel830_options(MachineClass *m) +{ + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); -+ pc_q35_machine_rhel_options(m); ++ pc_q35_machine_rhel840_options(m); + m->desc = "RHEL-8.3.0 PC (Q35 + ICH9, 2009)"; ++ m->alias = NULL; + pcmc->smbios_stream_product = "RHEL-AV"; + pcmc->smbios_stream_version = "8.3.0"; ++ compat_props_add(m->compat_props, hw_compat_rhel_8_3, ++ hw_compat_rhel_8_3_len); ++ compat_props_add(m->compat_props, pc_rhel_8_3_compat, ++ pc_rhel_8_3_compat_len); ++ /* From pc_q35_5_1_machine_options() */ ++ pcmc->kvmclock_create_always = false; ++ /* From pc_q35_5_1_machine_options() */ ++ pcmc->pci_root_uid = 1; +} + +DEFINE_PC_MACHINE(q35_rhel830, "pc-q35-rhel8.3.0", pc_q35_init_rhel830, @@ -697,9 +701,8 @@ index f6c2ef4e43..3340008c00 100644 +static void pc_q35_machine_rhel820_options(MachineClass *m) +{ + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); -+ pc_q35_machine_rhel_options(m); ++ pc_q35_machine_rhel830_options(m); + m->desc = "RHEL-8.2.0 PC (Q35 + ICH9, 2009)"; -+ m->alias = NULL; + m->numa_mem_supported = true; + m->auto_enable_numa_with_memdev = false; + pcmc->smbios_stream_product = "RHEL-AV"; @@ -829,10 +832,10 @@ index f6c2ef4e43..3340008c00 100644 +DEFINE_PC_MACHINE(q35_rhel730, "pc-q35-rhel7.3.0", pc_q35_init_rhel730, + pc_q35_machine_rhel730_options); diff --git a/include/hw/boards.h b/include/hw/boards.h -index dd18c9e94d..4e4a54b313 100644 +index 2d7a65724a..90ae100bfc 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h -@@ -202,6 +202,8 @@ struct MachineClass { +@@ -243,6 +243,8 @@ struct MachineClass { strList *allowed_dynamic_sysbus_devices; bool auto_enable_numa_with_memhp; bool auto_enable_numa_with_memdev; @@ -842,10 +845,10 @@ index dd18c9e94d..4e4a54b313 100644 bool smbus_no_migration_support; bool nvdimm_supported; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h -index ae6bf1d209..e2ba9a4b58 100644 +index 93c012ac95..79a7803a2f 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h -@@ -125,6 +125,9 @@ struct PCMachineClass { +@@ -128,6 +128,9 @@ struct PCMachineClass { /* create kvmclock device even when KVM PV features are not exposed */ bool kvmclock_create_always; @@ -855,13 +858,16 @@ index ae6bf1d209..e2ba9a4b58 100644 }; #define TYPE_PC_MACHINE "generic-pc-machine" -@@ -266,6 +269,39 @@ extern const size_t pc_compat_1_5_len; +@@ -275,6 +278,42 @@ extern const size_t pc_compat_1_5_len; extern GlobalProperty pc_compat_1_4[]; extern const size_t pc_compat_1_4_len; +extern GlobalProperty pc_rhel_compat[]; +extern const size_t pc_rhel_compat_len; + ++extern GlobalProperty pc_rhel_8_3_compat[]; ++extern const size_t pc_rhel_8_3_compat_len; ++ +extern GlobalProperty pc_rhel_8_2_compat[]; +extern const size_t pc_rhel_8_2_compat_len; + @@ -896,10 +902,10 @@ index ae6bf1d209..e2ba9a4b58 100644 * depending on QEMU versions up to QEMU 2.4. */ diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 5a8c96072e..dc592e990e 100644 +index ad99cad0e7..c30bb2a6b0 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c -@@ -1803,7 +1803,7 @@ static X86CPUDefinition builtin_x86_defs[] = { +@@ -1882,7 +1882,7 @@ static X86CPUDefinition builtin_x86_defs[] = { .level = 0xd, .vendor = CPUID_VENDOR_AMD, .family = 6, @@ -908,7 +914,7 @@ index 5a8c96072e..dc592e990e 100644 .stepping = 3, .features[FEAT_1_EDX] = PPRO_FEATURES | -@@ -4117,6 +4117,7 @@ static PropValue kvm_default_props[] = { +@@ -4264,6 +4264,7 @@ static PropValue kvm_default_props[] = { { "acpi", "off" }, { "monitor", "off" }, { "svm", "off" }, @@ -916,11 +922,11 @@ index 5a8c96072e..dc592e990e 100644 { NULL, NULL }, }; -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index a2934dda02..19bc39b9e3 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -3126,6 +3126,7 @@ static int kvm_get_msrs(X86CPU *cpu) +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 7fe9f52710..4c69c2cb4b 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -3181,6 +3181,7 @@ static int kvm_get_msrs(X86CPU *cpu) struct kvm_msr_entry *msrs = cpu->kvm_msr_buf->entries; int ret, i; uint64_t mtrr_top_bits; @@ -928,7 +934,7 @@ index a2934dda02..19bc39b9e3 100644 kvm_msr_buf_reset(cpu); -@@ -3438,6 +3439,9 @@ static int kvm_get_msrs(X86CPU *cpu) +@@ -3499,6 +3500,9 @@ static int kvm_get_msrs(X86CPU *cpu) break; case MSR_KVM_ASYNC_PF_EN: env->async_pf_en_msr = msrs[i].data; @@ -938,6 +944,29 @@ index a2934dda02..19bc39b9e3 100644 break; case MSR_KVM_ASYNC_PF_INT: env->async_pf_int_msr = msrs[i].data; +diff --git a/tests/qtest/pvpanic-test.c b/tests/qtest/pvpanic-test.c +index 6dcad2db49..580c2c43d2 100644 +--- a/tests/qtest/pvpanic-test.c ++++ b/tests/qtest/pvpanic-test.c +@@ -17,7 +17,7 @@ static void test_panic_nopause(void) + QDict *response, *data; + QTestState *qts; + +- qts = qtest_init("-device pvpanic -action panic=none"); ++ qts = qtest_init("-M q35 -device pvpanic -action panic=none"); + + val = qtest_inb(qts, 0x505); + g_assert_cmpuint(val, ==, 3); +@@ -40,7 +40,8 @@ static void test_panic(void) + QDict *response, *data; + QTestState *qts; + +- qts = qtest_init("-device pvpanic -action panic=pause"); ++ /* RHEL: Use q35 */ ++ qts = qtest_init("-M q35 -device pvpanic -action panic=pause"); + + val = qtest_inb(qts, 0x505); + g_assert_cmpuint(val, ==, 3); -- -2.18.4 +2.27.0 diff --git a/0012-Enable-make-check.patch b/0011-Enable-make-check.patch similarity index 65% rename from 0012-Enable-make-check.patch rename to 0011-Enable-make-check.patch index 906bb4e..b3af9a8 100644 --- a/0012-Enable-make-check.patch +++ b/0011-Enable-make-check.patch @@ -1,4 +1,4 @@ -From 7b8ca8c1cbd3763900e3e472556116c9832e06f8 Mon Sep 17 00:00:00 2001 +From 5f6a55a218029af944a8d02ab9264647315890d3 Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Wed, 2 Sep 2020 09:39:41 +0200 Subject: Enable make check @@ -7,88 +7,87 @@ Fixing tests after device disabling and machine types changes and enabling make check run during build. Signed-off-by: Miroslav Rezanina - -Rebase changes (4.0.0): -- Remove testing for pseries-2.7 in endianess test -- Disable device-plug-test on s390x as it use disabled device -- Do not run cpu-plug-tests on 7.3 and older machine types - -Rebase changes (4.1.0-rc0): -- removed iotests 068 - -Rebase changes (4.1.0-rc1): -- remove all 205 tests (unstable) - -Rebase changes (4.2.0-rc0): -- partially disable hd-geo-test (requires lsi53c895a) - -Rebase changes (5.1.0-rc1): -- Disable qtest/q35-test (uses upstream machine types) -- Do not run iotests on make checka -- Enabled iotests 071 and 099 - -Rebase changes (5.2.0 rc0): -- Disable cdrom tests (unsupported devices) on x86_64 -- disable fuzz test - -Merged patches (4.0.0): -- f7ffd13 Remove 7 qcow2 and luks iotests that are taking > 25 sec to run during the fast train build proce - -Merged patches (4.1.0-rc0): -- 41288ff redhat: Remove raw iotest 205 - -Conflicts: - redhat/qemu-kvm.spec.template --- - redhat/qemu-kvm.spec.template | 4 ++-- - tests/qemu-iotests/051 | 12 ++++++------ + redhat/qemu-kvm.spec.template | 6 ++---- + tests/qemu-iotests/051 | 8 ++++---- + tests/qtest/bios-tables-test.c | 6 +++--- tests/qtest/boot-serial-test.c | 6 +++++- - tests/qtest/cdrom-test.c | 2 ++ + tests/qtest/cdrom-test.c | 4 ++++ tests/qtest/cpu-plug-test.c | 4 ++-- tests/qtest/e1000-test.c | 2 ++ + tests/qtest/fuzz-e1000e-test.c | 2 +- + tests/qtest/fuzz-virtio-scsi-test.c | 2 +- tests/qtest/hd-geo-test.c | 4 ++++ - tests/qtest/meson.build | 10 ++-------- + tests/qtest/libqos/meson.build | 2 +- + tests/qtest/lpc-ich9-test.c | 2 +- + tests/qtest/meson.build | 11 +++-------- tests/qtest/prom-env-test.c | 4 ++++ tests/qtest/test-x86-cpuid-compat.c | 2 ++ tests/qtest/usb-hcd-xhci-test.c | 4 ++++ - 11 files changed, 35 insertions(+), 19 deletions(-) + tests/unit/meson.build | 2 +- + 17 files changed, 44 insertions(+), 27 deletions(-) diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 -index bee26075b2..61d25c4ed7 100755 +index 7bf29343d7..fd63402d78 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 -@@ -183,11 +183,11 @@ run_qemu -drive if=virtio +@@ -174,9 +174,9 @@ run_qemu -drive if=virtio case "$QEMU_DEFAULT_MACHINE" in pc) run_qemu -drive if=none,id=disk -device ide-cd,drive=disk - run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk +# run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk - run_qemu -drive if=none,id=disk -device ide-drive,drive=disk run_qemu -drive if=none,id=disk -device ide-hd,drive=disk -- run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk - run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk -+# run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk +# run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk ;; *) ;; -@@ -236,11 +236,11 @@ run_qemu -drive file="$TEST_IMG",if=virtio,readonly=on +@@ -225,9 +225,9 @@ run_qemu -drive file="$TEST_IMG",if=virtio,readonly=on case "$QEMU_DEFAULT_MACHINE" in pc) run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-cd,drive=disk - run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk +# run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk - run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-drive,drive=disk run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-hd,drive=disk -- run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk - run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk -+# run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk +# run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk ;; *) ;; +diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c +index 156d4174aa..b4a1074b77 100644 +--- a/tests/qtest/bios-tables-test.c ++++ b/tests/qtest/bios-tables-test.c +@@ -1299,7 +1299,7 @@ static void test_acpi_virt_tcg_numamem(void) + free_test_data(&data); + + } +- ++#if 0 /* Disabled for Red Hat Enterprise Linux */ + static void test_acpi_virt_tcg_pxb(void) + { + test_data data = { +@@ -1331,7 +1331,7 @@ static void test_acpi_virt_tcg_pxb(void) + + free_test_data(&data); + } +- ++#endif + static void test_acpi_tcg_acpi_hmat(const char *machine) + { + test_data data; +@@ -1561,7 +1561,7 @@ int main(int argc, char *argv[]) + qtest_add_func("acpi/virt", test_acpi_virt_tcg); + qtest_add_func("acpi/virt/numamem", test_acpi_virt_tcg_numamem); + qtest_add_func("acpi/virt/memhp", test_acpi_virt_tcg_memhp); +- qtest_add_func("acpi/virt/pxb", test_acpi_virt_tcg_pxb); ++/* qtest_add_func("acpi/virt/pxb", test_acpi_virt_tcg_pxb); */ + qtest_add_func("acpi/virt/oem-fields", test_acpi_oem_fields_virt); + } + ret = g_test_run(); diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c -index b6b1c23cd0..cefa1b38b7 100644 +index d74509b1c5..a64c55e384 100644 --- a/tests/qtest/boot-serial-test.c +++ b/tests/qtest/boot-serial-test.c @@ -120,19 +120,23 @@ static testdef_t tests[] = { @@ -117,7 +116,7 @@ index b6b1c23cd0..cefa1b38b7 100644 { "sparc", "LX", "", "TMS390S10" }, { "sparc", "SS-4", "", "MB86904" }, diff --git a/tests/qtest/cdrom-test.c b/tests/qtest/cdrom-test.c -index 5af944a5fb..cd5b8e0f16 100644 +index 5af944a5fb..69d9bac38a 100644 --- a/tests/qtest/cdrom-test.c +++ b/tests/qtest/cdrom-test.c @@ -140,6 +140,7 @@ static void add_x86_tests(void) @@ -136,6 +135,22 @@ index 5af944a5fb..cd5b8e0f16 100644 } static void add_s390x_tests(void) +@@ -220,6 +222,7 @@ int main(int argc, char **argv) + "magnum", "malta", "pica61", NULL + }; + add_cdrom_param_tests(mips64machines); ++#if 0 /* Disabled for Red Hat Enterprise Linux */ + } else if (g_str_equal(arch, "arm") || g_str_equal(arch, "aarch64")) { + const char *armmachines[] = { + "realview-eb", "realview-eb-mpcore", "realview-pb-a8", +@@ -227,6 +230,7 @@ int main(int argc, char **argv) + "vexpress-a9", "virt", NULL + }; + add_cdrom_param_tests(armmachines); ++#endif + } else { + const char *nonemachine[] = { "none", NULL }; + add_cdrom_param_tests(nonemachine); diff --git a/tests/qtest/cpu-plug-test.c b/tests/qtest/cpu-plug-test.c index a1c689414b..a8f076711c 100644 --- a/tests/qtest/cpu-plug-test.c @@ -167,6 +182,32 @@ index ea286d1793..a1847ac8ed 100644 }; static void *e1000_get_driver(void *obj, const char *interface) +diff --git a/tests/qtest/fuzz-e1000e-test.c b/tests/qtest/fuzz-e1000e-test.c +index 66229e6096..947fba73b7 100644 +--- a/tests/qtest/fuzz-e1000e-test.c ++++ b/tests/qtest/fuzz-e1000e-test.c +@@ -17,7 +17,7 @@ static void test_lp1879531_eth_get_rss_ex_dst_addr(void) + { + QTestState *s; + +- s = qtest_init("-nographic -monitor none -serial none -M pc-q35-5.0"); ++ s = qtest_init("-nographic -monitor none -serial none -M pc-q35-rhel8.4.0"); + + qtest_outl(s, 0xcf8, 0x80001010); + qtest_outl(s, 0xcfc, 0xe1020000); +diff --git a/tests/qtest/fuzz-virtio-scsi-test.c b/tests/qtest/fuzz-virtio-scsi-test.c +index aaf6d10e18..43727d62ac 100644 +--- a/tests/qtest/fuzz-virtio-scsi-test.c ++++ b/tests/qtest/fuzz-virtio-scsi-test.c +@@ -19,7 +19,7 @@ static void test_mmio_oob_from_memory_region_cache(void) + { + QTestState *s; + +- s = qtest_init("-M pc-q35-5.2 -display none -m 512M " ++ s = qtest_init("-M pc-q35-rhel8.4.0 -display none -m 512M " + "-device virtio-scsi,num_queues=8,addr=03.0 "); + + qtest_outl(s, 0xcf8, 0x80001811); diff --git a/tests/qtest/hd-geo-test.c b/tests/qtest/hd-geo-test.c index f7b7cfbc2d..99cccf8638 100644 --- a/tests/qtest/hd-geo-test.c @@ -199,20 +240,45 @@ index f7b7cfbc2d..99cccf8638 100644 qtest_add_func("hd-geo/override/virtio_blk", test_override_virtio_blk); qtest_add_func("hd-geo/override/zero_chs", test_override_zero_chs); qtest_add_func("hd-geo/override/scsi_hot_unplug", +diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build +index 1cddf5bdaa..2f4a564105 100644 +--- a/tests/qtest/libqos/meson.build ++++ b/tests/qtest/libqos/meson.build +@@ -41,7 +41,7 @@ libqos_srcs = files('../libqtest.c', + 'virtio-serial.c', + + # qgraph machines: +- 'aarch64-xlnx-zcu102-machine.c', ++# 'aarch64-xlnx-zcu102-machine.c', + 'arm-imx25-pdk-machine.c', + 'arm-n800-machine.c', + 'arm-raspi2-machine.c', +diff --git a/tests/qtest/lpc-ich9-test.c b/tests/qtest/lpc-ich9-test.c +index fe0bef9980..7a9d51579b 100644 +--- a/tests/qtest/lpc-ich9-test.c ++++ b/tests/qtest/lpc-ich9-test.c +@@ -15,7 +15,7 @@ static void test_lp1878642_pci_bus_get_irq_level_assert(void) + { + QTestState *s; + +- s = qtest_init("-M pc-q35-5.0 " ++ s = qtest_init("-M pc-q35-rhel8.4.0 " + "-nographic -monitor none -serial none"); + + qtest_outl(s, 0xcf8, 0x8000f840); /* PMBASE */ diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build -index c19f1c8503..15ed460ff0 100644 +index 0c76738921..b9a7426a7b 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build -@@ -51,16 +51,13 @@ qtests_i386 = \ +@@ -71,7 +71,6 @@ qtests_i386 = \ 'ide-test', 'hd-geo-test', 'boot-order-test', - 'bios-tables-test', 'rtc-test', 'i440fx-test', -- 'fuzz-test', 'fw_cfg-test', - 'device-plug-test', +@@ -79,7 +78,6 @@ qtests_i386 = \ 'drive_del-test', 'tco-test', 'cpu-plug-test', @@ -220,7 +286,7 @@ index c19f1c8503..15ed460ff0 100644 'vmgenid-test', 'migration-test', 'test-x86-cpuid-compat', -@@ -111,17 +108,15 @@ qtests_moxie = [ 'boot-serial-test' ] +@@ -130,17 +128,15 @@ qtests_moxie = [ 'boot-serial-test' ] qtests_ppc = \ (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \ @@ -240,7 +306,16 @@ index c19f1c8503..15ed460ff0 100644 qtests_pci + ['migration-test', 'numa-test', 'cpu-plug-test', 'drive_del-test'] qtests_sh4 = (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) -@@ -164,7 +159,6 @@ qtests_s390x = \ +@@ -183,7 +179,7 @@ qtests_aarch64 = \ + ['arm-cpu-features', + 'numa-test', + 'boot-serial-test', +- 'xlnx-can-test', ++# 'xlnx-can-test', + 'migration-test'] + + qtests_s390x = \ +@@ -192,7 +188,6 @@ qtests_s390x = \ (config_host.has_key('CONFIG_POSIX') ? ['test-filter-redirector'] : []) + \ ['boot-serial-test', 'drive_del-test', @@ -268,11 +343,11 @@ index f41d80154a..f8dc478ce8 100644 add_tests(sparc_machines); } else if (!strcmp(arch, "sparc64")) { diff --git a/tests/qtest/test-x86-cpuid-compat.c b/tests/qtest/test-x86-cpuid-compat.c -index 7ca1883a29..983aa0719a 100644 +index f28848e06e..6b2fd398a2 100644 --- a/tests/qtest/test-x86-cpuid-compat.c +++ b/tests/qtest/test-x86-cpuid-compat.c @@ -300,6 +300,7 @@ int main(int argc, char **argv) - "-cpu 486,xlevel2=0xC0000002,+xstore", + "-cpu 486,xlevel2=0xC0000002,xstore=on", "xlevel2", 0xC0000002); +#if 0 /* Disabled in Red Hat Enterprise Linux */ @@ -281,7 +356,7 @@ index 7ca1883a29..983aa0719a 100644 @@ -350,6 +351,7 @@ int main(int argc, char **argv) add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.4/npt-on", - "-machine pc-i440fx-2.4 -cpu SandyBridge,+svm,+npt", + "-machine pc-i440fx-2.4 -cpu SandyBridge,svm=on,npt=on", "xlevel", 0x80000008); +#endif @@ -317,6 +392,19 @@ index 10ef9d2a91..3855873050 100644 qtest_add_func("/xhci/pci/hotplug/usb-ccid", test_usb_ccid_hotplug); qtest_start("-device nec-usb-xhci,id=xhci" +diff --git a/tests/unit/meson.build b/tests/unit/meson.build +index b3bc2109da..244d35f5d4 100644 +--- a/tests/unit/meson.build ++++ b/tests/unit/meson.build +@@ -65,7 +65,7 @@ if have_block + 'test-blockjob': [testblock], + 'test-blockjob-txn': [testblock], + 'test-block-backend': [testblock], +- 'test-block-iothread': [testblock], ++# 'test-block-iothread': [testblock], + 'test-write-threshold': [testblock], + 'test-crypto-hash': [crypto], + 'test-crypto-hmac': [crypto], -- -2.18.4 +2.27.0 diff --git a/0013-vfio-cap-number-of-devices-that-can-be-assigned.patch b/0012-vfio-cap-number-of-devices-that-can-be-assigned.patch similarity index 85% rename from 0013-vfio-cap-number-of-devices-that-can-be-assigned.patch rename to 0012-vfio-cap-number-of-devices-that-can-be-assigned.patch index 9575257..45abe27 100644 --- a/0013-vfio-cap-number-of-devices-that-can-be-assigned.patch +++ b/0012-vfio-cap-number-of-devices-that-can-be-assigned.patch @@ -1,4 +1,4 @@ -From da70823afbdbb904950068fe5f0323ff75b0d4fc Mon Sep 17 00:00:00 2001 +From 22c0f47f02c5db63f3857dabc6cc7cb6bfc78158 Mon Sep 17 00:00:00 2001 From: Bandan Das Date: Tue, 3 Dec 2013 20:05:13 +0100 Subject: vfio: cap number of devices that can be assigned @@ -23,25 +23,16 @@ matches the number of slots on a PCI bus and is also a nice power of two. Signed-off-by: Bandan Das - -Rebase notes (2.8.0): -- removed return value for vfio_realize (commit 1a22aca) - -Merged patches (2.9.0): -- 17eb774 vfio: Use error_setg when reporting max assigned device overshoot - - Merged patches (4.1.0-rc3): -- 2b89558 vfio: increase the cap on number of assigned devices to 64 --- hw/vfio/pci.c | 29 ++++++++++++++++++++++++++++- hw/vfio/pci.h | 1 + 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index 51dc373695..06ce2a39aa 100644 +index 5c65aa0a98..327b86703a 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c -@@ -45,6 +45,9 @@ +@@ -46,6 +46,9 @@ #define TYPE_VFIO_PCI_NOHOTPLUG "vfio-pci-nohotplug" @@ -51,7 +42,7 @@ index 51dc373695..06ce2a39aa 100644 static void vfio_disable_interrupts(VFIOPCIDevice *vdev); static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled); -@@ -2768,9 +2771,30 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) +@@ -2783,9 +2786,30 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) ssize_t len; struct stat st; int groupid; @@ -83,7 +74,7 @@ index 51dc373695..06ce2a39aa 100644 if (!vdev->vbasedev.sysfsdev) { if (!(~vdev->host.domain || ~vdev->host.bus || ~vdev->host.slot || ~vdev->host.function)) { -@@ -3207,6 +3231,9 @@ static Property vfio_pci_dev_properties[] = { +@@ -3222,6 +3246,9 @@ static Property vfio_pci_dev_properties[] = { DEFINE_PROP_BOOL("x-no-kvm-msix", VFIOPCIDevice, no_kvm_msix, false), DEFINE_PROP_BOOL("x-no-geforce-quirks", VFIOPCIDevice, no_geforce_quirks, false), @@ -94,7 +85,7 @@ index 51dc373695..06ce2a39aa 100644 false), DEFINE_PROP_BOOL("x-no-vfio-ioeventfd", VFIOPCIDevice, no_vfio_ioeventfd, diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h -index 1574ef983f..fef907c112 100644 +index 64777516d1..e0fe6ca97e 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -139,6 +139,7 @@ struct VFIOPCIDevice { @@ -106,5 +97,5 @@ index 1574ef983f..fef907c112 100644 uint32_t device_id; uint32_t sub_vendor_id; -- -2.18.4 +2.27.0 diff --git a/0014-Add-support-statement-to-help-output.patch b/0013-Add-support-statement-to-help-output.patch similarity index 88% rename from 0014-Add-support-statement-to-help-output.patch rename to 0013-Add-support-statement-to-help-output.patch index 04d89d8..8739e82 100644 --- a/0014-Add-support-statement-to-help-output.patch +++ b/0013-Add-support-statement-to-help-output.patch @@ -1,4 +1,4 @@ -From f69c3b855ec419b4afe240bbd039141a59aad808 Mon Sep 17 00:00:00 2001 +From ffd8eff2ce1d7eda81d425324593924c098f6c39 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 4 Dec 2013 18:53:17 +0100 Subject: Add support statement to -help output @@ -21,10 +21,10 @@ Signed-off-by: Eduardo Habkost 1 file changed, 9 insertions(+) diff --git a/softmmu/vl.c b/softmmu/vl.c -index e6e0ad5a92..065d52e8dc 100644 +index aadb526138..6c8498022b 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c -@@ -1688,9 +1688,17 @@ static void version(void) +@@ -848,9 +848,17 @@ static void version(void) QEMU_COPYRIGHT "\n"); } @@ -42,7 +42,7 @@ index e6e0ad5a92..065d52e8dc 100644 printf("usage: %s [options] [disk_image]\n\n" "'disk_image' is a raw hard disk image for IDE hard disk 0\n\n", error_get_progname()); -@@ -1707,6 +1715,7 @@ static void help(int exitcode) +@@ -867,6 +875,7 @@ static void help(int exitcode) "\n" QEMU_HELP_BOTTOM "\n"); @@ -51,5 +51,5 @@ index e6e0ad5a92..065d52e8dc 100644 } -- -2.18.4 +2.27.0 diff --git a/0015-globally-limit-the-maximum-number-of-CPUs.patch b/0014-globally-limit-the-maximum-number-of-CPUs.patch similarity index 63% rename from 0015-globally-limit-the-maximum-number-of-CPUs.patch rename to 0014-globally-limit-the-maximum-number-of-CPUs.patch index 4a65df5..b44ad7c 100644 --- a/0015-globally-limit-the-maximum-number-of-CPUs.patch +++ b/0014-globally-limit-the-maximum-number-of-CPUs.patch @@ -1,4 +1,4 @@ -From 9585c8927744d8b07b317063ef788e1f01773f0e Mon Sep 17 00:00:00 2001 +From b5dab6e678d9b53359b3a915421114258e803cad Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 21 Jan 2014 10:46:52 +0100 Subject: globally limit the maximum number of CPUs @@ -13,35 +13,15 @@ default and minimize the ppc hack in kvm-all.c. Signed-off-by: David Hildenbrand Signed-off-by: Miroslav Rezanina Signed-off-by: Danilo Cesar Lemes de Paula - -Rebase notes (2.11.0): -- Removed CONFIG_RHV reference -- Update commit log - -Merged patches (2.11.0): -- 92fef14623 redhat: remove manual max_cpus limitations for ppc -- bb722e9eff redhat: globally limit the maximum number of CPUs -- fdeef3c1c7 RHEL: Set vcpus hard limit to 240 for Power -- 0584216921 Match POWER max cpus to x86 - -Signed-off-by: Andrew Jones - -Merged patches (5.1.0): -- redhat: globally limit the maximum number of CPUs -- redhat: remove manual max_cpus limitations for ppc -- use recommended max vcpu count - -Merged patches (5.2.0 rc0): -- f8a4123 vl: Remove downstream-only MAX_RHEL_CPUS code --- accel/kvm/kvm-all.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index baaa54249d..a1fbda0945 100644 +index b6d9f92f15..70a94ba76d 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c -@@ -2108,6 +2108,18 @@ static int kvm_init(MachineState *ms) +@@ -2095,6 +2095,18 @@ static int kvm_init(MachineState *ms) soft_vcpus_limit = kvm_recommended_vcpus(s); hard_vcpus_limit = kvm_max_vcpus(s); @@ -61,5 +41,5 @@ index baaa54249d..a1fbda0945 100644 if (nc->num > soft_vcpus_limit) { warn_report("Number of %s cpus requested (%d) exceeds " -- -2.18.4 +2.27.0 diff --git a/0016-Use-qemu-kvm-in-documentation-instead-of-qemu-system.patch b/0015-Use-qemu-kvm-in-documentation-instead-of-qemu-system.patch similarity index 91% rename from 0016-Use-qemu-kvm-in-documentation-instead-of-qemu-system.patch rename to 0015-Use-qemu-kvm-in-documentation-instead-of-qemu-system.patch index 67f920a..599e101 100644 --- a/0016-Use-qemu-kvm-in-documentation-instead-of-qemu-system.patch +++ b/0015-Use-qemu-kvm-in-documentation-instead-of-qemu-system.patch @@ -1,4 +1,4 @@ -From 091f9e47dc4609bfded5474cfe2797777cdd56f1 Mon Sep 17 00:00:00 2001 +From 55fde02ee1a9aa0e812af8534a9adf553accc522 Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Wed, 8 Jul 2020 08:35:50 +0200 Subject: Use qemu-kvm in documentation instead of qemu-system- @@ -16,12 +16,6 @@ We change the name and location of qemu-kvm binaries. Update documentation to reflect this change. Only architectures available in RHEL are updated. Signed-off-by: Miroslav Rezanina - -Rebase notes (5.1.0 rc0): - - qemu-block-drivers.texi converted to qemu-block-drivers.rst (upstream) - -Rebase notes (5.2.0 rc0): - - rewrite patch to new docs structure --- docs/defs.rst.inc | 4 ++-- docs/interop/live-block-operations.rst | 4 ++-- @@ -31,7 +25,7 @@ Rebase notes (5.2.0 rc0): 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/defs.rst.inc b/docs/defs.rst.inc -index 48d05aaf33..d74dbdeca9 100644 +index 52d6454b93..d74dbdeca9 100644 --- a/docs/defs.rst.inc +++ b/docs/defs.rst.inc @@ -9,7 +9,7 @@ @@ -39,13 +33,13 @@ index 48d05aaf33..d74dbdeca9 100644 incorrectly in boldface. -.. |qemu_system| replace:: qemu-system-x86_64 --.. |qemu_system_x86| replace:: qemu_system-x86_64 +-.. |qemu_system_x86| replace:: qemu-system-x86_64 +.. |qemu_system| replace:: qemu-kvm +.. |qemu_system_x86| replace:: qemu-kvm .. |I2C| replace:: I\ :sup:`2`\ C .. |I2S| replace:: I\ :sup:`2`\ S diff --git a/docs/interop/live-block-operations.rst b/docs/interop/live-block-operations.rst -index e13f5a21f8..6650b2c975 100644 +index 1073b930dc..881432253f 100644 --- a/docs/interop/live-block-operations.rst +++ b/docs/interop/live-block-operations.rst @@ -129,7 +129,7 @@ To show some example invocations of command-line, we will use the @@ -125,10 +119,10 @@ index fb70445c75..0d9a783112 100644 See also -------- diff --git a/docs/tools/virtiofsd.rst b/docs/tools/virtiofsd.rst -index 866b7db3ee..5b3be8a6d6 100644 +index 00554c75bd..6e0fc94005 100644 --- a/docs/tools/virtiofsd.rst +++ b/docs/tools/virtiofsd.rst -@@ -297,7 +297,7 @@ Export ``/var/lib/fs/vm001/`` on vhost-user UNIX domain socket +@@ -301,7 +301,7 @@ Export ``/var/lib/fs/vm001/`` on vhost-user UNIX domain socket :: host# virtiofsd --socket-path=/var/run/vm001-vhost-fs.sock -o source=/var/lib/fs/vm001 @@ -138,10 +132,10 @@ index 866b7db3ee..5b3be8a6d6 100644 -device vhost-user-fs-pci,chardev=char0,tag=myfs \ -object memory-backend-memfd,id=mem,size=4G,share=on \ diff --git a/qemu-options.hx b/qemu-options.hx -index 363a15b4e8..5e5e265331 100644 +index 0d4fb61bf7..79ca09feac 100644 --- a/qemu-options.hx +++ b/qemu-options.hx -@@ -2935,11 +2935,11 @@ SRST +@@ -3011,11 +3011,11 @@ SRST :: @@ -159,5 +153,5 @@ index 363a15b4e8..5e5e265331 100644 ``-netdev vhost-vdpa,vhostdev=/path/to/dev`` Establish a vhost-vdpa netdev. -- -2.18.4 +2.27.0 diff --git a/0017-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch b/0016-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch similarity index 92% rename from 0017-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch rename to 0016-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch index 7ab1831..cd00b4f 100644 --- a/0017-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch +++ b/0016-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch @@ -1,4 +1,4 @@ -From 4d69dc90e66deec6bc6b46074ee44ef8c902266b Mon Sep 17 00:00:00 2001 +From 2ab1a61510036bd409532f24ea14fa693ec0362c Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 14 Jun 2017 15:37:01 +0200 Subject: virtio-scsi: Reject scsi-cd if data plane enabled [RHEL only] @@ -42,11 +42,11 @@ Signed-off-by: Danilo C. L. de Paula 1 file changed, 9 insertions(+) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c -index 3db9a8aae9..82c025146d 100644 +index 6d80730287..bba3d75707 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c -@@ -823,6 +823,15 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, - SCSIDevice *sd = SCSI_DEVICE(dev); +@@ -896,6 +896,15 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, + AioContext *old_context; int ret; + /* XXX: Remove this check once block backend is capable of handling @@ -62,5 +62,5 @@ index 3db9a8aae9..82c025146d 100644 if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) { return; -- -2.18.4 +2.27.0 diff --git a/0018-BZ1653590-Require-at-least-64kiB-pages-for-downstrea.patch b/0017-BZ1653590-Require-at-least-64kiB-pages-for-downstrea.patch similarity index 92% rename from 0018-BZ1653590-Require-at-least-64kiB-pages-for-downstrea.patch rename to 0017-BZ1653590-Require-at-least-64kiB-pages-for-downstrea.patch index 6c16c93..2e670a2 100644 --- a/0018-BZ1653590-Require-at-least-64kiB-pages-for-downstrea.patch +++ b/0017-BZ1653590-Require-at-least-64kiB-pages-for-downstrea.patch @@ -1,4 +1,4 @@ -From 18c5a8c24e22b7c2ba9f7e26cac190cefc7ecf26 Mon Sep 17 00:00:00 2001 +From 7b3d9142f3b296b127dce35336765dc16265d155 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 6 Feb 2019 03:58:56 +0000 Subject: BZ1653590: Require at least 64kiB pages for downstream guests & hosts @@ -32,10 +32,10 @@ Signed-off-by: Danilo C. L. de Paula 1 file changed, 7 insertions(+) diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index 9341e9782a..f11428eae9 100644 +index 9ea7ddd1e9..1338b677d2 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c -@@ -333,12 +333,19 @@ bool spapr_check_pagesize(SpaprMachineState *spapr, hwaddr pagesize, +@@ -332,12 +332,19 @@ bool spapr_check_pagesize(SpaprMachineState *spapr, hwaddr pagesize, static void cap_hpt_maxpagesize_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { @@ -56,5 +56,5 @@ index 9341e9782a..f11428eae9 100644 spapr_check_pagesize(spapr, qemu_minrampagesize(), errp); } -- -2.18.4 +2.27.0 diff --git a/0019-block-Versioned-x-blockdev-reopen-API-with-feature-f.patch b/0018-block-Versioned-x-blockdev-reopen-API-with-feature-f.patch similarity index 72% rename from 0019-block-Versioned-x-blockdev-reopen-API-with-feature-f.patch rename to 0018-block-Versioned-x-blockdev-reopen-API-with-feature-f.patch index c644891..b5e8f92 100644 --- a/0019-block-Versioned-x-blockdev-reopen-API-with-feature-f.patch +++ b/0018-block-Versioned-x-blockdev-reopen-API-with-feature-f.patch @@ -1,4 +1,4 @@ -From 989cfded8fdd5df3b6b1f1a304ca16c128d7561b Mon Sep 17 00:00:00 2001 +From acdc84c1077be7d347414f781014ea785ce41d7b Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 13 Mar 2020 12:34:32 +0000 Subject: block: Versioned x-blockdev-reopen API with feature flag @@ -26,13 +26,14 @@ Signed-off-by: Kevin Wolf Signed-off-by: Danilo C. L. de Paula --- qapi/block-core.json | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) + scripts/qapi/expr.py | 2 +- + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json -index 04ad80bc1e..2a7dca299f 100644 +index 6d227924d0..15ad8cee05 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json -@@ -4143,10 +4143,17 @@ +@@ -4166,10 +4166,17 @@ # image does not have a default backing file name as part of its # metadata. # @@ -51,6 +52,19 @@ index 04ad80bc1e..2a7dca299f 100644 ## # @blockdev-del: +diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py +index 540b3982b1..884874d205 100644 +--- a/scripts/qapi/expr.py ++++ b/scripts/qapi/expr.py +@@ -215,7 +215,7 @@ def check_features(features, info): + check_keys(f, info, source, ['name'], ['if']) + check_name_is_str(f['name'], info, source) + source = "%s '%s'" % (source, f['name']) +- check_name_lower(f['name'], info, source) ++ check_name_lower(f['name'], info, source, permit_underscore=True) + check_if(f, info, source) + + -- -2.18.4 +2.27.0 diff --git a/0021-redhat-Define-hw_compat_8_3.patch b/0021-redhat-Define-hw_compat_8_3.patch deleted file mode 100644 index a5ca2c6..0000000 --- a/0021-redhat-Define-hw_compat_8_3.patch +++ /dev/null @@ -1,70 +0,0 @@ -From fa0063ba67071384d8c749cee8f4f4e5bbc8ef91 Mon Sep 17 00:00:00 2001 -From: Greg Kurz -Date: Fri, 20 Nov 2020 14:00:31 -0500 -Subject: redhat: Define hw_compat_8_3 - -RH-Author: Greg Kurz -Message-id: <20201120140033.578472-2-gkurz@redhat.com> -Patchwork-id: 99790 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 1/3] redhat: Define hw_compat_8_3 -Bugzilla: 1893935 -RH-Acked-by: Danilo de Paula -RH-Acked-by: Laurent Vivier -RH-Acked-by: David Gibson - -Signed-off-by: Greg Kurz -Signed-off-by: Danilo C. L. de Paula ---- - hw/core/machine.c | 21 +++++++++++++++++++++ - include/hw/boards.h | 3 +++ - 2 files changed, 24 insertions(+) - -diff --git a/hw/core/machine.c b/hw/core/machine.c -index 19d50dde45..aba05ad676 100644 ---- a/hw/core/machine.c -+++ b/hw/core/machine.c -@@ -28,6 +28,27 @@ - #include "hw/mem/nvdimm.h" - #include "migration/vmstate.h" - -+/* -+ * The same as hw_compat_5_1 -+ */ -+GlobalProperty hw_compat_rhel_8_3[] = { -+ /* hw_compat_rhel_8_3 from hw_compat_5_1 */ -+ { "vhost-scsi", "num_queues", "1"}, -+ /* hw_compat_rhel_8_3 from hw_compat_5_1 */ -+ { "vhost-user-blk", "num-queues", "1"}, -+ /* hw_compat_rhel_8_3 from hw_compat_5_1 */ -+ { "vhost-user-scsi", "num_queues", "1"}, -+ /* hw_compat_rhel_8_3 from hw_compat_5_1 */ -+ { "virtio-blk-device", "num-queues", "1"}, -+ /* hw_compat_rhel_8_3 from hw_compat_5_1 */ -+ { "virtio-scsi-device", "num_queues", "1"}, -+ /* hw_compat_rhel_8_3 from hw_compat_5_1 */ -+ { "nvme", "use-intel-id", "on"}, -+ /* hw_compat_rhel_8_3 from hw_compat_5_1 */ -+ { "pvpanic", "events", "1"}, /* PVPANIC_PANICKED */ -+}; -+const size_t hw_compat_rhel_8_3_len = G_N_ELEMENTS(hw_compat_rhel_8_3); -+ - /* - * The same as hw_compat_4_2 + hw_compat_5_0 - */ -diff --git a/include/hw/boards.h b/include/hw/boards.h -index 4e4a54b313..526e5aea04 100644 ---- a/include/hw/boards.h -+++ b/include/hw/boards.h -@@ -369,6 +369,9 @@ extern const size_t hw_compat_2_2_len; - extern GlobalProperty hw_compat_2_1[]; - extern const size_t hw_compat_2_1_len; - -+extern GlobalProperty hw_compat_rhel_8_3[]; -+extern const size_t hw_compat_rhel_8_3_len; -+ - extern GlobalProperty hw_compat_rhel_8_2[]; - extern const size_t hw_compat_rhel_8_2_len; - --- -2.18.4 - diff --git a/0022-redhat-Add-spapr_machine_rhel_default_class_options.patch b/0022-redhat-Add-spapr_machine_rhel_default_class_options.patch deleted file mode 100644 index f77916f..0000000 --- a/0022-redhat-Add-spapr_machine_rhel_default_class_options.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 943c936df3b6b5c3197ad727f2105e61778e749a Mon Sep 17 00:00:00 2001 -From: Greg Kurz -Date: Fri, 20 Nov 2020 14:00:32 -0500 -Subject: redhat: Add spapr_machine_rhel_default_class_options() - -RH-Author: Greg Kurz -Message-id: <20201120140033.578472-3-gkurz@redhat.com> -Patchwork-id: 99791 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 2/3] redhat: Add spapr_machine_rhel_default_class_options() -Bugzilla: 1893935 -RH-Acked-by: Danilo de Paula -RH-Acked-by: Laurent Vivier -RH-Acked-by: David Gibson - -RHEL may need to override some default property inherited from upstream. -This is currently handled in the class_options() function of the latest -machine type, and thus the defaults need to be carried around each time -we add a new RHEL machine. - -Override the defaults in a dedicated function to be called by the -latest RHEL machine type. - -Signed-off-by: Greg Kurz -Signed-off-by: Danilo C. L. de Paula ---- - hw/ppc/spapr.c | 17 +++++++++++++---- - 1 file changed, 13 insertions(+), 4 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 4a838cc955..1d7482b2fb 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -4961,6 +4961,17 @@ static void spapr_machine_2_1_class_options(MachineClass *mc) - DEFINE_SPAPR_MACHINE(2_1, "2.1", false); - #endif - -+static void spapr_machine_rhel_default_class_options(MachineClass *mc) -+{ -+ /* -+ * Defaults for the latest behaviour inherited from the base class -+ * can be overriden here for all pseries-rhel* machines. -+ */ -+ -+ /* Maximum supported VCPU count */ -+ mc->max_cpus = 384; -+} -+ - /* - * pseries-rhel8.3.0 - * like pseries-5.1 -@@ -4968,10 +4979,8 @@ DEFINE_SPAPR_MACHINE(2_1, "2.1", false); - - static void spapr_machine_rhel830_class_options(MachineClass *mc) - { -- /* Defaults for the latest behaviour inherited from the base class */ -- -- /* Maximum supported VCPU count for all pseries-rhel* machines */ -- mc->max_cpus = 384; -+ /* The default machine type must apply the RHEL specific defaults */ -+ spapr_machine_rhel_default_class_options(mc); - } - - DEFINE_SPAPR_MACHINE(rhel830, "rhel8.3.0", true); --- -2.18.4 - diff --git a/0023-redhat-Define-pseries-rhel8.4.0-machine-type.patch b/0023-redhat-Define-pseries-rhel8.4.0-machine-type.patch deleted file mode 100644 index 406c7e1..0000000 --- a/0023-redhat-Define-pseries-rhel8.4.0-machine-type.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 030b5e6fba510b8b9f8c8690ef6ea63f71628d25 Mon Sep 17 00:00:00 2001 -From: Greg Kurz -Date: Fri, 20 Nov 2020 14:00:33 -0500 -Subject: redhat: Define pseries-rhel8.4.0 machine type - -RH-Author: Greg Kurz -Message-id: <20201120140033.578472-4-gkurz@redhat.com> -Patchwork-id: 99792 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 3/3] redhat: Define pseries-rhel8.4.0 machine type -Bugzilla: 1893935 -RH-Acked-by: Danilo de Paula -RH-Acked-by: Laurent Vivier -RH-Acked-by: David Gibson - -From: Greg Kurz - -Signed-off-by: Greg Kurz -Signed-off-by: Danilo C. L. de Paula ---- - hw/ppc/spapr.c | 25 ++++++++++++++++++++++--- - 1 file changed, 22 insertions(+), 3 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 1d7482b2fb..4f61b64a21 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -4972,6 +4972,19 @@ static void spapr_machine_rhel_default_class_options(MachineClass *mc) - mc->max_cpus = 384; - } - -+/* -+ * pseries-rhel8.4.0 -+ * like pseries-5.2 -+ */ -+ -+static void spapr_machine_rhel840_class_options(MachineClass *mc) -+{ -+ /* The default machine type must apply the RHEL specific defaults */ -+ spapr_machine_rhel_default_class_options(mc); -+} -+ -+DEFINE_SPAPR_MACHINE(rhel840, "rhel8.4.0", true); -+ - /* - * pseries-rhel8.3.0 - * like pseries-5.1 -@@ -4979,11 +4992,17 @@ static void spapr_machine_rhel_default_class_options(MachineClass *mc) - - static void spapr_machine_rhel830_class_options(MachineClass *mc) - { -- /* The default machine type must apply the RHEL specific defaults */ -- spapr_machine_rhel_default_class_options(mc); -+ SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc); -+ -+ spapr_machine_rhel840_class_options(mc); -+ compat_props_add(mc->compat_props, hw_compat_rhel_8_3, -+ hw_compat_rhel_8_3_len); -+ -+ /* from pseries-5.1 */ -+ smc->pre_5_2_numa_associativity = true; - } - --DEFINE_SPAPR_MACHINE(rhel830, "rhel8.3.0", true); -+DEFINE_SPAPR_MACHINE(rhel830, "rhel8.3.0", false); - - /* - * pseries-rhel8.2.0 --- -2.18.4 - diff --git a/0024-redhat-s390x-add-rhel-8.4.0-compat-machine.patch b/0024-redhat-s390x-add-rhel-8.4.0-compat-machine.patch deleted file mode 100644 index bedb835..0000000 --- a/0024-redhat-s390x-add-rhel-8.4.0-compat-machine.patch +++ /dev/null @@ -1,72 +0,0 @@ -From a6ae745cceee1acc3667f5ba5e007ca6c083f8a8 Mon Sep 17 00:00:00 2001 -From: Cornelia Huck -Date: Tue, 1 Dec 2020 17:53:41 -0500 -Subject: redhat: s390x: add rhel-8.4.0 compat machine - -RH-Author: Cornelia Huck -Message-id: <20201201175341.37537-3-cohuck@redhat.com> -Patchwork-id: 100195 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 2/2] redhat: s390x: add rhel-8.4.0 compat machine -Bugzilla: 1836282 -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Thomas Huth -RH-Acked-by: David Hildenbrand - -Note that we did not publish a rhel-8.3.0 machine on s390x, so we -need to add the respective hw_compat entry in the rhel-8.2.0 machine. - -Also, the hw_compat entry for 8.1 was missing; however, the contents -there are not relevant for s390x. - -Signed-off-by: Cornelia Huck -Signed-off-by: Danilo C. L. de Paula ---- - hw/s390x/s390-virtio-ccw.c | 17 ++++++++++++++++- - 1 file changed, 16 insertions(+), 1 deletion(-) - -diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c -index b8dde7e4e1..c7b5bcb06b 100644 ---- a/hw/s390x/s390-virtio-ccw.c -+++ b/hw/s390x/s390-virtio-ccw.c -@@ -1056,15 +1056,29 @@ static void ccw_machine_2_4_class_options(MachineClass *mc) - DEFINE_CCW_MACHINE(2_4, "2.4", false); - #endif - -+static void ccw_machine_rhel840_instance_options(MachineState *machine) -+{ -+} -+ -+static void ccw_machine_rhel840_class_options(MachineClass *mc) -+{ -+} -+DEFINE_CCW_MACHINE(rhel840, "rhel8.4.0", true); -+ - static void ccw_machine_rhel820_instance_options(MachineState *machine) - { -+ ccw_machine_rhel840_instance_options(machine); - } - - static void ccw_machine_rhel820_class_options(MachineClass *mc) - { -+ ccw_machine_rhel840_class_options(mc); - mc->fixup_ram_size = s390_fixup_ram_size; -+ /* we did not publish a rhel8.3.0 machine */ -+ compat_props_add(mc->compat_props, hw_compat_rhel_8_3, hw_compat_rhel_8_3_len); -+ compat_props_add(mc->compat_props, hw_compat_rhel_8_2, hw_compat_rhel_8_2_len); - } --DEFINE_CCW_MACHINE(rhel820, "rhel8.2.0", true); -+DEFINE_CCW_MACHINE(rhel820, "rhel8.2.0", false); - - static void ccw_machine_rhel760_instance_options(MachineState *machine) - { -@@ -1086,6 +1100,7 @@ static void ccw_machine_rhel760_class_options(MachineClass *mc) - { - ccw_machine_rhel820_class_options(mc); - /* We never published the s390x version of RHEL-AV 8.0 and 8.1, so add this here */ -+ compat_props_add(mc->compat_props, hw_compat_rhel_8_1, hw_compat_rhel_8_1_len); - compat_props_add(mc->compat_props, hw_compat_rhel_8_0, hw_compat_rhel_8_0_len); - compat_props_add(mc->compat_props, hw_compat_rhel_7_6, hw_compat_rhel_7_6_len); - } --- -2.18.4 - diff --git a/0027-block-vpc-Make-vpc_open-read-the-full-dynamic-header.patch b/0027-block-vpc-Make-vpc_open-read-the-full-dynamic-header.patch deleted file mode 100644 index 7af0b8d..0000000 --- a/0027-block-vpc-Make-vpc_open-read-the-full-dynamic-header.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 974af930d4e5cae5611bb2e3a5ac18d3bda15a68 Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Thu, 17 Dec 2020 17:58:43 +0100 -Subject: block/vpc: Make vpc_open() read the full dynamic header - -The dynamic header's size is 1024 bytes. - -vpc_open() reads only the 512 bytes of the dynamic header into buf[]. -Works, because it doesn't actually access the second half. However, a -colleague told me that GCC 11 warns: - - ../block/vpc.c:358:51: error: array subscript 'struct VHDDynDiskHeader[0]' is partly outside array bounds of 'uint8_t[512]' [-Werror=array-bounds] - -Clean up to read the full header. - -Rename buf[] to dyndisk_header_buf[] while there. - -Signed-off-by: Markus Armbruster ---- - block/vpc.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/block/vpc.c b/block/vpc.c -index 1ab55f9287..2fcf3f6283 100644 ---- a/block/vpc.c -+++ b/block/vpc.c -@@ -220,7 +220,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, - QemuOpts *opts = NULL; - Error *local_err = NULL; - bool use_chs; -- uint8_t buf[HEADER_SIZE]; -+ uint8_t dyndisk_header_buf[1024]; - uint32_t checksum; - uint64_t computed_size; - uint64_t pagetable_size; -@@ -340,14 +340,14 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, - } - - if (disk_type == VHD_DYNAMIC) { -- ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, -- HEADER_SIZE); -+ ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), -+ dyndisk_header_buf, 1024); - if (ret < 0) { - error_setg(errp, "Error reading dynamic VHD header"); - goto fail; - } - -- dyndisk_header = (VHDDynDiskHeader *) buf; -+ dyndisk_header = (VHDDynDiskHeader *)dyndisk_header_buf; - - if (strncmp(dyndisk_header->magic, "cxsparse", 8)) { - error_setg(errp, "Invalid header magic"); --- -2.18.4 - diff --git a/0028-GCC-11-warnings-hacks.patch b/0028-GCC-11-warnings-hacks.patch deleted file mode 100644 index 86ae8c2..0000000 --- a/0028-GCC-11-warnings-hacks.patch +++ /dev/null @@ -1,163 +0,0 @@ -From 6e9564986a00456c6748cf888d9ba9f7f0db01bf Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Mon, 4 Jan 2021 07:47:03 +0100 -Subject: GCC 11 warnings hacks - ---- - hw/scsi/scsi-disk.c | 13 +++++++------ - net/eth.c | 4 +++- - target/s390x/kvm.c | 2 +- - target/s390x/misc_helper.c | 2 +- - tcg/aarch64/tcg-target.c.inc | 3 +-- - tests/test-block-iothread.c | 12 ++++++------ - 6 files changed, 19 insertions(+), 17 deletions(-) - -diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index 90841ad791..8ce77777d3 100644 ---- a/hw/scsi/scsi-disk.c -+++ b/hw/scsi/scsi-disk.c -@@ -2578,14 +2578,15 @@ static void scsi_disk_new_request_dump(uint32_t lun, uint32_t tag, uint8_t *buf) - int len = scsi_cdb_length(buf); - char *line_buffer, *p; - -- line_buffer = g_malloc(len * 5 + 1); -+ if (len > 0) { -+ line_buffer = g_malloc(len * 5 + 1); -+ for (i = 0, p = line_buffer; i < len; i++) { -+ p += sprintf(p, " 0x%02x", buf[i]); -+ } -+ trace_scsi_disk_new_request(lun, tag, line_buffer); - -- for (i = 0, p = line_buffer; i < len; i++) { -- p += sprintf(p, " 0x%02x", buf[i]); -+ g_free(line_buffer); - } -- trace_scsi_disk_new_request(lun, tag, line_buffer); -- -- g_free(line_buffer); - } - - static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, -diff --git a/net/eth.c b/net/eth.c -index 1e0821c5f8..041ac4865a 100644 ---- a/net/eth.c -+++ b/net/eth.c -@@ -405,6 +405,8 @@ _eth_get_rss_ex_dst_addr(const struct iovec *pkt, int pkt_frags, - struct ip6_ext_hdr *ext_hdr, - struct in6_address *dst_addr) - { -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Warray-bounds" - struct ip6_ext_hdr_routing *rthdr = (struct ip6_ext_hdr_routing *) ext_hdr; - - if ((rthdr->rtype == 2) && -@@ -424,7 +426,7 @@ _eth_get_rss_ex_dst_addr(const struct iovec *pkt, int pkt_frags, - - return bytes_read == sizeof(*dst_addr); - } -- -+#pragma GCC diagnostic pop - return false; - } - -diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c -index 1839cc6648..ab1ca6b1bf 100644 ---- a/target/s390x/kvm.c -+++ b/target/s390x/kvm.c -@@ -1918,7 +1918,7 @@ static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar) - */ - if (qemu_name) { - strncpy((char *)sysib.ext_names[0], qemu_name, -- sizeof(sysib.ext_names[0])); -+ sizeof(sysib.ext_names[0])-1); - } else { - strcpy((char *)sysib.ext_names[0], "KVMguest"); - } -diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c -index 58dbc023eb..adaf4145e6 100644 ---- a/target/s390x/misc_helper.c -+++ b/target/s390x/misc_helper.c -@@ -370,7 +370,7 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint64_t r0, uint64_t r1) - MIN(sizeof(sysib.sysib_322.vm[0].name), - strlen(qemu_name))); - strncpy((char *)sysib.sysib_322.ext_names[0], qemu_name, -- sizeof(sysib.sysib_322.ext_names[0])); -+ sizeof(sysib.sysib_322.ext_names[0])-1); - } else { - ebcdic_put(sysib.sysib_322.vm[0].name, "TCGguest", 8); - strcpy((char *)sysib.sysib_322.ext_names[0], "TCGguest"); -diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc -index 26f71cb599..fe6bdbf721 100644 ---- a/tcg/aarch64/tcg-target.c.inc -+++ b/tcg/aarch64/tcg-target.c.inc -@@ -1852,8 +1852,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, - static tcg_insn_unit *tb_ret_addr; - - static void tcg_out_op(TCGContext *s, TCGOpcode opc, -- const TCGArg args[TCG_MAX_OP_ARGS], -- const int const_args[TCG_MAX_OP_ARGS]) -+ const TCGArg *args, const int *const_args) - { - /* 99% of the time, we can signal the use of extension registers - by looking to see if the opcode handles 64-bit data. */ -diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c -index 3f866a35c6..bc64b50e66 100644 ---- a/tests/test-block-iothread.c -+++ b/tests/test-block-iothread.c -@@ -75,7 +75,7 @@ static BlockDriver bdrv_test = { - - static void test_sync_op_pread(BdrvChild *c) - { -- uint8_t buf[512]; -+ uint8_t buf[512] = {0}; - int ret; - - /* Success */ -@@ -89,7 +89,7 @@ static void test_sync_op_pread(BdrvChild *c) - - static void test_sync_op_pwrite(BdrvChild *c) - { -- uint8_t buf[512]; -+ uint8_t buf[512] = {0}; - int ret; - - /* Success */ -@@ -103,7 +103,7 @@ static void test_sync_op_pwrite(BdrvChild *c) - - static void test_sync_op_blk_pread(BlockBackend *blk) - { -- uint8_t buf[512]; -+ uint8_t buf[512] = {0}; - int ret; - - /* Success */ -@@ -117,7 +117,7 @@ static void test_sync_op_blk_pread(BlockBackend *blk) - - static void test_sync_op_blk_pwrite(BlockBackend *blk) - { -- uint8_t buf[512]; -+ uint8_t buf[512] = {0}; - int ret; - - /* Success */ -@@ -131,7 +131,7 @@ static void test_sync_op_blk_pwrite(BlockBackend *blk) - - static void test_sync_op_load_vmstate(BdrvChild *c) - { -- uint8_t buf[512]; -+ uint8_t buf[512] = {0}; - int ret; - - /* Error: Driver does not support snapshots */ -@@ -141,7 +141,7 @@ static void test_sync_op_load_vmstate(BdrvChild *c) - - static void test_sync_op_save_vmstate(BdrvChild *c) - { -- uint8_t buf[512]; -+ uint8_t buf[512] = {0}; - int ret; - - /* Error: Driver does not support snapshots */ --- -2.18.4 - diff --git a/0029-Disable-problematic-tests-for-initial-build.patch b/0029-Disable-problematic-tests-for-initial-build.patch deleted file mode 100644 index 84743b8..0000000 --- a/0029-Disable-problematic-tests-for-initial-build.patch +++ /dev/null @@ -1,41 +0,0 @@ -From bb42f8a495aa0da2410109de14aca901b8c4ac4f Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Tue, 5 Jan 2021 07:40:08 +0100 -Subject: Disable problematic tests for initial build - ---- - tests/meson.build | 2 +- - tests/qtest/meson.build | 4 ++-- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/tests/meson.build b/tests/meson.build -index afeb6be689..e562a0499e 100644 ---- a/tests/meson.build -+++ b/tests/meson.build -@@ -136,7 +136,7 @@ if have_block - 'test-blockjob': [testblock], - 'test-blockjob-txn': [testblock], - 'test-block-backend': [testblock], -- 'test-block-iothread': [testblock], -+# 'test-block-iothread': [testblock], - 'test-write-threshold': [testblock], - 'test-crypto-hash': [crypto], - 'test-crypto-hmac': [crypto], -diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build -index 15ed460ff0..70ef8c236c 100644 ---- a/tests/qtest/meson.build -+++ b/tests/qtest/meson.build -@@ -150,8 +150,8 @@ qtests_aarch64 = \ - (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-swtpm-test'] : []) + \ - ['arm-cpu-features', - 'numa-test', -- 'boot-serial-test', -- 'migration-test'] -+ 'boot-serial-test'] -+# 'migration-test'] - - qtests_s390x = \ - (slirp.found() ? ['pxe-test', 'test-netfilter'] : []) + \ --- -2.18.4 - diff --git a/0030-Revert-GCC-11-warnings-hacks.patch b/0030-Revert-GCC-11-warnings-hacks.patch deleted file mode 100644 index 6f13efa..0000000 --- a/0030-Revert-GCC-11-warnings-hacks.patch +++ /dev/null @@ -1,166 +0,0 @@ -From f488becdbb12c6001a2524d049371196a05f5256 Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Fri, 15 Jan 2021 09:27:40 +0100 -Subject: Revert "GCC 11 warnings hacks" - -This reverts commit 6e9564986a00456c6748cf888d9ba9f7f0db01bf. - -Hacks solved upstream. Going to import upstream solutions. ---- - hw/scsi/scsi-disk.c | 13 ++++++------- - net/eth.c | 4 +--- - target/s390x/kvm.c | 2 +- - target/s390x/misc_helper.c | 2 +- - tcg/aarch64/tcg-target.c.inc | 3 ++- - tests/test-block-iothread.c | 12 ++++++------ - 6 files changed, 17 insertions(+), 19 deletions(-) - -diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index 8ce77777d3..90841ad791 100644 ---- a/hw/scsi/scsi-disk.c -+++ b/hw/scsi/scsi-disk.c -@@ -2578,15 +2578,14 @@ static void scsi_disk_new_request_dump(uint32_t lun, uint32_t tag, uint8_t *buf) - int len = scsi_cdb_length(buf); - char *line_buffer, *p; - -- if (len > 0) { -- line_buffer = g_malloc(len * 5 + 1); -- for (i = 0, p = line_buffer; i < len; i++) { -- p += sprintf(p, " 0x%02x", buf[i]); -- } -- trace_scsi_disk_new_request(lun, tag, line_buffer); -+ line_buffer = g_malloc(len * 5 + 1); - -- g_free(line_buffer); -+ for (i = 0, p = line_buffer; i < len; i++) { -+ p += sprintf(p, " 0x%02x", buf[i]); - } -+ trace_scsi_disk_new_request(lun, tag, line_buffer); -+ -+ g_free(line_buffer); - } - - static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, -diff --git a/net/eth.c b/net/eth.c -index 041ac4865a..1e0821c5f8 100644 ---- a/net/eth.c -+++ b/net/eth.c -@@ -405,8 +405,6 @@ _eth_get_rss_ex_dst_addr(const struct iovec *pkt, int pkt_frags, - struct ip6_ext_hdr *ext_hdr, - struct in6_address *dst_addr) - { --#pragma GCC diagnostic push --#pragma GCC diagnostic ignored "-Warray-bounds" - struct ip6_ext_hdr_routing *rthdr = (struct ip6_ext_hdr_routing *) ext_hdr; - - if ((rthdr->rtype == 2) && -@@ -426,7 +424,7 @@ _eth_get_rss_ex_dst_addr(const struct iovec *pkt, int pkt_frags, - - return bytes_read == sizeof(*dst_addr); - } --#pragma GCC diagnostic pop -+ - return false; - } - -diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c -index ab1ca6b1bf..1839cc6648 100644 ---- a/target/s390x/kvm.c -+++ b/target/s390x/kvm.c -@@ -1918,7 +1918,7 @@ static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar) - */ - if (qemu_name) { - strncpy((char *)sysib.ext_names[0], qemu_name, -- sizeof(sysib.ext_names[0])-1); -+ sizeof(sysib.ext_names[0])); - } else { - strcpy((char *)sysib.ext_names[0], "KVMguest"); - } -diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c -index adaf4145e6..58dbc023eb 100644 ---- a/target/s390x/misc_helper.c -+++ b/target/s390x/misc_helper.c -@@ -370,7 +370,7 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint64_t r0, uint64_t r1) - MIN(sizeof(sysib.sysib_322.vm[0].name), - strlen(qemu_name))); - strncpy((char *)sysib.sysib_322.ext_names[0], qemu_name, -- sizeof(sysib.sysib_322.ext_names[0])-1); -+ sizeof(sysib.sysib_322.ext_names[0])); - } else { - ebcdic_put(sysib.sysib_322.vm[0].name, "TCGguest", 8); - strcpy((char *)sysib.sysib_322.ext_names[0], "TCGguest"); -diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc -index fe6bdbf721..26f71cb599 100644 ---- a/tcg/aarch64/tcg-target.c.inc -+++ b/tcg/aarch64/tcg-target.c.inc -@@ -1852,7 +1852,8 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, - static tcg_insn_unit *tb_ret_addr; - - static void tcg_out_op(TCGContext *s, TCGOpcode opc, -- const TCGArg *args, const int *const_args) -+ const TCGArg args[TCG_MAX_OP_ARGS], -+ const int const_args[TCG_MAX_OP_ARGS]) - { - /* 99% of the time, we can signal the use of extension registers - by looking to see if the opcode handles 64-bit data. */ -diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c -index bc64b50e66..3f866a35c6 100644 ---- a/tests/test-block-iothread.c -+++ b/tests/test-block-iothread.c -@@ -75,7 +75,7 @@ static BlockDriver bdrv_test = { - - static void test_sync_op_pread(BdrvChild *c) - { -- uint8_t buf[512] = {0}; -+ uint8_t buf[512]; - int ret; - - /* Success */ -@@ -89,7 +89,7 @@ static void test_sync_op_pread(BdrvChild *c) - - static void test_sync_op_pwrite(BdrvChild *c) - { -- uint8_t buf[512] = {0}; -+ uint8_t buf[512]; - int ret; - - /* Success */ -@@ -103,7 +103,7 @@ static void test_sync_op_pwrite(BdrvChild *c) - - static void test_sync_op_blk_pread(BlockBackend *blk) - { -- uint8_t buf[512] = {0}; -+ uint8_t buf[512]; - int ret; - - /* Success */ -@@ -117,7 +117,7 @@ static void test_sync_op_blk_pread(BlockBackend *blk) - - static void test_sync_op_blk_pwrite(BlockBackend *blk) - { -- uint8_t buf[512] = {0}; -+ uint8_t buf[512]; - int ret; - - /* Success */ -@@ -131,7 +131,7 @@ static void test_sync_op_blk_pwrite(BlockBackend *blk) - - static void test_sync_op_load_vmstate(BdrvChild *c) - { -- uint8_t buf[512] = {0}; -+ uint8_t buf[512]; - int ret; - - /* Error: Driver does not support snapshots */ -@@ -141,7 +141,7 @@ static void test_sync_op_load_vmstate(BdrvChild *c) - - static void test_sync_op_save_vmstate(BdrvChild *c) - { -- uint8_t buf[512] = {0}; -+ uint8_t buf[512]; - int ret; - - /* Error: Driver does not support snapshots */ --- -2.18.4 - diff --git a/0031-s390x-Use-strpadcpy-for-copying-vm-name.patch b/0031-s390x-Use-strpadcpy-for-copying-vm-name.patch deleted file mode 100644 index a7827ee..0000000 --- a/0031-s390x-Use-strpadcpy-for-copying-vm-name.patch +++ /dev/null @@ -1,84 +0,0 @@ -From adbabd33e81f46c6b29c4b940c053e562e4f55fd Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Fri, 15 Jan 2021 09:28:59 +0100 -Subject: s390x: Use strpadcpy for copying vm name - -Using strncpy with length equal to the size of target array, GCC 11 -reports following warning: - - warning: '__builtin_strncpy' specified bound 256 equals destination size [-Wstringop-truncation] - -We can prevent this warning by using strpadcpy that copies string -up to specified length, zeroes target array after copied string -and does not raise warning when length is equal to target array -size (and ending '\0' is discarded). - -Signed-off-by: Miroslav Rezanina ---- - target/s390x/kvm.c | 12 +++++------- - target/s390x/misc_helper.c | 7 +++++-- - 2 files changed, 10 insertions(+), 9 deletions(-) - -diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c -index 1839cc6648..c08b5bc2de 100644 ---- a/target/s390x/kvm.c -+++ b/target/s390x/kvm.c -@@ -29,6 +29,7 @@ - #include "internal.h" - #include "kvm_s390x.h" - #include "sysemu/kvm_int.h" -+#include "qemu/cutils.h" - #include "qapi/error.h" - #include "qemu/error-report.h" - #include "qemu/timer.h" -@@ -1910,18 +1911,15 @@ static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar) - strlen(qemu_name))); - } - sysib.vm[0].ext_name_encoding = 2; /* 2 = UTF-8 */ -- memset(sysib.ext_names[0], 0, sizeof(sysib.ext_names[0])); - /* If hypervisor specifies zero Extended Name in STSI322 SYSIB, it's - * considered by s390 as not capable of providing any Extended Name. - * Therefore if no name was specified on qemu invocation, we go with the - * same "KVMguest" default, which KVM has filled into short name field. - */ -- if (qemu_name) { -- strncpy((char *)sysib.ext_names[0], qemu_name, -- sizeof(sysib.ext_names[0])); -- } else { -- strcpy((char *)sysib.ext_names[0], "KVMguest"); -- } -+ strpadcpy((char *)sysib.ext_names[0], -+ sizeof(sysib.ext_names[0]), -+ qemu_name ?: "KVMguest", '\0'); -+ - /* Insert UUID */ - memcpy(sysib.vm[0].uuid, &qemu_uuid, sizeof(sysib.vm[0].uuid)); - -diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c -index 58dbc023eb..7ea90d414a 100644 ---- a/target/s390x/misc_helper.c -+++ b/target/s390x/misc_helper.c -@@ -19,6 +19,7 @@ - */ - - #include "qemu/osdep.h" -+#include "qemu/cutils.h" - #include "qemu/main-loop.h" - #include "cpu.h" - #include "internal.h" -@@ -369,8 +370,10 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint64_t r0, uint64_t r1) - ebcdic_put(sysib.sysib_322.vm[0].name, qemu_name, - MIN(sizeof(sysib.sysib_322.vm[0].name), - strlen(qemu_name))); -- strncpy((char *)sysib.sysib_322.ext_names[0], qemu_name, -- sizeof(sysib.sysib_322.ext_names[0])); -+ strpadcpy((char *)sysib.sysib_322.ext_names[0], -+ sizeof(sysib.sysib_322.ext_names[0]), -+ qemu_name, '\0'); -+ - } else { - ebcdic_put(sysib.sysib_322.vm[0].name, "TCGguest", 8); - strcpy((char *)sysib.sysib_322.ext_names[0], "TCGguest"); --- -2.18.4 - diff --git a/0032-tcg-Restrict-tcg_out_op-to-arrays-of-TCG_MAX_OP_ARGS.patch b/0032-tcg-Restrict-tcg_out_op-to-arrays-of-TCG_MAX_OP_ARGS.patch deleted file mode 100644 index 6cd75ce..0000000 --- a/0032-tcg-Restrict-tcg_out_op-to-arrays-of-TCG_MAX_OP_ARGS.patch +++ /dev/null @@ -1,138 +0,0 @@ -From 8773f3688ca87e5e7da2e1a5170d0bde9a54eae0 Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Fri, 15 Jan 2021 09:38:53 +0100 -Subject: tcg: Restrict tcg_out_op() to arrays of TCG_MAX_OP_ARGS elements - ---- - tcg/aarch64/tcg-target.c.inc | 3 ++- - tcg/i386/tcg-target.c.inc | 6 ++++-- - tcg/ppc/tcg-target.c.inc | 8 +++++--- - tcg/s390/tcg-target.c.inc | 3 ++- - tcg/tcg.c | 19 +++++++++++-------- - 5 files changed, 24 insertions(+), 15 deletions(-) - -diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc -index 26f71cb599..ce8689e889 100644 ---- a/tcg/aarch64/tcg-target.c.inc -+++ b/tcg/aarch64/tcg-target.c.inc -@@ -2271,7 +2271,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, - - static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, - unsigned vecl, unsigned vece, -- const TCGArg *args, const int *const_args) -+ const TCGArg args[TCG_MAX_OP_ARGS], -+ const int const_args[TCG_MAX_OP_ARGS]) - { - static const AArch64Insn cmp_insn[16] = { - [TCG_COND_EQ] = I3616_CMEQ, -diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc -index d8797ed398..0e557d177a 100644 ---- a/tcg/i386/tcg-target.c.inc -+++ b/tcg/i386/tcg-target.c.inc -@@ -2242,7 +2242,8 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64) - } - - static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, -- const TCGArg *args, const int *const_args) -+ const TCGArg args[TCG_MAX_OP_ARGS], -+ const int const_args[TCG_MAX_OP_ARGS]) - { - TCGArg a0, a1, a2; - int c, const_a2, vexop, rexw = 0; -@@ -2679,7 +2680,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, - - static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, - unsigned vecl, unsigned vece, -- const TCGArg *args, const int *const_args) -+ const TCGArg args[TCG_MAX_OP_ARGS], -+ const int const_args[TCG_MAX_OP_ARGS]) - { - static int const add_insn[4] = { - OPC_PADDB, OPC_PADDW, OPC_PADDD, OPC_PADDQ -diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc -index 18ee989f95..b2bc1fc0c4 100644 ---- a/tcg/ppc/tcg-target.c.inc -+++ b/tcg/ppc/tcg-target.c.inc -@@ -2353,8 +2353,9 @@ static void tcg_target_qemu_prologue(TCGContext *s) - tcg_out32(s, BCLR | BO_ALWAYS); - } - --static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, -- const int *const_args) -+static void tcg_out_op(TCGContext *s, TCGOpcode opc, -+ const TCGArg args[TCG_MAX_OP_ARGS], -+ const int const_args[TCG_MAX_OP_ARGS]) - { - TCGArg a0, a1, a2; - int c; -@@ -3151,7 +3152,8 @@ static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, - - static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, - unsigned vecl, unsigned vece, -- const TCGArg *args, const int *const_args) -+ const TCGArg args[TCG_MAX_OP_ARGS], -+ const int const_args[TCG_MAX_OP_ARGS]) - { - static const uint32_t - add_op[4] = { VADDUBM, VADDUHM, VADDUWM, VADDUDM }, -diff --git a/tcg/s390/tcg-target.c.inc b/tcg/s390/tcg-target.c.inc -index c5e096449b..79753c8af7 100644 ---- a/tcg/s390/tcg-target.c.inc -+++ b/tcg/s390/tcg-target.c.inc -@@ -1746,7 +1746,8 @@ static void tcg_out_qemu_st(TCGContext* s, TCGReg data_reg, TCGReg addr_reg, - case glue(glue(INDEX_op_,x),_i64) - - static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, -- const TCGArg *args, const int *const_args) -+ const TCGArg args[TCG_MAX_OP_ARGS], -+ const int const_args[TCG_MAX_OP_ARGS]) - { - S390Opcode op, op2; - TCGArg a0, a1, a2; -diff --git a/tcg/tcg.c b/tcg/tcg.c -index 43c6cf8f52..2d0116d29f 100644 ---- a/tcg/tcg.c -+++ b/tcg/tcg.c -@@ -109,8 +109,9 @@ static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, - static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); - static void tcg_out_movi(TCGContext *s, TCGType type, - TCGReg ret, tcg_target_long arg); --static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, -- const int *const_args); -+static void tcg_out_op(TCGContext *s, TCGOpcode opc, -+ const TCGArg args[TCG_MAX_OP_ARGS], -+ const int const_args[TCG_MAX_OP_ARGS]); - #if TCG_TARGET_MAYBE_vec - static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, - TCGReg dst, TCGReg src); -@@ -118,9 +119,10 @@ static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece, - TCGReg dst, TCGReg base, intptr_t offset); - static void tcg_out_dupi_vec(TCGContext *s, TCGType type, - TCGReg dst, tcg_target_long arg); --static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl, -- unsigned vece, const TCGArg *args, -- const int *const_args); -+static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, -+ unsigned vecl, unsigned vece, -+ const TCGArg args[TCG_MAX_OP_ARGS], -+ const int const_args[TCG_MAX_OP_ARGS]); - #else - static inline bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, - TCGReg dst, TCGReg src) -@@ -137,9 +139,10 @@ static inline void tcg_out_dupi_vec(TCGContext *s, TCGType type, - { - g_assert_not_reached(); - } --static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl, -- unsigned vece, const TCGArg *args, -- const int *const_args) -+static inline void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, -+ unsigned vecl, unsigned vece, -+ const TCGArg args[TCG_MAX_OP_ARGS], -+ const int const_args[TCG_MAX_OP_ARGS]) - { - g_assert_not_reached(); - } --- -2.18.4 - diff --git a/0033-net-eth-Simplify-_eth_get_rss_ex_dst_addr.patch b/0033-net-eth-Simplify-_eth_get_rss_ex_dst_addr.patch deleted file mode 100644 index 29a1b7e..0000000 --- a/0033-net-eth-Simplify-_eth_get_rss_ex_dst_addr.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 76ed390a52769c5ca64db5496a2adcb43df72035 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= -Date: Fri, 15 Jan 2021 09:42:33 +0100 -Subject: net/eth: Simplify _eth_get_rss_ex_dst_addr() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The length field is already contained in the ip6_ext_hdr structure. -Check it direcly in eth_parse_ipv6_hdr() before calling -_eth_get_rss_ex_dst_addr(), which gets a bit simplified. - -Signed-off-by: Philippe Mathieu-Daudé ---- - net/eth.c | 14 +++++++------- - 1 file changed, 7 insertions(+), 7 deletions(-) - -diff --git a/net/eth.c b/net/eth.c -index 1e0821c5f8..7d4dd48c1f 100644 ---- a/net/eth.c -+++ b/net/eth.c -@@ -407,9 +407,7 @@ _eth_get_rss_ex_dst_addr(const struct iovec *pkt, int pkt_frags, - { - struct ip6_ext_hdr_routing *rthdr = (struct ip6_ext_hdr_routing *) ext_hdr; - -- if ((rthdr->rtype == 2) && -- (rthdr->len == sizeof(struct in6_address) / 8) && -- (rthdr->segleft == 1)) { -+ if ((rthdr->rtype == 2) && (rthdr->segleft == 1)) { - - size_t input_size = iov_size(pkt, pkt_frags); - size_t bytes_read; -@@ -528,10 +526,12 @@ bool eth_parse_ipv6_hdr(const struct iovec *pkt, int pkt_frags, - } - - if (curr_ext_hdr_type == IP6_ROUTING) { -- info->rss_ex_dst_valid = -- _eth_get_rss_ex_dst_addr(pkt, pkt_frags, -- ip6hdr_off + info->full_hdr_len, -- &ext_hdr, &info->rss_ex_dst); -+ if (ext_hdr.ip6r_len == sizeof(struct in6_address) / 8) { -+ info->rss_ex_dst_valid = -+ _eth_get_rss_ex_dst_addr(pkt, pkt_frags, -+ ip6hdr_off + info->full_hdr_len, -+ &ext_hdr, &info->rss_ex_dst); -+ } - } else if (curr_ext_hdr_type == IP6_DESTINATON) { - info->rss_ex_src_valid = - _eth_get_rss_ex_src_addr(pkt, pkt_frags, --- -2.18.4 - diff --git a/0034-net-eth-Fix-stack-buffer-overflow-in.patch b/0034-net-eth-Fix-stack-buffer-overflow-in.patch deleted file mode 100644 index 5be9d9e..0000000 --- a/0034-net-eth-Fix-stack-buffer-overflow-in.patch +++ /dev/null @@ -1,196 +0,0 @@ -From 9abf30d739cfe5a7808f1e30ec85c0cfd73b67cb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= -Date: Fri, 15 Jan 2021 09:43:31 +0100 -Subject: net/eth: Fix stack-buffer-overflow in -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -QEMU fuzzer reported a buffer overflow in _eth_get_rss_ex_dst_addr() -reproducible as: - - $ cat << EOF | ./qemu-system-i386 -M pc-q35-5.0 \ - -accel qtest -monitor none \ - -serial none -nographic -qtest stdio - outl 0xcf8 0x80001010 - outl 0xcfc 0xe1020000 - outl 0xcf8 0x80001004 - outw 0xcfc 0x7 - write 0x25 0x1 0x86 - write 0x26 0x1 0xdd - write 0x4f 0x1 0x2b - write 0xe1020030 0x4 0x190002e1 - write 0xe102003a 0x2 0x0807 - write 0xe1020048 0x4 0x12077cdd - write 0xe1020400 0x4 0xba077cdd - write 0xe1020420 0x4 0x190002e1 - write 0xe1020428 0x4 0x3509d807 - write 0xe1020438 0x1 0xe2 - EOF - ================================================================= - ==2859770==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffdef904902 at pc 0x561ceefa78de bp 0x7ffdef904820 sp 0x7ffdef904818 - READ of size 1 at 0x7ffdef904902 thread T0 - #0 0x561ceefa78dd in _eth_get_rss_ex_dst_addr net/eth.c:410:17 - #1 0x561ceefa41fb in eth_parse_ipv6_hdr net/eth.c:532:17 - #2 0x561cef7de639 in net_tx_pkt_parse_headers hw/net/net_tx_pkt.c:228:14 - #3 0x561cef7dbef4 in net_tx_pkt_parse hw/net/net_tx_pkt.c:273:9 - #4 0x561ceec29f22 in e1000e_process_tx_desc hw/net/e1000e_core.c:730:29 - #5 0x561ceec28eac in e1000e_start_xmit hw/net/e1000e_core.c:927:9 - #6 0x561ceec1baab in e1000e_set_tdt hw/net/e1000e_core.c:2444:9 - #7 0x561ceebf300e in e1000e_core_write hw/net/e1000e_core.c:3256:9 - #8 0x561cef3cd4cd in e1000e_mmio_write hw/net/e1000e.c:110:5 - - Address 0x7ffdef904902 is located in stack of thread T0 at offset 34 in frame - #0 0x561ceefa320f in eth_parse_ipv6_hdr net/eth.c:486 - - This frame has 1 object(s): - [32, 34) 'ext_hdr' (line 487) <== Memory access at offset 34 overflows this variable - HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork - (longjmp and C++ exceptions *are* supported) - SUMMARY: AddressSanitizer: stack-buffer-overflow net/eth.c:410:17 in _eth_get_rss_ex_dst_addr - Shadow bytes around the buggy address: - 0x10003df188d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x10003df188e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x10003df188f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x10003df18900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x10003df18910: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 - =>0x10003df18920:[02]f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 - 0x10003df18930: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x10003df18940: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x10003df18950: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x10003df18960: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x10003df18970: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - Shadow byte legend (one shadow byte represents 8 application bytes): - Addressable: 00 - Partially addressable: 01 02 03 04 05 06 07 - Stack left redzone: f1 - Stack right redzone: f3 - ==2859770==ABORTING - -Similarly GCC 11 reports: - - net/eth.c: In function 'eth_parse_ipv6_hdr': - net/eth.c:410:15: error: array subscript 'struct ip6_ext_hdr_routing[0]' is partly outside array bounds of 'struct ip6_ext_hdr[1]' [-Werror=array-bounds] - 410 | if ((rthdr->rtype == 2) && (rthdr->segleft == 1)) { - | ~~~~~^~~~~~~ - net/eth.c:485:24: note: while referencing 'ext_hdr' - 485 | struct ip6_ext_hdr ext_hdr; - | ^~~~~~~ - net/eth.c:410:38: error: array subscript 'struct ip6_ext_hdr_routing[0]' is partly outside array bounds of 'struct ip6_ext_hdr[1]' [-Werror=array-bounds] - 410 | if ((rthdr->rtype == 2) && (rthdr->segleft == 1)) { - | ~~~~~^~~~~~~~~ - net/eth.c:485:24: note: while referencing 'ext_hdr' - 485 | struct ip6_ext_hdr ext_hdr; - | ^~~~~~~ - -In eth_parse_ipv6_hdr() we called iov_to_buf() to fill the 2 bytes of -the 'ext_hdr' buffer, then _eth_get_rss_ex_dst_addr() tries to access -beside the 2 filled bytes. - -Fix by reworking the function, filling the full rt_hdr buffer on the -stack calling iov_to_buf() again. - -Cc: qemu-stable@nongnu.org -Buglink: https://bugs.launchpad.net/qemu/+bug/1879531 -Reported-by: Alexander Bulekov -Reported-by: Miroslav Rezanina -Fixes: eb700029c78 ("net_pkt: Extend packet abstraction as required by e1000e functionality") -Signed-off-by: Philippe Mathieu-Daudé -Signed-off-by: Miroslav Rezanina ---- - net/eth.c | 25 +++++++++++-------------- - tests/qtest/fuzz-test.c | 29 +++++++++++++++++++++++++++++ - 2 files changed, 40 insertions(+), 14 deletions(-) - -diff --git a/net/eth.c b/net/eth.c -index 7d4dd48c1f..ae4db37888 100644 ---- a/net/eth.c -+++ b/net/eth.c -@@ -401,26 +401,23 @@ eth_is_ip6_extension_header_type(uint8_t hdr_type) - - static bool - _eth_get_rss_ex_dst_addr(const struct iovec *pkt, int pkt_frags, -- size_t rthdr_offset, -+ size_t ext_hdr_offset, - struct ip6_ext_hdr *ext_hdr, - struct in6_address *dst_addr) - { -- struct ip6_ext_hdr_routing *rthdr = (struct ip6_ext_hdr_routing *) ext_hdr; -- -- if ((rthdr->rtype == 2) && (rthdr->segleft == 1)) { -- -- size_t input_size = iov_size(pkt, pkt_frags); -- size_t bytes_read; -+ struct ip6_ext_hdr_routing rt_hdr; -+ size_t input_size = iov_size(pkt, pkt_frags); -+ size_t bytes_read; - -- if (input_size < rthdr_offset + sizeof(*ext_hdr)) { -- return false; -- } -+ if (input_size < ext_hdr_offset + sizeof(rt_hdr)) { -+ return false; -+ } - -- bytes_read = iov_to_buf(pkt, pkt_frags, -- rthdr_offset + sizeof(*ext_hdr), -- dst_addr, sizeof(*dst_addr)); -+ bytes_read = iov_to_buf(pkt, pkt_frags, ext_hdr_offset, -+ &rt_hdr, sizeof(rt_hdr)); - -- return bytes_read == sizeof(*dst_addr); -+ if ((rt_hdr.rtype == 2) && (rt_hdr.segleft == 1)) { -+ return bytes_read == sizeof(*ext_hdr) + sizeof(*dst_addr); - } - - return false; -diff --git a/tests/qtest/fuzz-test.c b/tests/qtest/fuzz-test.c -index 9cb4c42bde..2692d556d9 100644 ---- a/tests/qtest/fuzz-test.c -+++ b/tests/qtest/fuzz-test.c -@@ -47,6 +47,32 @@ static void test_lp1878642_pci_bus_get_irq_level_assert(void) - qtest_outl(s, 0x5d02, 0xebed205d); - } - -+/* -+ * https://bugs.launchpad.net/qemu/+bug/1879531 -+ */ -+static void test_lp1879531_eth_get_rss_ex_dst_addr(void) -+{ -+ QTestState *s; -+ -+ s = qtest_init("-nographic -monitor none -serial none -M pc-q35-5.0"); -+ -+ qtest_outl(s, 0xcf8 0x80001010); -+ qtest_outl(s, 0xcfc 0xe1020000); -+ qtest_outl(s, 0xcf8 0x80001004); -+ qtest_outw(s, 0xcfc 0x7); -+ qtest_writeb(s, 0x25 0x1 0x86); -+ qtest_writeb(s, 0x26 0x1 0xdd); -+ qtest_writeb(s, 0x4f 0x1 0x2b); -+ qtest_writel(s, 0xe1020030, 0x190002e1); -+ qtest_writew(s, 0xe102003a, 0x0807); -+ qtest_writel(s, 0xe1020048, 0x12077cdd); -+ qtest_writel(s, 0xe1020400, 0xba077cdd); -+ qtest_writel(s, 0xe1020420, 0x190002e1); -+ qtest_writel(s, 0xe1020428, 0x3509d807); -+ qtest_writeb(s, 0xe1020438, 0xe2); -+ qtest_quit(s); -+} -+ - int main(int argc, char **argv) - { - const char *arch = qtest_get_arch(); -@@ -58,6 +84,9 @@ int main(int argc, char **argv) - test_lp1878263_megasas_zero_iov_cnt); - qtest_add_func("fuzz/test_lp1878642_pci_bus_get_irq_level_assert", - test_lp1878642_pci_bus_get_irq_level_assert); -+ qtest_add_func("fuzz/test_lp1879531_eth_get_rss_ex_dst_addr", -+ test_lp1879531_eth_get_rss_ex_dst_addr); -+ - } - - return g_test_run(); --- -2.18.4 - diff --git a/0035-block-nvme-Implement-fake-truncate-coroutine.patch b/0035-block-nvme-Implement-fake-truncate-coroutine.patch deleted file mode 100644 index 237e9e1..0000000 --- a/0035-block-nvme-Implement-fake-truncate-coroutine.patch +++ /dev/null @@ -1,84 +0,0 @@ -From f4c65e14055e208e331a83b9340998ecbe796b5f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= -Date: Fri, 1 Jan 2021 17:18:13 -0500 -Subject: block/nvme: Implement fake truncate() coroutine -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Philippe Mathieu-Daudé -Message-id: <20210101171813.1734014-2-philmd@redhat.com> -Patchwork-id: 100503 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/1] block/nvme: Implement fake truncate() coroutine -Bugzilla: 1848834 -RH-Acked-by: Thomas Huth -RH-Acked-by: Max Reitz -RH-Acked-by: Stefan Hajnoczi - -NVMe drive cannot be shrunk. - -Since commit c80d8b06cfa we can use the @exact parameter (set -to false) to return success if the block device is larger than -the requested offset (even if we can not be shrunk). - -Use this parameter to implement the NVMe truncate() coroutine, -similarly how it is done for the iscsi and file-posix drivers -(see commit 82325ae5f2f "Evaluate @exact in protocol drivers"). - -Reported-by: Xueqiang Wei -Suggested-by: Max Reitz -Signed-off-by: Philippe Mathieu-Daudé -Message-Id: <20201210125202.858656-1-philmd@redhat.com> -Signed-off-by: Max Reitz -(cherry picked from commit c8807c5edcc8bd8917a5b7531d47ef6a99e07bd8) -Signed-off-by: Philippe Mathieu-Daudé -Signed-off-by: Danilo C. L. de Paula ---- - block/nvme.c | 24 ++++++++++++++++++++++++ - 1 file changed, 24 insertions(+) - -diff --git a/block/nvme.c b/block/nvme.c -index a06a188d53..5a6fbacf4a 100644 ---- a/block/nvme.c -+++ b/block/nvme.c -@@ -1389,6 +1389,29 @@ out: - - } - -+static int coroutine_fn nvme_co_truncate(BlockDriverState *bs, int64_t offset, -+ bool exact, PreallocMode prealloc, -+ BdrvRequestFlags flags, Error **errp) -+{ -+ int64_t cur_length; -+ -+ if (prealloc != PREALLOC_MODE_OFF) { -+ error_setg(errp, "Unsupported preallocation mode '%s'", -+ PreallocMode_str(prealloc)); -+ return -ENOTSUP; -+ } -+ -+ cur_length = nvme_getlength(bs); -+ if (offset != cur_length && exact) { -+ error_setg(errp, "Cannot resize NVMe devices"); -+ return -ENOTSUP; -+ } else if (offset > cur_length) { -+ error_setg(errp, "Cannot grow NVMe devices"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} - - static int nvme_reopen_prepare(BDRVReopenState *reopen_state, - BlockReopenQueue *queue, Error **errp) -@@ -1523,6 +1546,7 @@ static BlockDriver bdrv_nvme = { - .bdrv_close = nvme_close, - .bdrv_getlength = nvme_getlength, - .bdrv_probe_blocksizes = nvme_probe_blocksizes, -+ .bdrv_co_truncate = nvme_co_truncate, - - .bdrv_co_preadv = nvme_co_preadv, - .bdrv_co_pwritev = nvme_co_pwritev, --- -2.18.4 - diff --git a/0037-build-system-use-b_staticpic-false.patch b/0037-build-system-use-b_staticpic-false.patch deleted file mode 100644 index b47336b..0000000 --- a/0037-build-system-use-b_staticpic-false.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 50b575b27b9daa331da08d10dbe6524de0580833 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Wed, 16 Dec 2020 17:53:08 -0500 -Subject: build-system: use b_staticpic=false -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Paolo Bonzini -Message-id: <20201216175308.1463822-3-pbonzini@redhat.com> -Patchwork-id: 100484 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 2/2] build-system: use b_staticpic=false -Bugzilla: 1899619 -RH-Acked-by: Philippe Mathieu-Daudé -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Danilo de Paula - -Meson 0.56.0 correctly builds non-PIC static libraries with -fPIE if -b_pie=true, while Meson 0.55.3 has a bug that causes the library -to use non-PIE objects and fail to link. Therefore, upstream -QEMU looks at the meson version in order to decide between -b_staticpic=false and b_staticpic=$pie. - -Unfortunately, b_staticpic=$pie still has a negative effect -on performance when you QEMU is compiled with --enable-pie -like RHEL does. Therefore, we have backported the fix -to Meson 0.55.3-3.el8. We can require it and unconditionally -use b_staticpic=false. - -The patch is RHEL-specific, but a similar change is included -in the larger patch for "meson: switch minimum meson version to -0.56.0". - -Signed-off-by: Paolo Bonzini -Signed-off-by: Danilo C. L. de Paula ---- - configure | 5 ----- - meson.build | 4 ++-- - redhat/qemu-kvm.spec.template | 2 +- - 3 files changed, 3 insertions(+), 8 deletions(-) - -diff --git a/configure b/configure -index 18c26e0389..d60097c0d4 100755 ---- a/configure -+++ b/configure -@@ -6979,10 +6979,6 @@ fi - mv $cross config-meson.cross - - rm -rf meson-private meson-info meson-logs --unset staticpic --if ! version_ge "$($meson --version)" 0.56.0; then -- staticpic=$(if test "$pie" = yes; then echo true; else echo false; fi) --fi - NINJA=$ninja $meson setup \ - --prefix "$prefix" \ - --libdir "$libdir" \ -@@ -7002,7 +6998,6 @@ NINJA=$ninja $meson setup \ - -Dwerror=$(if test "$werror" = yes; then echo true; else echo false; fi) \ - -Dstrip=$(if test "$strip_opt" = yes; then echo true; else echo false; fi) \ - -Db_pie=$(if test "$pie" = yes; then echo true; else echo false; fi) \ -- ${staticpic:+-Db_staticpic=$staticpic} \ - -Db_coverage=$(if test "$gcov" = yes; then echo true; else echo false; fi) \ - -Dmalloc=$malloc -Dmalloc_trim=$malloc_trim -Dsparse=$sparse \ - -Dkvm=$kvm -Dhax=$hax -Dwhpx=$whpx -Dhvf=$hvf \ -diff --git a/meson.build b/meson.build -index 8c38b2ea36..c482d075d5 100644 ---- a/meson.build -+++ b/meson.build -@@ -1,6 +1,6 @@ - project('qemu', ['c'], meson_version: '>=0.55.0', -- default_options: ['warning_level=1', 'c_std=gnu99', 'cpp_std=gnu++11', 'b_colorout=auto'] + -- (meson.version().version_compare('>=0.56.0') ? [ 'b_staticpic=false' ] : []), -+ default_options: ['warning_level=1', 'c_std=gnu99', 'cpp_std=gnu++11', 'b_colorout=auto', -+ 'b_staticpic=false' ], - version: run_command('head', meson.source_root() / 'VERSION').stdout().strip()) - - not_found = dependency('', required: false) diff --git a/0038-spapr-Fix-buffer-overflow-in-spapr_numa_associativit.patch b/0038-spapr-Fix-buffer-overflow-in-spapr_numa_associativit.patch deleted file mode 100644 index 5c7f88d..0000000 --- a/0038-spapr-Fix-buffer-overflow-in-spapr_numa_associativit.patch +++ /dev/null @@ -1,131 +0,0 @@ -From d66ae008007853df7d3a24bd2d5e7494f53f007c Mon Sep 17 00:00:00 2001 -From: Greg Kurz -Date: Thu, 7 Jan 2021 10:10:20 -0500 -Subject: spapr: Fix buffer overflow in spapr_numa_associativity_init() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Greg Kurz -Message-id: <20210107101020.579456-2-gkurz@redhat.com> -Patchwork-id: 100515 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/1] spapr: Fix buffer overflow in spapr_numa_associativity_init() -Bugzilla: 1908693 -RH-Acked-by: David Gibson -RH-Acked-by: Philippe Mathieu-Daudé -RH-Acked-by: Laurent Vivier - -From: Greg Kurz - -Running a guest with 128 NUMA nodes crashes QEMU: - -../../util/error.c:59: error_setv: Assertion `*errp == NULL' failed. - -The crash happens when setting the FWNMI migration blocker: - -2861 if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI) == SPAPR_CAP_ON) { -2862 /* Create the error string for live migration blocker */ -2863 error_setg(&spapr->fwnmi_migration_blocker, -2864 "A machine check is being handled during migration. The handler" -2865 "may run and log hardware error on the destination"); -2866 } - -Inspection reveals that papr->fwnmi_migration_blocker isn't NULL: - -(gdb) p spapr->fwnmi_migration_blocker -$1 = (Error *) 0x8000000004000000 - -Since this is the only place where papr->fwnmi_migration_blocker is -set, this means someone wrote there in our back. Further analysis -points to spapr_numa_associativity_init(), especially the part -that initializes the associative arrays for NVLink GPUs: - - max_nodes_with_gpus = nb_numa_nodes + NVGPU_MAX_NUM; - -ie. max_nodes_with_gpus = 128 + 6, but the array isn't sized to -accommodate the 6 extra nodes: - -struct SpaprMachineState { - . - . - . - uint32_t numa_assoc_array[MAX_NODES][NUMA_ASSOC_SIZE]; - - Error *fwnmi_migration_blocker; -}; - -and the following loops happily overwrite spapr->fwnmi_migration_blocker, -and probably more: - - for (i = nb_numa_nodes; i < max_nodes_with_gpus; i++) { - spapr->numa_assoc_array[i][0] = cpu_to_be32(MAX_DISTANCE_REF_POINTS); - - for (j = 1; j < MAX_DISTANCE_REF_POINTS; j++) { - uint32_t gpu_assoc = smc->pre_5_1_assoc_refpoints ? - SPAPR_GPU_NUMA_ID : cpu_to_be32(i); - spapr->numa_assoc_array[i][j] = gpu_assoc; - } - - spapr->numa_assoc_array[i][MAX_DISTANCE_REF_POINTS] = cpu_to_be32(i); - } - -Fix the size of the array. This requires "hw/ppc/spapr.h" to see -NVGPU_MAX_NUM. Including "hw/pci-host/spapr.h" introduces a -circular dependency that breaks the build, so this moves the -definition of NVGPU_MAX_NUM to "hw/ppc/spapr.h" instead. - -Reported-by: Min Deng -BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1908693 -Fixes: dd7e1d7ae431 ("spapr_numa: move NVLink2 associativity handling to spapr_numa.c") -Cc: danielhb413@gmail.com -Signed-off-by: Greg Kurz -Message-Id: <160829960428.734871.12634150161215429514.stgit@bahia.lan> -Reviewed-by: Daniel Henrique Barboza -Signed-off-by: David Gibson -(cherry picked from commit 30499fdd9883026e106d74e8199e2f1311fd4011) -Signed-off-by: Greg Kurz -Signed-off-by: Danilo C. L. de Paula ---- - include/hw/pci-host/spapr.h | 2 -- - include/hw/ppc/spapr.h | 5 ++++- - 2 files changed, 4 insertions(+), 3 deletions(-) - -diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h -index 4f58f0223b..bd014823a9 100644 ---- a/include/hw/pci-host/spapr.h -+++ b/include/hw/pci-host/spapr.h -@@ -115,8 +115,6 @@ struct SpaprPhbState { - #define SPAPR_PCI_NV2RAM64_WIN_BASE SPAPR_PCI_LIMIT - #define SPAPR_PCI_NV2RAM64_WIN_SIZE (2 * TiB) /* For up to 6 GPUs 256GB each */ - --/* Max number of these GPUsper a physical box */ --#define NVGPU_MAX_NUM 6 - /* Max number of NVLinks per GPU in any physical box */ - #define NVGPU_MAX_LINKS 3 - -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index ba2d81404b..28bbf07f8f 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -112,6 +112,9 @@ typedef enum { - #define NUMA_ASSOC_SIZE (MAX_DISTANCE_REF_POINTS + 1) - #define VCPU_ASSOC_SIZE (NUMA_ASSOC_SIZE + 1) - -+/* Max number of these GPUsper a physical box */ -+#define NVGPU_MAX_NUM 6 -+ - typedef struct SpaprCapabilities SpaprCapabilities; - struct SpaprCapabilities { - uint8_t caps[SPAPR_CAP_NUM]; -@@ -243,7 +246,7 @@ struct SpaprMachineState { - unsigned gpu_numa_id; - SpaprTpmProxy *tpm_proxy; - -- uint32_t numa_assoc_array[MAX_NODES][NUMA_ASSOC_SIZE]; -+ uint32_t numa_assoc_array[MAX_NODES + NVGPU_MAX_NUM][NUMA_ASSOC_SIZE]; - - Error *fwnmi_migration_blocker; - }; --- -2.18.4 - diff --git a/0039-usb-hcd-xhci-pci-Fixup-capabilities-ordering-again.patch b/0039-usb-hcd-xhci-pci-Fixup-capabilities-ordering-again.patch deleted file mode 100644 index 01edcf3..0000000 --- a/0039-usb-hcd-xhci-pci-Fixup-capabilities-ordering-again.patch +++ /dev/null @@ -1,175 +0,0 @@ -From e85ee5f0196b85ad6f9faa02571325831b612c37 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Thu, 7 Jan 2021 14:12:25 -0500 -Subject: usb/hcd-xhci-pci: Fixup capabilities ordering (again) -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Dr. David Alan Gilbert -Message-id: <20210107141225.19709-2-dgilbert@redhat.com> -Patchwork-id: 100518 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/1] usb/hcd-xhci-pci: Fixup capabilities ordering (again) -Bugzilla: 1912846 -RH-Acked-by: Philippe Mathieu-Daudé -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Gerd Hoffmann - -From: "Dr. David Alan Gilbert" - -Allow the reordering of the PCIe capabilities for MSI around the PCIe -capability. -This changed incompatibly way back in QEMU 2.7 and in RHEL we fixed -it up in bz 1447874 unconditionally putting it back. - -The xhci code got reorganised between 5.0 and 5.2; and we lost this -fixup on rebase. - -This time, add it as a property, and enable the property for old -machine types; this will allow us to drop this patch once the -old machine types go. - -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Danilo C. L. de Paula ---- - hw/core/machine.c | 4 ++- - hw/usb/hcd-xhci-pci.c | 59 +++++++++++++++++++++++++++++++++---------- - hw/usb/hcd-xhci-pci.h | 1 + - 3 files changed, 49 insertions(+), 15 deletions(-) - -diff --git a/hw/core/machine.c b/hw/core/machine.c -index aba05ad676..68495b9411 100644 ---- a/hw/core/machine.c -+++ b/hw/core/machine.c -@@ -29,7 +29,7 @@ - #include "migration/vmstate.h" - - /* -- * The same as hw_compat_5_1 -+ * Mostly the same as hw_compat_5_1 - */ - GlobalProperty hw_compat_rhel_8_3[] = { - /* hw_compat_rhel_8_3 from hw_compat_5_1 */ -@@ -46,6 +46,8 @@ GlobalProperty hw_compat_rhel_8_3[] = { - { "nvme", "use-intel-id", "on"}, - /* hw_compat_rhel_8_3 from hw_compat_5_1 */ - { "pvpanic", "events", "1"}, /* PVPANIC_PANICKED */ -+ /* hw_compat_rhel_8_3 bz 1912846 */ -+ { "pci-xhci", "x-rh-late-msi-cap", "off" }, - }; - const size_t hw_compat_rhel_8_3_len = G_N_ELEMENTS(hw_compat_rhel_8_3); - -diff --git a/hw/usb/hcd-xhci-pci.c b/hw/usb/hcd-xhci-pci.c -index bba628d3d2..d045a2a8be 100644 ---- a/hw/usb/hcd-xhci-pci.c -+++ b/hw/usb/hcd-xhci-pci.c -@@ -101,6 +101,33 @@ static int xhci_pci_vmstate_post_load(void *opaque, int version_id) - return 0; - } - -+/* RH bz 1912846 */ -+static bool usb_xhci_pci_add_msi(struct PCIDevice *dev, Error **errp) -+{ -+ int ret; -+ Error *err = NULL; -+ XHCIPciState *s = XHCI_PCI(dev); -+ -+ ret = msi_init(dev, 0x70, s->xhci.numintrs, true, false, &err); -+ /* -+ * Any error other than -ENOTSUP(board's MSI support is broken) -+ * is a programming error -+ */ -+ assert(!ret || ret == -ENOTSUP); -+ if (ret && s->msi == ON_OFF_AUTO_ON) { -+ /* Can't satisfy user's explicit msi=on request, fail */ -+ error_append_hint(&err, "You have to use msi=auto (default) or " -+ "msi=off with this machine type.\n"); -+ error_propagate(errp, err); -+ return true; -+ } -+ assert(!err || s->msi == ON_OFF_AUTO_AUTO); -+ /* With msi=auto, we fall back to MSI off silently */ -+ error_free(err); -+ -+ return false; -+} -+ - static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp) - { - int ret; -@@ -124,23 +151,12 @@ static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp) - s->xhci.nec_quirks = true; - } - -- if (s->msi != ON_OFF_AUTO_OFF) { -- ret = msi_init(dev, 0x70, s->xhci.numintrs, true, false, &err); -- /* -- * Any error other than -ENOTSUP(board's MSI support is broken) -- * is a programming error -- */ -- assert(!ret || ret == -ENOTSUP); -- if (ret && s->msi == ON_OFF_AUTO_ON) { -- /* Can't satisfy user's explicit msi=on request, fail */ -- error_append_hint(&err, "You have to use msi=auto (default) or " -- "msi=off with this machine type.\n"); -+ if (s->msi != ON_OFF_AUTO_OFF && s->rh_late_msi_cap) { -+ /* This gives the behaviour from 5.2.0 onwards, lspci shows 90,a0,70 */ -+ if (usb_xhci_pci_add_msi(dev, &err)) { - error_propagate(errp, err); - return; - } -- assert(!err || s->msi == ON_OFF_AUTO_AUTO); -- /* With msi=auto, we fall back to MSI off silently */ -- error_free(err); - } - pci_register_bar(dev, 0, - PCI_BASE_ADDRESS_SPACE_MEMORY | -@@ -153,6 +169,14 @@ static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp) - assert(ret > 0); - } - -+ /* RH bz 1912846 */ -+ if (s->msi != ON_OFF_AUTO_OFF && !s->rh_late_msi_cap) { -+ /* This gives the older RH machine behaviour, lspci shows 90,70,a0 */ -+ if (usb_xhci_pci_add_msi(dev, &err)) { -+ error_propagate(errp, err); -+ return; -+ } -+ } - if (s->msix != ON_OFF_AUTO_OFF) { - /* TODO check for errors, and should fail when msix=on */ - msix_init(dev, s->xhci.numintrs, -@@ -197,11 +221,18 @@ static void xhci_instance_init(Object *obj) - qdev_alias_all_properties(DEVICE(&s->xhci), obj); - } - -+static Property xhci_pci_properties[] = { -+ /* RH bz 1912846 */ -+ DEFINE_PROP_BOOL("x-rh-late-msi-cap", XHCIPciState, rh_late_msi_cap, true), -+ DEFINE_PROP_END_OF_LIST() -+}; -+ - static void xhci_class_init(ObjectClass *klass, void *data) - { - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - DeviceClass *dc = DEVICE_CLASS(klass); - -+ device_class_set_props(dc, xhci_pci_properties); - dc->reset = xhci_pci_reset; - dc->vmsd = &vmstate_xhci_pci; - set_bit(DEVICE_CATEGORY_USB, dc->categories); -diff --git a/hw/usb/hcd-xhci-pci.h b/hw/usb/hcd-xhci-pci.h -index c193f79443..086a1feb1e 100644 ---- a/hw/usb/hcd-xhci-pci.h -+++ b/hw/usb/hcd-xhci-pci.h -@@ -39,6 +39,7 @@ typedef struct XHCIPciState { - XHCIState xhci; - OnOffAuto msi; - OnOffAuto msix; -+ bool rh_late_msi_cap; /* bz 1912846 */ - } XHCIPciState; - - #endif --- -2.18.4 - diff --git a/0040-qga-commands-posix-Send-CCW-address-on-s390x-with-th.patch b/0040-qga-commands-posix-Send-CCW-address-on-s390x-with-th.patch deleted file mode 100644 index cd881aa..0000000 --- a/0040-qga-commands-posix-Send-CCW-address-on-s390x-with-th.patch +++ /dev/null @@ -1,132 +0,0 @@ -From 0e1bc444240fb2d8d3ee65533baaa72a7267c53a Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Fri, 8 Jan 2021 12:27:19 -0500 -Subject: qga/commands-posix: Send CCW address on s390x with the fsinfo data -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Thomas Huth -Message-id: <20210108122719.73201-2-thuth@redhat.com> -Patchwork-id: 100532 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 1/1] qga/commands-posix: Send CCW address on s390x with the fsinfo data -Bugzilla: 1755075 -RH-Acked-by: Philippe Mathieu-Daudé -RH-Acked-by: Cornelia Huck -RH-Acked-by: David Hildenbrand - -We need the CCW address on the libvirt side to correctly identify -the disk, so add this information to the GuestDiskAddress on s390x. - -Signed-off-by: Thomas Huth -Reviewed-by: Cornelia Huck -Reviewed-by: Michael Roth -Message-Id: <20201127082353.448251-1-thuth@redhat.com> -Signed-off-by: Cornelia Huck -(cherry picked from commit 5b723a5d8df44b69b8ba350e643059c8fd889315) -Signed-off-by: Danilo C. L. de Paula ---- - qga/commands-posix.c | 34 ++++++++++++++++++++++++++++++++++ - qga/qapi-schema.json | 20 +++++++++++++++++++- - 2 files changed, 53 insertions(+), 1 deletion(-) - -diff --git a/qga/commands-posix.c b/qga/commands-posix.c -index c089e38120..5aa5eff84f 100644 ---- a/qga/commands-posix.c -+++ b/qga/commands-posix.c -@@ -1029,6 +1029,38 @@ static bool build_guest_fsinfo_for_nonpci_virtio(char const *syspath, - return true; - } - -+/* -+ * Store disk device info for CCW devices (s390x channel I/O devices). -+ * Returns true if information has been stored, or false for failure. -+ */ -+static bool build_guest_fsinfo_for_ccw_dev(char const *syspath, -+ GuestDiskAddress *disk, -+ Error **errp) -+{ -+ unsigned int cssid, ssid, subchno, devno; -+ char *p; -+ -+ p = strstr(syspath, "/devices/css"); -+ if (!p || sscanf(p + 12, "%*x/%x.%x.%x/%*x.%*x.%x/", -+ &cssid, &ssid, &subchno, &devno) < 4) { -+ g_debug("could not parse ccw device sysfs path: %s", syspath); -+ return false; -+ } -+ -+ disk->has_ccw_address = true; -+ disk->ccw_address = g_new0(GuestCCWAddress, 1); -+ disk->ccw_address->cssid = cssid; -+ disk->ccw_address->ssid = ssid; -+ disk->ccw_address->subchno = subchno; -+ disk->ccw_address->devno = devno; -+ -+ if (strstr(p, "/virtio")) { -+ build_guest_fsinfo_for_nonpci_virtio(syspath, disk, errp); -+ } -+ -+ return true; -+} -+ - /* Store disk device info specified by @sysfs into @fs */ - static void build_guest_fsinfo_for_real_device(char const *syspath, - GuestFilesystemInfo *fs, -@@ -1081,6 +1113,8 @@ static void build_guest_fsinfo_for_real_device(char const *syspath, - - if (strstr(syspath, "/devices/pci")) { - has_hwinf = build_guest_fsinfo_for_pci_dev(syspath, disk, errp); -+ } else if (strstr(syspath, "/devices/css")) { -+ has_hwinf = build_guest_fsinfo_for_ccw_dev(syspath, disk, errp); - } else if (strstr(syspath, "/virtio")) { - has_hwinf = build_guest_fsinfo_for_nonpci_virtio(syspath, disk, errp); - } else { -diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json -index 3b3d1d0bd9..9a82b7e952 100644 ---- a/qga/qapi-schema.json -+++ b/qga/qapi-schema.json -@@ -846,6 +846,22 @@ - 'data': {'domain': 'int', 'bus': 'int', - 'slot': 'int', 'function': 'int'} } - -+## -+# @GuestCCWAddress: -+# -+# @cssid: channel subsystem image id -+# @ssid: subchannel set id -+# @subchno: subchannel number -+# @devno: device number -+# -+# Since: 6.0 -+## -+{ 'struct': 'GuestCCWAddress', -+ 'data': {'cssid': 'int', -+ 'ssid': 'int', -+ 'subchno': 'int', -+ 'devno': 'int'} } -+ - ## - # @GuestDiskAddress: - # -@@ -856,6 +872,7 @@ - # @unit: unit id - # @serial: serial number (since: 3.1) - # @dev: device node (POSIX) or device UNC (Windows) (since: 3.1) -+# @ccw-address: CCW address on s390x (since: 6.0) - # - # Since: 2.2 - ## -@@ -863,7 +880,8 @@ - 'data': {'pci-controller': 'GuestPCIAddress', - 'bus-type': 'GuestDiskBusType', - 'bus': 'int', 'target': 'int', 'unit': 'int', -- '*serial': 'str', '*dev': 'str'} } -+ '*serial': 'str', '*dev': 'str', -+ '*ccw-address': 'GuestCCWAddress'} } - - ## - # @GuestDiskInfo: --- -2.18.4 - diff --git a/0041-AArch64-machine-types-cleanup.patch b/0041-AArch64-machine-types-cleanup.patch deleted file mode 100644 index 0ac8f70..0000000 --- a/0041-AArch64-machine-types-cleanup.patch +++ /dev/null @@ -1,188 +0,0 @@ -From bfa3dc6e290c7b4f7f8825e4d4320ba062ed445a Mon Sep 17 00:00:00 2001 -From: Andrew Jones -Date: Sat, 9 Jan 2021 22:19:27 -0500 -Subject: AArch64 machine types cleanup - -RH-Author: Andrew Jones -Message-id: <20210109221928.31407-2-drjones@redhat.com> -Patchwork-id: 100547 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 1/2] AArch64 machine types cleanup -Bugzilla: 1895276 -RH-Acked-by: Gavin Shan -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Auger Eric -RH-Acked-by: Thomas Huth - -No functional change here, just a reduction of downstream-only -changes and whitespace differences. Also the removal of a nested -'#if 0 /* disabled for RHEL */' block. - -Signed-off-by: Andrew Jones -Signed-off-by: Danilo C. L. de Paula ---- - hw/arm/virt.c | 69 +++++++++++++++++++++++---------------------------- - 1 file changed, 31 insertions(+), 38 deletions(-) - -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 21e0485ac5..530072fce0 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -123,7 +123,6 @@ - static const TypeInfo rhel##m##n##s##_machvirt_info = { \ - .name = MACHINE_TYPE_NAME("virt-rhel" # m "." # n "." # s), \ - .parent = TYPE_RHEL_MACHINE, \ -- .instance_init = rhel##m##n##s##_virt_instance_init, \ - .class_init = rhel##m##n##s##_virt_class_init, \ - }; \ - static void rhel##m##n##s##_machvirt_init(void) \ -@@ -2098,8 +2097,8 @@ static void virt_set_virt(Object *obj, bool value, Error **errp) - - vms->virt = value; - } -- - #endif /* disabled for RHEL */ -+ - static bool virt_get_highmem(Object *obj, Error **errp) - { - VirtMachineState *vms = VIRT_MACHINE(obj); -@@ -2167,14 +2166,13 @@ static void virt_set_ras(Object *obj, bool value, Error **errp) - - vms->ras = value; - } --#if 0 /* Disabled for Red Hat Enterprise Linux */ -+ - static bool virt_get_mte(Object *obj, Error **errp) - { - VirtMachineState *vms = VIRT_MACHINE(obj); - - return vms->mte; - } --#endif /* disabled for RHEL */ - - static void virt_set_mte(Object *obj, bool value, Error **errp) - { -@@ -2182,7 +2180,8 @@ static void virt_set_mte(Object *obj, bool value, Error **errp) - - vms->mte = value; - } --#endif -+#endif /* disabled for RHEL */ -+ - static char *virt_get_gic_version(Object *obj, Error **errp) - { - VirtMachineState *vms = VIRT_MACHINE(obj); -@@ -2818,25 +2817,6 @@ static void rhel_machine_class_init(ObjectClass *oc, void *data) - "Enable ACPI"); - } - --static const TypeInfo rhel_machine_info = { -- .name = TYPE_RHEL_MACHINE, -- .parent = TYPE_MACHINE, -- .abstract = true, -- .instance_size = sizeof(VirtMachineState), -- .class_size = sizeof(VirtMachineClass), -- .class_init = rhel_machine_class_init, -- .interfaces = (InterfaceInfo[]) { -- { TYPE_HOTPLUG_HANDLER }, -- { } -- }, --}; -- --static void rhel_machine_init(void) --{ -- type_register_static(&rhel_machine_info); --} --type_init(rhel_machine_init); -- - static void rhel_virt_instance_init(Object *obj) - { - VirtMachineState *vms = VIRT_MACHINE(obj); -@@ -2844,22 +2824,23 @@ static void rhel_virt_instance_init(Object *obj) - - /* EL3 is disabled by default and non-configurable for RHEL */ - vms->secure = false; -+ - /* EL2 is disabled by default and non-configurable for RHEL */ - vms->virt = false; -- /* High memory is enabled by default for RHEL */ -+ -+ /* High memory is enabled by default */ - vms->highmem = true; - object_property_add_bool(obj, "highmem", virt_get_highmem, - virt_set_highmem); - object_property_set_description(obj, "highmem", - "Set on/off to enable/disable using " - "physical address space above 32 bits"); -- - vms->gic_version = VIRT_GIC_VERSION_NOSEL; - object_property_add_str(obj, "gic-version", virt_get_gic_version, - virt_set_gic_version); - object_property_set_description(obj, "gic-version", - "Set GIC version. " -- "Valid values are 2, 3 and host"); -+ "Valid values are 2, 3, host and max"); - - vms->highmem_ecam = !vmc->no_highmem_ecam; - -@@ -2882,18 +2863,36 @@ static void rhel_virt_instance_init(Object *obj) - "Set the IOMMU type. " - "Valid values are none and smmuv3"); - -+ /* Default disallows RAS instantiation and is non-configurable for RHEL */ - vms->ras = false; -- /* MTE is disabled by default. */ -+ -+ /* MTE is disabled by default and non-configurable for RHEL */ - vms->mte = false; - -- vms->irqmap=a15irqmap; -+ vms->irqmap = a15irqmap; -+ - virt_flash_create(vms); - } - --static void rhel830_virt_instance_init(Object *obj) -+static const TypeInfo rhel_machine_info = { -+ .name = TYPE_RHEL_MACHINE, -+ .parent = TYPE_MACHINE, -+ .abstract = true, -+ .instance_size = sizeof(VirtMachineState), -+ .class_size = sizeof(VirtMachineClass), -+ .class_init = rhel_machine_class_init, -+ .instance_init = rhel_virt_instance_init, -+ .interfaces = (InterfaceInfo[]) { -+ { TYPE_HOTPLUG_HANDLER }, -+ { } -+ }, -+}; -+ -+static void rhel_machine_init(void) - { -- rhel_virt_instance_init(obj); -+ type_register_static(&rhel_machine_info); - } -+type_init(rhel_machine_init); - - static void rhel830_virt_options(MachineClass *mc) - { -@@ -2901,16 +2900,10 @@ static void rhel830_virt_options(MachineClass *mc) - } - DEFINE_RHEL_MACHINE_AS_LATEST(8, 3, 0) - --static void rhel820_virt_instance_init(Object *obj) --{ -- rhel_virt_instance_init(obj); --} -- - static void rhel820_virt_options(MachineClass *mc) - { - rhel830_virt_options(mc); -- compat_props_add(mc->compat_props, hw_compat_rhel_8_2, -- hw_compat_rhel_8_2_len); -+ compat_props_add(mc->compat_props, hw_compat_rhel_8_2, hw_compat_rhel_8_2_len); - mc->numa_mem_supported = true; - mc->auto_enable_numa_with_memdev = false; - } --- -2.18.4 - diff --git a/0042-hw-arm-virt-Add-8.4-Machine-type.patch b/0042-hw-arm-virt-Add-8.4-Machine-type.patch deleted file mode 100644 index 89753c9..0000000 --- a/0042-hw-arm-virt-Add-8.4-Machine-type.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 1bc68127d1531ed519cb839844febaecb2a3f6d0 Mon Sep 17 00:00:00 2001 -From: Andrew Jones -Date: Sat, 9 Jan 2021 22:19:28 -0500 -Subject: hw/arm/virt: Add 8.4 Machine type - -RH-Author: Andrew Jones -Message-id: <20210109221928.31407-3-drjones@redhat.com> -Patchwork-id: 100548 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 2/2] hw/arm/virt: Add 8.4 Machine type -Bugzilla: 1895276 -RH-Acked-by: Gavin Shan -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Auger Eric -RH-Acked-by: Thomas Huth - -8.4 isn't much different than 8.3, except it adds the steal-time -feature and enables it by default. - -Signed-off-by: Andrew Jones -Signed-off-by: Danilo C. L. de Paula ---- - hw/arm/virt.c | 14 ++++++++++++-- - 1 file changed, 12 insertions(+), 2 deletions(-) - -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 530072fce0..208c360342 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -2894,11 +2894,21 @@ static void rhel_machine_init(void) - } - type_init(rhel_machine_init); - --static void rhel830_virt_options(MachineClass *mc) -+static void rhel840_virt_options(MachineClass *mc) - { - compat_props_add(mc->compat_props, arm_rhel_compat, arm_rhel_compat_len); - } --DEFINE_RHEL_MACHINE_AS_LATEST(8, 3, 0) -+DEFINE_RHEL_MACHINE_AS_LATEST(8, 4, 0) -+ -+static void rhel830_virt_options(MachineClass *mc) -+{ -+ VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc)); -+ -+ rhel840_virt_options(mc); -+ compat_props_add(mc->compat_props, hw_compat_rhel_8_3, hw_compat_rhel_8_3_len); -+ vmc->no_kvm_steal_time = true; -+} -+DEFINE_RHEL_MACHINE(8, 3, 0) - - static void rhel820_virt_options(MachineClass *mc) - { --- -2.18.4 - diff --git a/0044-memory-Rename-memory_region_notify_one-to-memory_reg.patch b/0044-memory-Rename-memory_region_notify_one-to-memory_reg.patch deleted file mode 100644 index 419535a..0000000 --- a/0044-memory-Rename-memory_region_notify_one-to-memory_reg.patch +++ /dev/null @@ -1,146 +0,0 @@ -From 256180b78107813b8e8c292bc799f5d7c7676cd2 Mon Sep 17 00:00:00 2001 -From: eperezma -Date: Mon, 11 Jan 2021 14:36:11 -0500 -Subject: memory: Rename memory_region_notify_one to - memory_region_notify_iommu_one -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: eperezma -Message-id: <20210111143615.303645-2-eperezma@redhat.com> -Patchwork-id: 100570 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/5] memory: Rename memory_region_notify_one to memory_region_notify_iommu_one -Bugzilla: 1845758 -RH-Acked-by: Xiao Wang -RH-Acked-by: David Hildenbrand -RH-Acked-by: Peter Xu - -Previous name didn't reflect the iommu operation. - -Signed-off-by: Eugenio Pérez -Reviewed-by: Peter Xu -Reviewed-by: David Gibson -Reviewed-by: Juan Quintela -Reviewed-by: Eric Auger -Acked-by: Jason Wang -Message-Id: <20201116165506.31315-2-eperezma@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 3b5ebf8532afdc1518bd8b0961ed802bc3f5f07c) -Signed-off-by: Eugenio Pérez -Signed-off-by: Danilo C. L. de Paula ---- - hw/arm/smmu-common.c | 2 +- - hw/arm/smmuv3.c | 2 +- - hw/i386/intel_iommu.c | 4 ++-- - include/exec/memory.h | 6 +++--- - softmmu/memory.c | 6 +++--- - 5 files changed, 10 insertions(+), 10 deletions(-) - -diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c -index 3838db1395..88d2c454f0 100644 ---- a/hw/arm/smmu-common.c -+++ b/hw/arm/smmu-common.c -@@ -472,7 +472,7 @@ static void smmu_unmap_notifier_range(IOMMUNotifier *n) - entry.perm = IOMMU_NONE; - entry.addr_mask = n->end - n->start; - -- memory_region_notify_one(n, &entry); -+ memory_region_notify_iommu_one(n, &entry); - } - - /* Unmap all notifiers attached to @mr */ -diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index 22607c3784..273f5f7dce 100644 ---- a/hw/arm/smmuv3.c -+++ b/hw/arm/smmuv3.c -@@ -828,7 +828,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, - entry.addr_mask = num_pages * (1 << granule) - 1; - entry.perm = IOMMU_NONE; - -- memory_region_notify_one(n, &entry); -+ memory_region_notify_iommu_one(n, &entry); - } - - /* invalidate an asid/iova range tuple in all mr's */ -diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c -index 70ac837733..067593b9e4 100644 ---- a/hw/i386/intel_iommu.c -+++ b/hw/i386/intel_iommu.c -@@ -3497,7 +3497,7 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) - /* This field is meaningless for unmap */ - entry.translated_addr = 0; - -- memory_region_notify_one(n, &entry); -+ memory_region_notify_iommu_one(n, &entry); - - start += mask; - remain -= mask; -@@ -3535,7 +3535,7 @@ static void vtd_address_space_refresh_all(IntelIOMMUState *s) - - static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private) - { -- memory_region_notify_one((IOMMUNotifier *)private, entry); -+ memory_region_notify_iommu_one((IOMMUNotifier *)private, entry); - return 0; - } - -diff --git a/include/exec/memory.h b/include/exec/memory.h -index 0f3e6bcd5e..d8456ccf52 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -236,7 +236,7 @@ enum IOMMUMemoryRegionAttr { - * The IOMMU implementation must use the IOMMU notifier infrastructure - * to report whenever mappings are changed, by calling - * memory_region_notify_iommu() (or, if necessary, by calling -- * memory_region_notify_one() for each registered notifier). -+ * memory_region_notify_iommu_one() for each registered notifier). - * - * Conceptually an IOMMU provides a mapping from input address - * to an output TLB entry. If the IOMMU is aware of memory transaction -@@ -1346,7 +1346,7 @@ void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr, - IOMMUTLBEntry entry); - - /** -- * memory_region_notify_one: notify a change in an IOMMU translation -+ * memory_region_notify_iommu_one: notify a change in an IOMMU translation - * entry to a single notifier - * - * This works just like memory_region_notify_iommu(), but it only -@@ -1357,7 +1357,7 @@ void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr, - * replaces all old entries for the same virtual I/O address range. - * Deleted entries have .@perm == 0. - */ --void memory_region_notify_one(IOMMUNotifier *notifier, -+void memory_region_notify_iommu_one(IOMMUNotifier *notifier, - IOMMUTLBEntry *entry); - - /** -diff --git a/softmmu/memory.c b/softmmu/memory.c -index 11ca94d037..44de610c72 100644 ---- a/softmmu/memory.c -+++ b/softmmu/memory.c -@@ -1942,8 +1942,8 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr, - memory_region_update_iommu_notify_flags(iommu_mr, NULL); - } - --void memory_region_notify_one(IOMMUNotifier *notifier, -- IOMMUTLBEntry *entry) -+void memory_region_notify_iommu_one(IOMMUNotifier *notifier, -+ IOMMUTLBEntry *entry) - { - IOMMUNotifierFlag request_flags; - hwaddr entry_end = entry->iova + entry->addr_mask; -@@ -1979,7 +1979,7 @@ void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr, - - IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) { - if (iommu_notifier->iommu_idx == iommu_idx) { -- memory_region_notify_one(iommu_notifier, &entry); -+ memory_region_notify_iommu_one(iommu_notifier, &entry); - } - } - } --- -2.18.4 - diff --git a/0045-memory-Add-IOMMUTLBEvent.patch b/0045-memory-Add-IOMMUTLBEvent.patch deleted file mode 100644 index 0cc568b..0000000 --- a/0045-memory-Add-IOMMUTLBEvent.patch +++ /dev/null @@ -1,647 +0,0 @@ -From d282fdd88e60aa081365d8e0903ceb18743ccc9d Mon Sep 17 00:00:00 2001 -From: eperezma -Date: Mon, 11 Jan 2021 14:36:12 -0500 -Subject: memory: Add IOMMUTLBEvent -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: eperezma -Message-id: <20210111143615.303645-3-eperezma@redhat.com> -Patchwork-id: 100568 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 2/5] memory: Add IOMMUTLBEvent -Bugzilla: 1845758 -RH-Acked-by: Xiao Wang -RH-Acked-by: David Hildenbrand -RH-Acked-by: Peter Xu - -This way we can tell between regular IOMMUTLBEntry (entry of IOMMU -hardware) and notifications. - -In the notifications, we set explicitly if it is a MAPs or an UNMAP, -instead of trusting in entry permissions to differentiate them. - -Signed-off-by: Eugenio Pérez -Reviewed-by: Peter Xu -Reviewed-by: Juan Quintela -Acked-by: Jason Wang -Message-Id: <20201116165506.31315-3-eperezma@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Reviewed-by: Matthew Rosato -Acked-by: David Gibson -(cherry picked from commit 5039caf3c449c49e625d34e134463260cf8e00e0) -Signed-off-by: Eugenio Pérez -Signed-off-by: Danilo C. L. de Paula ---- - hw/arm/smmu-common.c | 13 +++--- - hw/arm/smmuv3.c | 13 +++--- - hw/i386/intel_iommu.c | 88 ++++++++++++++++++++++------------------ - hw/misc/tz-mpc.c | 32 ++++++++------- - hw/ppc/spapr_iommu.c | 15 +++---- - hw/s390x/s390-pci-inst.c | 27 +++++++----- - hw/virtio/virtio-iommu.c | 30 +++++++------- - include/exec/memory.h | 27 ++++++------ - softmmu/memory.c | 20 ++++----- - 9 files changed, 143 insertions(+), 122 deletions(-) - -diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c -index 88d2c454f0..405d5c5325 100644 ---- a/hw/arm/smmu-common.c -+++ b/hw/arm/smmu-common.c -@@ -465,14 +465,15 @@ IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_t sid) - /* Unmap the whole notifier's range */ - static void smmu_unmap_notifier_range(IOMMUNotifier *n) - { -- IOMMUTLBEntry entry; -+ IOMMUTLBEvent event; - -- entry.target_as = &address_space_memory; -- entry.iova = n->start; -- entry.perm = IOMMU_NONE; -- entry.addr_mask = n->end - n->start; -+ event.type = IOMMU_NOTIFIER_UNMAP; -+ event.entry.target_as = &address_space_memory; -+ event.entry.iova = n->start; -+ event.entry.perm = IOMMU_NONE; -+ event.entry.addr_mask = n->end - n->start; - -- memory_region_notify_iommu_one(n, &entry); -+ memory_region_notify_iommu_one(n, &event); - } - - /* Unmap all notifiers attached to @mr */ -diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index 273f5f7dce..bbca0e9f20 100644 ---- a/hw/arm/smmuv3.c -+++ b/hw/arm/smmuv3.c -@@ -800,7 +800,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, - uint8_t tg, uint64_t num_pages) - { - SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu); -- IOMMUTLBEntry entry; -+ IOMMUTLBEvent event; - uint8_t granule = tg; - - if (!tg) { -@@ -823,12 +823,13 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, - granule = tt->granule_sz; - } - -- entry.target_as = &address_space_memory; -- entry.iova = iova; -- entry.addr_mask = num_pages * (1 << granule) - 1; -- entry.perm = IOMMU_NONE; -+ event.type = IOMMU_NOTIFIER_UNMAP; -+ event.entry.target_as = &address_space_memory; -+ event.entry.iova = iova; -+ event.entry.addr_mask = num_pages * (1 << granule) - 1; -+ event.entry.perm = IOMMU_NONE; - -- memory_region_notify_iommu_one(n, &entry); -+ memory_region_notify_iommu_one(n, &event); - } - - /* invalidate an asid/iova range tuple in all mr's */ -diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c -index 067593b9e4..56180b1c43 100644 ---- a/hw/i386/intel_iommu.c -+++ b/hw/i386/intel_iommu.c -@@ -1073,7 +1073,7 @@ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce, - } - } - --typedef int (*vtd_page_walk_hook)(IOMMUTLBEntry *entry, void *private); -+typedef int (*vtd_page_walk_hook)(IOMMUTLBEvent *event, void *private); - - /** - * Constant information used during page walking -@@ -1094,11 +1094,12 @@ typedef struct { - uint16_t domain_id; - } vtd_page_walk_info; - --static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info) -+static int vtd_page_walk_one(IOMMUTLBEvent *event, vtd_page_walk_info *info) - { - VTDAddressSpace *as = info->as; - vtd_page_walk_hook hook_fn = info->hook_fn; - void *private = info->private; -+ IOMMUTLBEntry *entry = &event->entry; - DMAMap target = { - .iova = entry->iova, - .size = entry->addr_mask, -@@ -1107,7 +1108,7 @@ static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info) - }; - DMAMap *mapped = iova_tree_find(as->iova_tree, &target); - -- if (entry->perm == IOMMU_NONE && !info->notify_unmap) { -+ if (event->type == IOMMU_NOTIFIER_UNMAP && !info->notify_unmap) { - trace_vtd_page_walk_one_skip_unmap(entry->iova, entry->addr_mask); - return 0; - } -@@ -1115,7 +1116,7 @@ static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info) - assert(hook_fn); - - /* Update local IOVA mapped ranges */ -- if (entry->perm) { -+ if (event->type == IOMMU_NOTIFIER_MAP) { - if (mapped) { - /* If it's exactly the same translation, skip */ - if (!memcmp(mapped, &target, sizeof(target))) { -@@ -1141,19 +1142,21 @@ static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info) - int ret; - - /* Emulate an UNMAP */ -+ event->type = IOMMU_NOTIFIER_UNMAP; - entry->perm = IOMMU_NONE; - trace_vtd_page_walk_one(info->domain_id, - entry->iova, - entry->translated_addr, - entry->addr_mask, - entry->perm); -- ret = hook_fn(entry, private); -+ ret = hook_fn(event, private); - if (ret) { - return ret; - } - /* Drop any existing mapping */ - iova_tree_remove(as->iova_tree, &target); -- /* Recover the correct permission */ -+ /* Recover the correct type */ -+ event->type = IOMMU_NOTIFIER_MAP; - entry->perm = cache_perm; - } - } -@@ -1170,7 +1173,7 @@ static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info) - trace_vtd_page_walk_one(info->domain_id, entry->iova, - entry->translated_addr, entry->addr_mask, - entry->perm); -- return hook_fn(entry, private); -+ return hook_fn(event, private); - } - - /** -@@ -1191,7 +1194,7 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start, - uint32_t offset; - uint64_t slpte; - uint64_t subpage_size, subpage_mask; -- IOMMUTLBEntry entry; -+ IOMMUTLBEvent event; - uint64_t iova = start; - uint64_t iova_next; - int ret = 0; -@@ -1245,13 +1248,15 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start, - * - * In either case, we send an IOTLB notification down. - */ -- entry.target_as = &address_space_memory; -- entry.iova = iova & subpage_mask; -- entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur); -- entry.addr_mask = ~subpage_mask; -+ event.entry.target_as = &address_space_memory; -+ event.entry.iova = iova & subpage_mask; -+ event.entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur); -+ event.entry.addr_mask = ~subpage_mask; - /* NOTE: this is only meaningful if entry_valid == true */ -- entry.translated_addr = vtd_get_slpte_addr(slpte, info->aw); -- ret = vtd_page_walk_one(&entry, info); -+ event.entry.translated_addr = vtd_get_slpte_addr(slpte, info->aw); -+ event.type = event.entry.perm ? IOMMU_NOTIFIER_MAP : -+ IOMMU_NOTIFIER_UNMAP; -+ ret = vtd_page_walk_one(&event, info); - } - - if (ret < 0) { -@@ -1430,10 +1435,10 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num, - return 0; - } - --static int vtd_sync_shadow_page_hook(IOMMUTLBEntry *entry, -+static int vtd_sync_shadow_page_hook(IOMMUTLBEvent *event, - void *private) - { -- memory_region_notify_iommu((IOMMUMemoryRegion *)private, 0, *entry); -+ memory_region_notify_iommu(private, 0, *event); - return 0; - } - -@@ -1993,14 +1998,17 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s, - * page tables. We just deliver the PSI down to - * invalidate caches. - */ -- IOMMUTLBEntry entry = { -- .target_as = &address_space_memory, -- .iova = addr, -- .translated_addr = 0, -- .addr_mask = size - 1, -- .perm = IOMMU_NONE, -+ IOMMUTLBEvent event = { -+ .type = IOMMU_NOTIFIER_UNMAP, -+ .entry = { -+ .target_as = &address_space_memory, -+ .iova = addr, -+ .translated_addr = 0, -+ .addr_mask = size - 1, -+ .perm = IOMMU_NONE, -+ }, - }; -- memory_region_notify_iommu(&vtd_as->iommu, 0, entry); -+ memory_region_notify_iommu(&vtd_as->iommu, 0, event); - } - } - } -@@ -2412,7 +2420,7 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s, - VTDInvDesc *inv_desc) - { - VTDAddressSpace *vtd_dev_as; -- IOMMUTLBEntry entry; -+ IOMMUTLBEvent event; - struct VTDBus *vtd_bus; - hwaddr addr; - uint64_t sz; -@@ -2460,12 +2468,13 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s, - sz = VTD_PAGE_SIZE; - } - -- entry.target_as = &vtd_dev_as->as; -- entry.addr_mask = sz - 1; -- entry.iova = addr; -- entry.perm = IOMMU_NONE; -- entry.translated_addr = 0; -- memory_region_notify_iommu(&vtd_dev_as->iommu, 0, entry); -+ event.type = IOMMU_NOTIFIER_UNMAP; -+ event.entry.target_as = &vtd_dev_as->as; -+ event.entry.addr_mask = sz - 1; -+ event.entry.iova = addr; -+ event.entry.perm = IOMMU_NONE; -+ event.entry.translated_addr = 0; -+ memory_region_notify_iommu(&vtd_dev_as->iommu, 0, event); - - done: - return true; -@@ -3485,19 +3494,20 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) - size = remain = end - start + 1; - - while (remain >= VTD_PAGE_SIZE) { -- IOMMUTLBEntry entry; -+ IOMMUTLBEvent event; - uint64_t mask = get_naturally_aligned_size(start, remain, s->aw_bits); - - assert(mask); - -- entry.iova = start; -- entry.addr_mask = mask - 1; -- entry.target_as = &address_space_memory; -- entry.perm = IOMMU_NONE; -+ event.type = IOMMU_NOTIFIER_UNMAP; -+ event.entry.iova = start; -+ event.entry.addr_mask = mask - 1; -+ event.entry.target_as = &address_space_memory; -+ event.entry.perm = IOMMU_NONE; - /* This field is meaningless for unmap */ -- entry.translated_addr = 0; -+ event.entry.translated_addr = 0; - -- memory_region_notify_iommu_one(n, &entry); -+ memory_region_notify_iommu_one(n, &event); - - start += mask; - remain -= mask; -@@ -3533,9 +3543,9 @@ static void vtd_address_space_refresh_all(IntelIOMMUState *s) - vtd_switch_address_space_all(s); - } - --static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private) -+static int vtd_replay_hook(IOMMUTLBEvent *event, void *private) - { -- memory_region_notify_iommu_one((IOMMUNotifier *)private, entry); -+ memory_region_notify_iommu_one(private, event); - return 0; - } - -diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c -index 98f151237f..30481e1c90 100644 ---- a/hw/misc/tz-mpc.c -+++ b/hw/misc/tz-mpc.c -@@ -82,8 +82,10 @@ static void tz_mpc_iommu_notify(TZMPC *s, uint32_t lutidx, - /* Called when the LUT word at lutidx has changed from oldlut to newlut; - * must call the IOMMU notifiers for the changed blocks. - */ -- IOMMUTLBEntry entry = { -- .addr_mask = s->blocksize - 1, -+ IOMMUTLBEvent event = { -+ .entry = { -+ .addr_mask = s->blocksize - 1, -+ } - }; - hwaddr addr = lutidx * s->blocksize * 32; - int i; -@@ -100,26 +102,28 @@ static void tz_mpc_iommu_notify(TZMPC *s, uint32_t lutidx, - block_is_ns = newlut & (1 << i); - - trace_tz_mpc_iommu_notify(addr); -- entry.iova = addr; -- entry.translated_addr = addr; -+ event.entry.iova = addr; -+ event.entry.translated_addr = addr; - -- entry.perm = IOMMU_NONE; -- memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, entry); -- memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, entry); -+ event.type = IOMMU_NOTIFIER_UNMAP; -+ event.entry.perm = IOMMU_NONE; -+ memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, event); -+ memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, event); - -- entry.perm = IOMMU_RW; -+ event.type = IOMMU_NOTIFIER_MAP; -+ event.entry.perm = IOMMU_RW; - if (block_is_ns) { -- entry.target_as = &s->blocked_io_as; -+ event.entry.target_as = &s->blocked_io_as; - } else { -- entry.target_as = &s->downstream_as; -+ event.entry.target_as = &s->downstream_as; - } -- memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, entry); -+ memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, event); - if (block_is_ns) { -- entry.target_as = &s->downstream_as; -+ event.entry.target_as = &s->downstream_as; - } else { -- entry.target_as = &s->blocked_io_as; -+ event.entry.target_as = &s->blocked_io_as; - } -- memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, entry); -+ memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, event); - } - } - -diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c -index 0790239ba5..30352df00e 100644 ---- a/hw/ppc/spapr_iommu.c -+++ b/hw/ppc/spapr_iommu.c -@@ -445,7 +445,7 @@ static void spapr_tce_reset(DeviceState *dev) - static target_ulong put_tce_emu(SpaprTceTable *tcet, target_ulong ioba, - target_ulong tce) - { -- IOMMUTLBEntry entry; -+ IOMMUTLBEvent event; - hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift); - unsigned long index = (ioba - tcet->bus_offset) >> tcet->page_shift; - -@@ -457,12 +457,13 @@ static target_ulong put_tce_emu(SpaprTceTable *tcet, target_ulong ioba, - - tcet->table[index] = tce; - -- entry.target_as = &address_space_memory, -- entry.iova = (ioba - tcet->bus_offset) & page_mask; -- entry.translated_addr = tce & page_mask; -- entry.addr_mask = ~page_mask; -- entry.perm = spapr_tce_iommu_access_flags(tce); -- memory_region_notify_iommu(&tcet->iommu, 0, entry); -+ event.entry.target_as = &address_space_memory, -+ event.entry.iova = (ioba - tcet->bus_offset) & page_mask; -+ event.entry.translated_addr = tce & page_mask; -+ event.entry.addr_mask = ~page_mask; -+ event.entry.perm = spapr_tce_iommu_access_flags(tce); -+ event.type = event.entry.perm ? IOMMU_NOTIFIER_MAP : IOMMU_NOTIFIER_UNMAP; -+ memory_region_notify_iommu(&tcet->iommu, 0, event); - - return H_SUCCESS; - } -diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c -index 70bfd91bf7..d9e1e29f1e 100644 ---- a/hw/s390x/s390-pci-inst.c -+++ b/hw/s390x/s390-pci-inst.c -@@ -602,15 +602,18 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, - S390IOTLBEntry *entry) - { - S390IOTLBEntry *cache = g_hash_table_lookup(iommu->iotlb, &entry->iova); -- IOMMUTLBEntry notify = { -- .target_as = &address_space_memory, -- .iova = entry->iova, -- .translated_addr = entry->translated_addr, -- .perm = entry->perm, -- .addr_mask = ~PAGE_MASK, -+ IOMMUTLBEvent event = { -+ .type = entry->perm ? IOMMU_NOTIFIER_MAP : IOMMU_NOTIFIER_UNMAP, -+ .entry = { -+ .target_as = &address_space_memory, -+ .iova = entry->iova, -+ .translated_addr = entry->translated_addr, -+ .perm = entry->perm, -+ .addr_mask = ~PAGE_MASK, -+ }, - }; - -- if (entry->perm == IOMMU_NONE) { -+ if (event.type == IOMMU_NOTIFIER_UNMAP) { - if (!cache) { - goto out; - } -@@ -623,9 +626,11 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, - goto out; - } - -- notify.perm = IOMMU_NONE; -- memory_region_notify_iommu(&iommu->iommu_mr, 0, notify); -- notify.perm = entry->perm; -+ event.type = IOMMU_NOTIFIER_UNMAP; -+ event.entry.perm = IOMMU_NONE; -+ memory_region_notify_iommu(&iommu->iommu_mr, 0, event); -+ event.type = IOMMU_NOTIFIER_MAP; -+ event.entry.perm = entry->perm; - } - - cache = g_new(S390IOTLBEntry, 1); -@@ -637,7 +642,7 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, - dec_dma_avail(iommu); - } - -- memory_region_notify_iommu(&iommu->iommu_mr, 0, notify); -+ memory_region_notify_iommu(&iommu->iommu_mr, 0, event); - - out: - return iommu->dma_limit ? iommu->dma_limit->avail : 1; -diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c -index fc5c75d693..cea8811295 100644 ---- a/hw/virtio/virtio-iommu.c -+++ b/hw/virtio/virtio-iommu.c -@@ -129,7 +129,7 @@ static void virtio_iommu_notify_map(IOMMUMemoryRegion *mr, hwaddr virt_start, - hwaddr virt_end, hwaddr paddr, - uint32_t flags) - { -- IOMMUTLBEntry entry; -+ IOMMUTLBEvent event; - IOMMUAccessFlags perm = IOMMU_ACCESS_FLAG(flags & VIRTIO_IOMMU_MAP_F_READ, - flags & VIRTIO_IOMMU_MAP_F_WRITE); - -@@ -141,19 +141,20 @@ static void virtio_iommu_notify_map(IOMMUMemoryRegion *mr, hwaddr virt_start, - trace_virtio_iommu_notify_map(mr->parent_obj.name, virt_start, virt_end, - paddr, perm); - -- entry.target_as = &address_space_memory; -- entry.addr_mask = virt_end - virt_start; -- entry.iova = virt_start; -- entry.perm = perm; -- entry.translated_addr = paddr; -+ event.type = IOMMU_NOTIFIER_MAP; -+ event.entry.target_as = &address_space_memory; -+ event.entry.addr_mask = virt_end - virt_start; -+ event.entry.iova = virt_start; -+ event.entry.perm = perm; -+ event.entry.translated_addr = paddr; - -- memory_region_notify_iommu(mr, 0, entry); -+ memory_region_notify_iommu(mr, 0, event); - } - - static void virtio_iommu_notify_unmap(IOMMUMemoryRegion *mr, hwaddr virt_start, - hwaddr virt_end) - { -- IOMMUTLBEntry entry; -+ IOMMUTLBEvent event; - - if (!(mr->iommu_notify_flags & IOMMU_NOTIFIER_UNMAP)) { - return; -@@ -161,13 +162,14 @@ static void virtio_iommu_notify_unmap(IOMMUMemoryRegion *mr, hwaddr virt_start, - - trace_virtio_iommu_notify_unmap(mr->parent_obj.name, virt_start, virt_end); - -- entry.target_as = &address_space_memory; -- entry.addr_mask = virt_end - virt_start; -- entry.iova = virt_start; -- entry.perm = IOMMU_NONE; -- entry.translated_addr = 0; -+ event.type = IOMMU_NOTIFIER_UNMAP; -+ event.entry.target_as = &address_space_memory; -+ event.entry.addr_mask = virt_end - virt_start; -+ event.entry.iova = virt_start; -+ event.entry.perm = IOMMU_NONE; -+ event.entry.translated_addr = 0; - -- memory_region_notify_iommu(mr, 0, entry); -+ memory_region_notify_iommu(mr, 0, event); - } - - static gboolean virtio_iommu_notify_unmap_cb(gpointer key, gpointer value, -diff --git a/include/exec/memory.h b/include/exec/memory.h -index d8456ccf52..e86b5e92da 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -116,6 +116,11 @@ struct IOMMUNotifier { - }; - typedef struct IOMMUNotifier IOMMUNotifier; - -+typedef struct IOMMUTLBEvent { -+ IOMMUNotifierFlag type; -+ IOMMUTLBEntry entry; -+} IOMMUTLBEvent; -+ - /* RAM is pre-allocated and passed into qemu_ram_alloc_from_ptr */ - #define RAM_PREALLOC (1 << 0) - -@@ -1326,24 +1331,18 @@ uint64_t memory_region_iommu_get_min_page_size(IOMMUMemoryRegion *iommu_mr); - /** - * memory_region_notify_iommu: notify a change in an IOMMU translation entry. - * -- * The notification type will be decided by entry.perm bits: -- * -- * - For UNMAP (cache invalidation) notifies: set entry.perm to IOMMU_NONE. -- * - For MAP (newly added entry) notifies: set entry.perm to the -- * permission of the page (which is definitely !IOMMU_NONE). -- * - * Note: for any IOMMU implementation, an in-place mapping change - * should be notified with an UNMAP followed by a MAP. - * - * @iommu_mr: the memory region that was changed - * @iommu_idx: the IOMMU index for the translation table which has changed -- * @entry: the new entry in the IOMMU translation table. The entry -- * replaces all old entries for the same virtual I/O address range. -- * Deleted entries have .@perm == 0. -+ * @event: TLB event with the new entry in the IOMMU translation table. -+ * The entry replaces all old entries for the same virtual I/O address -+ * range. - */ - void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr, - int iommu_idx, -- IOMMUTLBEntry entry); -+ IOMMUTLBEvent event); - - /** - * memory_region_notify_iommu_one: notify a change in an IOMMU translation -@@ -1353,12 +1352,12 @@ void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr, - * notifies a specific notifier, not all of them. - * - * @notifier: the notifier to be notified -- * @entry: the new entry in the IOMMU translation table. The entry -- * replaces all old entries for the same virtual I/O address range. -- * Deleted entries have .@perm == 0. -+ * @event: TLB event with the new entry in the IOMMU translation table. -+ * The entry replaces all old entries for the same virtual I/O address -+ * range. - */ - void memory_region_notify_iommu_one(IOMMUNotifier *notifier, -- IOMMUTLBEntry *entry); -+ IOMMUTLBEvent *event); - - /** - * memory_region_register_iommu_notifier: register a notifier for changes to -diff --git a/softmmu/memory.c b/softmmu/memory.c -index 44de610c72..6ca87e8d73 100644 ---- a/softmmu/memory.c -+++ b/softmmu/memory.c -@@ -1943,11 +1943,15 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr, - } - - void memory_region_notify_iommu_one(IOMMUNotifier *notifier, -- IOMMUTLBEntry *entry) -+ IOMMUTLBEvent *event) - { -- IOMMUNotifierFlag request_flags; -+ IOMMUTLBEntry *entry = &event->entry; - hwaddr entry_end = entry->iova + entry->addr_mask; - -+ if (event->type == IOMMU_NOTIFIER_UNMAP) { -+ assert(entry->perm == IOMMU_NONE); -+ } -+ - /* - * Skip the notification if the notification does not overlap - * with registered range. -@@ -1958,20 +1962,14 @@ void memory_region_notify_iommu_one(IOMMUNotifier *notifier, - - assert(entry->iova >= notifier->start && entry_end <= notifier->end); - -- if (entry->perm & IOMMU_RW) { -- request_flags = IOMMU_NOTIFIER_MAP; -- } else { -- request_flags = IOMMU_NOTIFIER_UNMAP; -- } -- -- if (notifier->notifier_flags & request_flags) { -+ if (event->type & notifier->notifier_flags) { - notifier->notify(notifier, entry); - } - } - - void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr, - int iommu_idx, -- IOMMUTLBEntry entry) -+ IOMMUTLBEvent event) - { - IOMMUNotifier *iommu_notifier; - -@@ -1979,7 +1977,7 @@ void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr, - - IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) { - if (iommu_notifier->iommu_idx == iommu_idx) { -- memory_region_notify_iommu_one(iommu_notifier, &entry); -+ memory_region_notify_iommu_one(iommu_notifier, &event); - } - } - } --- -2.18.4 - diff --git a/0046-memory-Add-IOMMU_NOTIFIER_DEVIOTLB_UNMAP-IOMMUTLBNot.patch b/0046-memory-Add-IOMMU_NOTIFIER_DEVIOTLB_UNMAP-IOMMUTLBNot.patch deleted file mode 100644 index 6201e2f..0000000 --- a/0046-memory-Add-IOMMU_NOTIFIER_DEVIOTLB_UNMAP-IOMMUTLBNot.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 6eb76ae169aaf695a5fb6ef052859828e3ea91bc Mon Sep 17 00:00:00 2001 -From: eperezma -Date: Mon, 11 Jan 2021 14:36:13 -0500 -Subject: memory: Add IOMMU_NOTIFIER_DEVIOTLB_UNMAP IOMMUTLBNotificationType -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: eperezma -Message-id: <20210111143615.303645-4-eperezma@redhat.com> -Patchwork-id: 100571 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 3/5] memory: Add IOMMU_NOTIFIER_DEVIOTLB_UNMAP IOMMUTLBNotificationType -Bugzilla: 1845758 -RH-Acked-by: Xiao Wang -RH-Acked-by: David Hildenbrand -RH-Acked-by: Peter Xu - -This allows us to differentiate between regular IOMMU map/unmap events -and DEVIOTLB unmap. Doing so, notifiers that only need device IOTLB -invalidations will not receive regular IOMMU unmappings. - -Adapt intel and vhost to use it. - -Signed-off-by: Eugenio Pérez -Reviewed-by: Peter Xu -Reviewed-by: Juan Quintela -Acked-by: Jason Wang -Message-Id: <20201116165506.31315-4-eperezma@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit b68ba1ca57677acf870d5ab10579e6105c1f5338) -Signed-off-by: Eugenio Pérez -Signed-off-by: Danilo C. L. de Paula ---- - hw/i386/intel_iommu.c | 2 +- - hw/virtio/vhost.c | 2 +- - include/exec/memory.h | 7 ++++++- - 3 files changed, 8 insertions(+), 3 deletions(-) - -diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c -index 56180b1c43..edc3090f91 100644 ---- a/hw/i386/intel_iommu.c -+++ b/hw/i386/intel_iommu.c -@@ -2468,7 +2468,7 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s, - sz = VTD_PAGE_SIZE; - } - -- event.type = IOMMU_NOTIFIER_UNMAP; -+ event.type = IOMMU_NOTIFIER_DEVIOTLB_UNMAP; - event.entry.target_as = &vtd_dev_as->as; - event.entry.addr_mask = sz - 1; - event.entry.iova = addr; -diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c -index 614ccc2bcb..28c7d78172 100644 ---- a/hw/virtio/vhost.c -+++ b/hw/virtio/vhost.c -@@ -718,7 +718,7 @@ static void vhost_iommu_region_add(MemoryListener *listener, - iommu_idx = memory_region_iommu_attrs_to_index(iommu_mr, - MEMTXATTRS_UNSPECIFIED); - iommu_notifier_init(&iommu->n, vhost_iommu_unmap_notify, -- IOMMU_NOTIFIER_UNMAP, -+ IOMMU_NOTIFIER_DEVIOTLB_UNMAP, - section->offset_within_region, - int128_get64(end), - iommu_idx); -diff --git a/include/exec/memory.h b/include/exec/memory.h -index e86b5e92da..521d9901d7 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -97,9 +97,14 @@ typedef enum { - IOMMU_NOTIFIER_UNMAP = 0x1, - /* Notify entry changes (newly created entries) */ - IOMMU_NOTIFIER_MAP = 0x2, -+ /* Notify changes on device IOTLB entries */ -+ IOMMU_NOTIFIER_DEVIOTLB_UNMAP = 0x04, - } IOMMUNotifierFlag; - --#define IOMMU_NOTIFIER_ALL (IOMMU_NOTIFIER_MAP | IOMMU_NOTIFIER_UNMAP) -+#define IOMMU_NOTIFIER_IOTLB_EVENTS (IOMMU_NOTIFIER_MAP | IOMMU_NOTIFIER_UNMAP) -+#define IOMMU_NOTIFIER_DEVIOTLB_EVENTS IOMMU_NOTIFIER_DEVIOTLB_UNMAP -+#define IOMMU_NOTIFIER_ALL (IOMMU_NOTIFIER_IOTLB_EVENTS | \ -+ IOMMU_NOTIFIER_DEVIOTLB_EVENTS) - - struct IOMMUNotifier; - typedef void (*IOMMUNotify)(struct IOMMUNotifier *notifier, --- -2.18.4 - diff --git a/0047-intel_iommu-Skip-page-walking-on-device-iotlb-invali.patch b/0047-intel_iommu-Skip-page-walking-on-device-iotlb-invali.patch deleted file mode 100644 index e5fd578..0000000 --- a/0047-intel_iommu-Skip-page-walking-on-device-iotlb-invali.patch +++ /dev/null @@ -1,57 +0,0 @@ -From add80ba59a85aca4c5e2619dee95557d2ec14169 Mon Sep 17 00:00:00 2001 -From: eperezma -Date: Mon, 11 Jan 2021 14:36:14 -0500 -Subject: intel_iommu: Skip page walking on device iotlb invalidations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: eperezma -Message-id: <20210111143615.303645-5-eperezma@redhat.com> -Patchwork-id: 100572 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 4/5] intel_iommu: Skip page walking on device iotlb invalidations -Bugzilla: 1845758 -RH-Acked-by: Xiao Wang -RH-Acked-by: David Hildenbrand -RH-Acked-by: Peter Xu - -Although they didn't reach the notifier because of the filtering in -memory_region_notify_iommu_one, the vt-d was still splitting huge -memory invalidations in chunks. Skipping it. - -This improves performance in case of netperf with vhost-net: -* TCP_STREAM: From 1923.6Mbit/s to 2175.13Mbit/s (13%) -* TCP_RR: From 8464.73 trans/s to 8932.703333 trans/s (5.5%) -* UDP_RR: From 8562.08 trans/s to 9005.62/s (5.1%) -* UDP_STREAM: No change observed (insignificant 0.1% improvement) - -Signed-off-by: Eugenio Pérez -Acked-by: Jason Wang -Message-Id: <20201116165506.31315-5-eperezma@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit f7701e2c7983b680790af47117577b285b6a1aed) -Signed-off-by: Eugenio Pérez -Signed-off-by: Danilo C. L. de Paula ---- - hw/i386/intel_iommu.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c -index edc3090f91..0cc71e4057 100644 ---- a/hw/i386/intel_iommu.c -+++ b/hw/i386/intel_iommu.c -@@ -1478,6 +1478,10 @@ static int vtd_sync_shadow_page_table(VTDAddressSpace *vtd_as) - VTDContextEntry ce; - IOMMUNotifier *n; - -+ if (!(vtd_as->iommu.iommu_notify_flags & IOMMU_NOTIFIER_IOTLB_EVENTS)) { -+ return 0; -+ } -+ - ret = vtd_dev_to_context_entry(vtd_as->iommu_state, - pci_bus_num(vtd_as->bus), - vtd_as->devfn, &ce); --- -2.18.4 - diff --git a/0048-memory-Skip-bad-range-assertion-if-notifier-is-DEVIO.patch b/0048-memory-Skip-bad-range-assertion-if-notifier-is-DEVIO.patch deleted file mode 100644 index 25fb623..0000000 --- a/0048-memory-Skip-bad-range-assertion-if-notifier-is-DEVIO.patch +++ /dev/null @@ -1,69 +0,0 @@ -From ce5295813c0f1c94964cbd126f37a3202c360b92 Mon Sep 17 00:00:00 2001 -From: eperezma -Date: Mon, 11 Jan 2021 14:36:15 -0500 -Subject: memory: Skip bad range assertion if notifier is DEVIOTLB_UNMAP type -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: eperezma -Message-id: <20210111143615.303645-6-eperezma@redhat.com> -Patchwork-id: 100573 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 5/5] memory: Skip bad range assertion if notifier is DEVIOTLB_UNMAP type -Bugzilla: 1845758 -RH-Acked-by: Xiao Wang -RH-Acked-by: David Hildenbrand -RH-Acked-by: Peter Xu - -Device IOTLB invalidations can unmap arbitrary ranges, eiter outside of -the memory region or even [0, ~0ULL] for all the space. The assertion -could be hit by a guest, and rhel7 guest effectively hit it. - -Signed-off-by: Eugenio Pérez -Reviewed-by: Peter Xu -Reviewed-by: Juan Quintela -Acked-by: Jason Wang -Message-Id: <20201116165506.31315-6-eperezma@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 1804857f19f612f6907832e35599cdb51d4ec764) -Signed-off-by: Eugenio Pérez -Signed-off-by: Danilo C. L. de Paula ---- - softmmu/memory.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/softmmu/memory.c b/softmmu/memory.c -index 6ca87e8d73..22bacbbc78 100644 ---- a/softmmu/memory.c -+++ b/softmmu/memory.c -@@ -1947,6 +1947,7 @@ void memory_region_notify_iommu_one(IOMMUNotifier *notifier, - { - IOMMUTLBEntry *entry = &event->entry; - hwaddr entry_end = entry->iova + entry->addr_mask; -+ IOMMUTLBEntry tmp = *entry; - - if (event->type == IOMMU_NOTIFIER_UNMAP) { - assert(entry->perm == IOMMU_NONE); -@@ -1960,10 +1961,16 @@ void memory_region_notify_iommu_one(IOMMUNotifier *notifier, - return; - } - -- assert(entry->iova >= notifier->start && entry_end <= notifier->end); -+ if (notifier->notifier_flags & IOMMU_NOTIFIER_DEVIOTLB_UNMAP) { -+ /* Crop (iova, addr_mask) to range */ -+ tmp.iova = MAX(tmp.iova, notifier->start); -+ tmp.addr_mask = MIN(entry_end, notifier->end) - tmp.iova; -+ } else { -+ assert(entry->iova >= notifier->start && entry_end <= notifier->end); -+ } - - if (event->type & notifier->notifier_flags) { -- notifier->notify(notifier, entry); -+ notifier->notify(notifier, &tmp); - } - } - --- -2.18.4 - diff --git a/0049-RHEL-Switch-pvpanic-test-to-q35.patch b/0049-RHEL-Switch-pvpanic-test-to-q35.patch deleted file mode 100644 index 7b6f4bf..0000000 --- a/0049-RHEL-Switch-pvpanic-test-to-q35.patch +++ /dev/null @@ -1,47 +0,0 @@ -From c489d2cd175e879071a3c5504a17d7f656dd7b06 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Tue, 8 Dec 2020 16:27:15 -0500 -Subject: RHEL: Switch pvpanic test to q35 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Dr. David Alan Gilbert -Message-id: <20201208162716.30836-3-dgilbert@redhat.com> -Patchwork-id: 100360 -O-Subject: [RHEL-av-8.4.0 qemu-kvm PATCH v2 2/3] RHEL: Switch pvpanic test to q35 -Bugzilla: 1885555 -RH-Acked-by: Thomas Huth -RH-Acked-by: Juan Quintela -RH-Acked-by: Philippe Mathieu-Daudé - -From: "Dr. David Alan Gilbert" - -Since b1b0393c3c5 the pvpanic test checks for a different -result (3) expecting it to get that on new machine types. -But, downstream, our 'pc' machine type is old, so switch the -test to q35, so it gets the new behaviour it's expecting. - -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Danilo C. L. de Paula ---- - tests/qtest/pvpanic-test.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/tests/qtest/pvpanic-test.c b/tests/qtest/pvpanic-test.c -index 016b32ebee..f0a7282b47 100644 ---- a/tests/qtest/pvpanic-test.c -+++ b/tests/qtest/pvpanic-test.c -@@ -17,7 +17,8 @@ static void test_panic(void) - QDict *response, *data; - QTestState *qts; - -- qts = qtest_init("-device pvpanic"); -+ /* RHEL: Use q35 */ -+ qts = qtest_init("-M q35 -device pvpanic"); - - val = qtest_inb(qts, 0x505); - g_assert_cmpuint(val, ==, 3); --- -2.18.4 - diff --git a/0050-8.4-x86-machine-type.patch b/0050-8.4-x86-machine-type.patch deleted file mode 100644 index 70d0554..0000000 --- a/0050-8.4-x86-machine-type.patch +++ /dev/null @@ -1,144 +0,0 @@ -From cb95a2dd9f549a4b7fcfac97b9a83c46a232d41e Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Tue, 8 Dec 2020 16:27:16 -0500 -Subject: 8.4 x86 machine type - -RH-Author: Dr. David Alan Gilbert -Message-id: <20201208162716.30836-4-dgilbert@redhat.com> -Patchwork-id: 100362 -O-Subject: [RHEL-av-8.4.0 qemu-kvm PATCH v2 3/3] 8.4 x86 machine type -Bugzilla: 1885555 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Igor Mammedov -RH-Acked-by: Juan Quintela - -From: "Dr. David Alan Gilbert" - -Add pc-q35-rhel8.4.0 and fix all the compatiiblity glue up. - -Note the moving of x-smi-cpu-hotplug follows bz 1846886 comment 18 -part 2. - -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Danilo C. L. de Paula ---- - hw/i386/pc.c | 8 ++++++-- - hw/i386/pc_piix.c | 5 +++++ - hw/i386/pc_q35.c | 30 +++++++++++++++++++++++++++--- - include/hw/i386/pc.h | 3 +++ - 4 files changed, 41 insertions(+), 5 deletions(-) - -diff --git a/hw/i386/pc.c b/hw/i386/pc.c -index f3fc695fe2..d5ea5b634c 100644 ---- a/hw/i386/pc.c -+++ b/hw/i386/pc.c -@@ -363,11 +363,15 @@ GlobalProperty pc_rhel_compat[] = { - { TYPE_X86_CPU, "vmx-exit-load-perf-global-ctrl", "off" }, - /* bz 1508330 */ - { "vfio-pci", "x-no-geforce-quirks", "on" }, -- /* BZ 1846886 */ -- { "ICH9-LPC", "x-smi-cpu-hotplug", "off" }, - }; - const size_t pc_rhel_compat_len = G_N_ELEMENTS(pc_rhel_compat); - -+GlobalProperty pc_rhel_8_3_compat[] = { -+ /* pc_rhel_8_3_compat from pc_compat_5_1 */ -+ { "ICH9-LPC", "x-smi-cpu-hotplug", "off" }, -+}; -+const size_t pc_rhel_8_3_compat_len = G_N_ELEMENTS(pc_rhel_8_3_compat); -+ - GlobalProperty pc_rhel_8_2_compat[] = { - /* pc_rhel_8_2_compat from pc_compat_4_2 */ - { "mch", "smbase-smram", "off" }, -diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c -index 815da79108..1b1cc18ae0 100644 ---- a/hw/i386/pc_piix.c -+++ b/hw/i386/pc_piix.c -@@ -1045,6 +1045,11 @@ static void pc_machine_rhel760_options(MachineClass *m) - m->smbus_no_migration_support = true; - pcmc->pvh_enabled = false; - pcmc->default_cpu_version = CPU_VERSION_LEGACY; -+ pcmc->kvmclock_create_always = false; -+ compat_props_add(m->compat_props, hw_compat_rhel_8_3, -+ hw_compat_rhel_8_3_len); -+ compat_props_add(m->compat_props, pc_rhel_8_3_compat, -+ pc_rhel_8_3_compat_len); - compat_props_add(m->compat_props, hw_compat_rhel_8_2, - hw_compat_rhel_8_2_len); - compat_props_add(m->compat_props, pc_rhel_8_2_compat, -diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c -index 3340008c00..5acb47afcf 100644 ---- a/hw/i386/pc_q35.c -+++ b/hw/i386/pc_q35.c -@@ -593,6 +593,24 @@ static void pc_q35_machine_rhel_options(MachineClass *m) - compat_props_add(m->compat_props, pc_rhel_compat, pc_rhel_compat_len); - } - -+static void pc_q35_init_rhel840(MachineState *machine) -+{ -+ pc_q35_init(machine); -+} -+ -+static void pc_q35_machine_rhel840_options(MachineClass *m) -+{ -+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); -+ pc_q35_machine_rhel_options(m); -+ m->desc = "RHEL-8.4.0 PC (Q35 + ICH9, 2009)"; -+ pcmc->smbios_stream_product = "RHEL-AV"; -+ pcmc->smbios_stream_version = "8.4.0"; -+} -+ -+DEFINE_PC_MACHINE(q35_rhel840, "pc-q35-rhel8.4.0", pc_q35_init_rhel840, -+ pc_q35_machine_rhel840_options); -+ -+ - static void pc_q35_init_rhel830(MachineState *machine) - { - pc_q35_init(machine); -@@ -601,10 +619,17 @@ static void pc_q35_init_rhel830(MachineState *machine) - static void pc_q35_machine_rhel830_options(MachineClass *m) - { - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); -- pc_q35_machine_rhel_options(m); -+ pc_q35_machine_rhel840_options(m); - m->desc = "RHEL-8.3.0 PC (Q35 + ICH9, 2009)"; -+ m->alias = NULL; - pcmc->smbios_stream_product = "RHEL-AV"; - pcmc->smbios_stream_version = "8.3.0"; -+ compat_props_add(m->compat_props, hw_compat_rhel_8_3, -+ hw_compat_rhel_8_3_len); -+ compat_props_add(m->compat_props, pc_rhel_8_3_compat, -+ pc_rhel_8_3_compat_len); -+ /* From pc_q35_5_1_machine_options() */ -+ pcmc->kvmclock_create_always = false; - } - - DEFINE_PC_MACHINE(q35_rhel830, "pc-q35-rhel8.3.0", pc_q35_init_rhel830, -@@ -618,9 +643,8 @@ static void pc_q35_init_rhel820(MachineState *machine) - static void pc_q35_machine_rhel820_options(MachineClass *m) - { - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); -- pc_q35_machine_rhel_options(m); -+ pc_q35_machine_rhel830_options(m); - m->desc = "RHEL-8.2.0 PC (Q35 + ICH9, 2009)"; -- m->alias = NULL; - m->numa_mem_supported = true; - m->auto_enable_numa_with_memdev = false; - pcmc->smbios_stream_product = "RHEL-AV"; -diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h -index e2ba9a4b58..68091bea98 100644 ---- a/include/hw/i386/pc.h -+++ b/include/hw/i386/pc.h -@@ -272,6 +272,9 @@ extern const size_t pc_compat_1_4_len; - extern GlobalProperty pc_rhel_compat[]; - extern const size_t pc_rhel_compat_len; - -+extern GlobalProperty pc_rhel_8_3_compat[]; -+extern const size_t pc_rhel_8_3_compat_len; -+ - extern GlobalProperty pc_rhel_8_2_compat[]; - extern const size_t pc_rhel_8_2_compat_len; - --- -2.18.4 - diff --git a/0051-memory-clamp-cached-translation-in-case-it-points-to.patch b/0051-memory-clamp-cached-translation-in-case-it-points-to.patch deleted file mode 100644 index 7700dcf..0000000 --- a/0051-memory-clamp-cached-translation-in-case-it-points-to.patch +++ /dev/null @@ -1,153 +0,0 @@ -From cf7723d08da5b371ef8b89a6e4edfaa21f88f03f Mon Sep 17 00:00:00 2001 -From: Jon Maloy -Date: Tue, 12 Jan 2021 21:01:25 -0500 -Subject: memory: clamp cached translation in case it points to an MMIO region - -RH-Author: Jon Maloy -Message-id: <20210112210125.851866-2-jmaloy@redhat.com> -Patchwork-id: 100614 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/1] memory: clamp cached translation in case it points to an MMIO region -Bugzilla: 1904392 -RH-Acked-by: Danilo de Paula -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Thomas Huth - -From: Paolo Bonzini - -In using the address_space_translate_internal API, address_space_cache_init -forgot one piece of advice that can be found in the code for -address_space_translate_internal: - - /* MMIO registers can be expected to perform full-width accesses based only - * on their address, without considering adjacent registers that could - * decode to completely different MemoryRegions. When such registers - * exist (e.g. I/O ports 0xcf8 and 0xcf9 on most PC chipsets), MMIO - * regions overlap wildly. For this reason we cannot clamp the accesses - * here. - * - * If the length is small (as is the case for address_space_ldl/stl), - * everything works fine. If the incoming length is large, however, - * the caller really has to do the clamping through memory_access_size. - */ - -address_space_cache_init is exactly one such case where "the incoming length -is large", therefore we need to clamp the resulting length---not to -memory_access_size though, since we are not doing an access yet, but to -the size of the resulting section. This ensures that subsequent accesses -to the cached MemoryRegionSection will be in range. - -With this patch, the enclosed testcase notices that the used ring does -not fit into the MSI-X table and prints a "qemu-system-x86_64: Cannot map used" -error. - -Signed-off-by: Paolo Bonzini - -(cherry picked from 4bfb024bc76973d40a359476dc0291f46e435442) -Signed-off-by: Jon Maloy -Signed-off-by: Danilo C. L. de Paula ---- - softmmu/physmem.c | 10 ++++++++ - tests/qtest/fuzz-test.c | 52 ++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 61 insertions(+), 1 deletion(-) - -diff --git a/softmmu/physmem.c b/softmmu/physmem.c -index 3027747c03..fb3f276844 100644 ---- a/softmmu/physmem.c -+++ b/softmmu/physmem.c -@@ -3255,6 +3255,7 @@ int64_t address_space_cache_init(MemoryRegionCache *cache, - AddressSpaceDispatch *d; - hwaddr l; - MemoryRegion *mr; -+ Int128 diff; - - assert(len > 0); - -@@ -3263,6 +3264,15 @@ int64_t address_space_cache_init(MemoryRegionCache *cache, - d = flatview_to_dispatch(cache->fv); - cache->mrs = *address_space_translate_internal(d, addr, &cache->xlat, &l, true); - -+ /* -+ * cache->xlat is now relative to cache->mrs.mr, not to the section itself. -+ * Take that into account to compute how many bytes are there between -+ * cache->xlat and the end of the section. -+ */ -+ diff = int128_sub(cache->mrs.size, -+ int128_make64(cache->xlat - cache->mrs.offset_within_region)); -+ l = int128_get64(int128_min(diff, int128_make64(l))); -+ - mr = cache->mrs.mr; - memory_region_ref(mr); - if (memory_access_is_direct(mr, is_write)) { -diff --git a/tests/qtest/fuzz-test.c b/tests/qtest/fuzz-test.c -index 2692d556d9..99d1a3ee12 100644 ---- a/tests/qtest/fuzz-test.c -+++ b/tests/qtest/fuzz-test.c -@@ -73,6 +73,55 @@ static void test_lp1879531_eth_get_rss_ex_dst_addr(void) - qtest_quit(s); - } - -+ /* -+ * Here a MemoryRegionCache pointed to an MMIO region but had a -+ * larger size than the underlying region. -+ */ -+static void test_mmio_oob_from_memory_region_cache(void) -+{ -+ QTestState *s; -+ -+ s = qtest_init("-M pc-q35-5.2 -display none -m 512M " -+ "-device virtio-scsi,num_queues=8,addr=03.0 "); -+ -+ qtest_outl(s, 0xcf8, 0x80001811); -+ qtest_outb(s, 0xcfc, 0x6e); -+ qtest_outl(s, 0xcf8, 0x80001824); -+ qtest_outl(s, 0xcf8, 0x80001813); -+ qtest_outl(s, 0xcfc, 0xa080000); -+ qtest_outl(s, 0xcf8, 0x80001802); -+ qtest_outl(s, 0xcfc, 0x5a175a63); -+ qtest_outb(s, 0x6e08, 0x9e); -+ qtest_writeb(s, 0x9f003, 0xff); -+ qtest_writeb(s, 0x9f004, 0x01); -+ qtest_writeb(s, 0x9e012, 0x0e); -+ qtest_writeb(s, 0x9e01b, 0x0e); -+ qtest_writeb(s, 0x9f006, 0x01); -+ qtest_writeb(s, 0x9f008, 0x01); -+ qtest_writeb(s, 0x9f00a, 0x01); -+ qtest_writeb(s, 0x9f00c, 0x01); -+ qtest_writeb(s, 0x9f00e, 0x01); -+ qtest_writeb(s, 0x9f010, 0x01); -+ qtest_writeb(s, 0x9f012, 0x01); -+ qtest_writeb(s, 0x9f014, 0x01); -+ qtest_writeb(s, 0x9f016, 0x01); -+ qtest_writeb(s, 0x9f018, 0x01); -+ qtest_writeb(s, 0x9f01a, 0x01); -+ qtest_writeb(s, 0x9f01c, 0x01); -+ qtest_writeb(s, 0x9f01e, 0x01); -+ qtest_writeb(s, 0x9f020, 0x01); -+ qtest_writeb(s, 0x9f022, 0x01); -+ qtest_writeb(s, 0x9f024, 0x01); -+ qtest_writeb(s, 0x9f026, 0x01); -+ qtest_writeb(s, 0x9f028, 0x01); -+ qtest_writeb(s, 0x9f02a, 0x01); -+ qtest_writeb(s, 0x9f02c, 0x01); -+ qtest_writeb(s, 0x9f02e, 0x01); -+ qtest_writeb(s, 0x9f030, 0x01); -+ qtest_outb(s, 0x6e10, 0x00); -+ qtest_quit(s); -+} -+ - int main(int argc, char **argv) - { - const char *arch = qtest_get_arch(); -@@ -86,7 +135,8 @@ int main(int argc, char **argv) - test_lp1878642_pci_bus_get_irq_level_assert); - qtest_add_func("fuzz/test_lp1879531_eth_get_rss_ex_dst_addr", - test_lp1879531_eth_get_rss_ex_dst_addr); -- -+ qtest_add_func("fuzz/test_mmio_oob_from_memory_region_cache", -+ test_mmio_oob_from_memory_region_cache); - } - - return g_test_run(); --- -2.18.4 - diff --git a/0054-Drop-bogus-IPv6-messages.patch b/0054-Drop-bogus-IPv6-messages.patch deleted file mode 100644 index 1ba8fd9..0000000 --- a/0054-Drop-bogus-IPv6-messages.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 1b118c53c70d9fa4ba3dcdf172039d29335bed73 Mon Sep 17 00:00:00 2001 -From: Jon Maloy -Date: Wed, 20 Jan 2021 00:13:11 -0500 -Subject: Drop bogus IPv6 messages -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Jon Maloy -Message-id: <20210120001311.1356511-2-jmaloy@redhat.com> -Patchwork-id: 100699 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/1] Drop bogus IPv6 messages -Bugzilla: 1918061 -RH-Acked-by: Philippe Mathieu-Daudé -RH-Acked-by: Stefano Garzarella -RH-Acked-by: Thomas Huth - -From: Ralf Haferkamp - -Drop IPv6 message shorter than what's mentioned in the payload -length header (+ the size of the IPv6 header). They're invalid an could -lead to data leakage in icmp6_send_echoreply(). - -(cherry picked from libslirp commit c7ede54cbd2e2b25385325600958ba0124e31cc0) -Signed-off-by: Jon Maloy -Signed-off-by: Danilo C. L. de Paula ---- - slirp/src/ip6_input.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/slirp/src/ip6_input.c b/slirp/src/ip6_input.c -index a83e4f8e3d..f7ef354ee4 100644 ---- a/slirp/src/ip6_input.c -+++ b/slirp/src/ip6_input.c -@@ -56,6 +56,13 @@ void ip6_input(struct mbuf *m) - goto bad; - } - -+ // Check if the message size is big enough to hold what's -+ // set in the payload length header. If not this is an invalid -+ // packet -+ if (m->m_len < ntohs(ip6->ip_pl) + sizeof(struct ip6)) { -+ goto bad; -+ } -+ - /* check ip_ttl for a correct ICMP reply */ - if (ip6->ip_hl == 0) { - icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS); --- -2.18.4 - diff --git a/README.rst b/README.rst deleted file mode 100644 index 4ca14c6..0000000 --- a/README.rst +++ /dev/null @@ -1,18 +0,0 @@ -=================== -qemu-kvm development -=================== - -qemu-kvm is maintained in a `source tree`_ rather than directly in dist-git -using packit service that provides way to develope using regular source code -structure and provides way to generate SRPM and build using koji service. - -Developers deliver all changes to source-git using merge request. Only maintainers -will be pushing changes sent to source-git to dist-git. - -Each release in dist-git is tagged in the source repository so you can easily -check out the source tree for a build. The tags are in the format -name-version-release, but note release doesn't contain the dist tag since the -source can be built in different build roots (Fedora, CentOS, etc.) - -.. _source tree: https://gitlab.com/redhat/centos-stream/src/qemu-kvm - diff --git a/kvm-block-Avoid-processing-BDS-twice-in-bdrv_set_aio_con.patch b/kvm-block-Avoid-processing-BDS-twice-in-bdrv_set_aio_con.patch deleted file mode 100644 index 59376b8..0000000 --- a/kvm-block-Avoid-processing-BDS-twice-in-bdrv_set_aio_con.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 0db52fa2553ba83454a347e0aca4896e1b0d9b41 Mon Sep 17 00:00:00 2001 -From: Sergio Lopez Pascual -Date: Thu, 11 Feb 2021 14:42:06 -0300 -Subject: [PATCH 4/6] block: Avoid processing BDS twice in - bdrv_set_aio_context_ignore() - -RH-Author: Sergio Lopez Pascual -Message-id: <20210211144208.58930-4-slp@redhat.com> -Patchwork-id: 101050 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 3/5] block: Avoid processing BDS twice in bdrv_set_aio_context_ignore() -Bugzilla: 1918966 1918968 -RH-Acked-by: Max Reitz -RH-Acked-by: Kevin Wolf -RH-Acked-by: Eric Blake - -Some graphs may contain an indirect reference to the first BDS in the -chain that can be reached while walking it bottom->up from one its -children. - -Doubling-processing of a BDS is especially problematic for the -aio_notifiers, as they might attempt to work on both the old and the -new AIO contexts. - -To avoid this problem, add every child and parent to the ignore list -before actually processing them. - -Suggested-by: Kevin Wolf -Signed-off-by: Sergio Lopez -Message-Id: <20210201125032.44713-2-slp@redhat.com> -Signed-off-by: Kevin Wolf -(cherry picked from commit 722d8e73d65cb54f39d360ecb2147ac58f43c399) -Signed-off-by: Sergio Lopez -Signed-off-by: Eduardo Lima (Etrunko) ---- - block.c | 34 +++++++++++++++++++++++++++------- - 1 file changed, 27 insertions(+), 7 deletions(-) - -diff --git a/block.c b/block.c -index f1cedac362..8bfa446f9c 100644 ---- a/block.c -+++ b/block.c -@@ -6454,7 +6454,10 @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs, - AioContext *new_context, GSList **ignore) - { - AioContext *old_context = bdrv_get_aio_context(bs); -- BdrvChild *child; -+ GSList *children_to_process = NULL; -+ GSList *parents_to_process = NULL; -+ GSList *entry; -+ BdrvChild *child, *parent; - - g_assert(qemu_get_current_aio_context() == qemu_get_aio_context()); - -@@ -6469,16 +6472,33 @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs, - continue; - } - *ignore = g_slist_prepend(*ignore, child); -- bdrv_set_aio_context_ignore(child->bs, new_context, ignore); -+ children_to_process = g_slist_prepend(children_to_process, child); - } -- QLIST_FOREACH(child, &bs->parents, next_parent) { -- if (g_slist_find(*ignore, child)) { -+ -+ QLIST_FOREACH(parent, &bs->parents, next_parent) { -+ if (g_slist_find(*ignore, parent)) { - continue; - } -- assert(child->klass->set_aio_ctx); -- *ignore = g_slist_prepend(*ignore, child); -- child->klass->set_aio_ctx(child, new_context, ignore); -+ *ignore = g_slist_prepend(*ignore, parent); -+ parents_to_process = g_slist_prepend(parents_to_process, parent); -+ } -+ -+ for (entry = children_to_process; -+ entry != NULL; -+ entry = g_slist_next(entry)) { -+ child = entry->data; -+ bdrv_set_aio_context_ignore(child->bs, new_context, ignore); -+ } -+ g_slist_free(children_to_process); -+ -+ for (entry = parents_to_process; -+ entry != NULL; -+ entry = g_slist_next(entry)) { -+ parent = entry->data; -+ assert(parent->klass->set_aio_ctx); -+ parent->klass->set_aio_ctx(parent, new_context, ignore); - } -+ g_slist_free(parents_to_process); - - bdrv_detach_aio_context(bs); - --- -2.27.0 - diff --git a/kvm-block-Honor-blk_set_aio_context-context-requirements.patch b/kvm-block-Honor-blk_set_aio_context-context-requirements.patch deleted file mode 100644 index de75ecc..0000000 --- a/kvm-block-Honor-blk_set_aio_context-context-requirements.patch +++ /dev/null @@ -1,118 +0,0 @@ -From bc284d49a00a1a716b380c2245aa0b897a259a5d Mon Sep 17 00:00:00 2001 -From: Sergio Lopez Pascual -Date: Thu, 11 Feb 2021 14:42:04 -0300 -Subject: [PATCH 2/6] block: Honor blk_set_aio_context() context requirements - -RH-Author: Sergio Lopez Pascual -Message-id: <20210211144208.58930-2-slp@redhat.com> -Patchwork-id: 101049 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/5] block: Honor blk_set_aio_context() context requirements -Bugzilla: 1918966 1918968 -RH-Acked-by: Max Reitz -RH-Acked-by: Kevin Wolf -RH-Acked-by: Eric Blake - -The documentation for bdrv_set_aio_context_ignore() states this: - - * The caller must own the AioContext lock for the old AioContext of bs, but it - * must not own the AioContext lock for new_context (unless new_context is the - * same as the current context of bs). - -As blk_set_aio_context() makes use of this function, this rule also -applies to it. - -Fix all occurrences where this rule wasn't honored. - -Suggested-by: Kevin Wolf -Signed-off-by: Sergio Lopez -Message-Id: <20201214170519.223781-2-slp@redhat.com> -Reviewed-by: Kevin Wolf -Signed-off-by: Eric Blake -(cherry picked from commit c7040ff64ec93ee925a81d3547db925fe7d1f1c0) -Signed-off-by: Sergio Lopez -Signed-off-by: Eduardo Lima (Etrunko) ---- - hw/block/dataplane/virtio-blk.c | 4 ++++ - hw/block/dataplane/xen-block.c | 7 ++++++- - hw/scsi/virtio-scsi.c | 6 ++++-- - 3 files changed, 14 insertions(+), 3 deletions(-) - -diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c -index 37499c5564..e9050c8987 100644 ---- a/hw/block/dataplane/virtio-blk.c -+++ b/hw/block/dataplane/virtio-blk.c -@@ -172,6 +172,7 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) - VirtIOBlockDataPlane *s = vblk->dataplane; - BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vblk))); - VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); -+ AioContext *old_context; - unsigned i; - unsigned nvqs = s->conf->num_queues; - Error *local_err = NULL; -@@ -214,7 +215,10 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) - vblk->dataplane_started = true; - trace_virtio_blk_data_plane_start(s); - -+ old_context = blk_get_aio_context(s->conf->conf.blk); -+ aio_context_acquire(old_context); - r = blk_set_aio_context(s->conf->conf.blk, s->ctx, &local_err); -+ aio_context_release(old_context); - if (r < 0) { - error_report_err(local_err); - goto fail_guest_notifiers; -diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c -index 71c337c7b7..3675f8deaf 100644 ---- a/hw/block/dataplane/xen-block.c -+++ b/hw/block/dataplane/xen-block.c -@@ -725,6 +725,7 @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane, - { - ERRP_GUARD(); - XenDevice *xendev = dataplane->xendev; -+ AioContext *old_context; - unsigned int ring_size; - unsigned int i; - -@@ -808,10 +809,14 @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane, - goto stop; - } - -- aio_context_acquire(dataplane->ctx); -+ old_context = blk_get_aio_context(dataplane->blk); -+ aio_context_acquire(old_context); - /* If other users keep the BlockBackend in the iothread, that's ok */ - blk_set_aio_context(dataplane->blk, dataplane->ctx, NULL); -+ aio_context_release(old_context); -+ - /* Only reason for failure is a NULL channel */ -+ aio_context_acquire(dataplane->ctx); - xen_device_set_event_channel_context(xendev, dataplane->event_channel, - dataplane->ctx, &error_abort); - aio_context_release(dataplane->ctx); -diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c -index 82c025146d..66bdda5473 100644 ---- a/hw/scsi/virtio-scsi.c -+++ b/hw/scsi/virtio-scsi.c -@@ -821,6 +821,7 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, - VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev); - VirtIOSCSI *s = VIRTIO_SCSI(vdev); - SCSIDevice *sd = SCSI_DEVICE(dev); -+ AioContext *old_context; - int ret; - - /* XXX: Remove this check once block backend is capable of handling -@@ -836,9 +837,10 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, - if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) { - return; - } -- virtio_scsi_acquire(s); -+ old_context = blk_get_aio_context(sd->conf.blk); -+ aio_context_acquire(old_context); - ret = blk_set_aio_context(sd->conf.blk, s->ctx, errp); -- virtio_scsi_release(s); -+ aio_context_release(old_context); - if (ret < 0) { - return; - } --- -2.27.0 - diff --git a/kvm-block-export-fix-blk_size-double-byteswap.patch b/kvm-block-export-fix-blk_size-double-byteswap.patch deleted file mode 100644 index c93ab98..0000000 --- a/kvm-block-export-fix-blk_size-double-byteswap.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 29c5b94ae259f21b792a611096c60b240e0c0983 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Mon, 15 Mar 2021 18:16:25 -0400 -Subject: [PATCH 09/15] block/export: fix blk_size double byteswap - -RH-Author: Stefan Hajnoczi -Message-id: <20210315181629.212884-3-stefanha@redhat.com> -Patchwork-id: 101340 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 2/6] block/export: fix blk_size double byteswap -Bugzilla: 1937004 -RH-Acked-by: Danilo de Paula -RH-Acked-by: Kevin Wolf -RH-Acked-by: Max Reitz - -The config->blk_size field is little-endian. Use the native-endian -blk_size variable to avoid double byteswapping. - -Fixes: 11f60f7eaee2630dd6fa0c3a8c49f792e46c4cf1 ("block/export: make vhost-user-blk config space little-endian") -Signed-off-by: Stefan Hajnoczi -Message-Id: <20210223144653.811468-8-stefanha@redhat.com> -Signed-off-by: Kevin Wolf -(cherry picked from commit a4f1542af58fd6ab061e594d4e161f1c8b4a4372) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Danilo C. L. de Paula ---- - block/export/vhost-user-blk-server.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c -index 62672d1cb9..3003cff189 100644 ---- a/block/export/vhost-user-blk-server.c -+++ b/block/export/vhost-user-blk-server.c -@@ -354,7 +354,7 @@ vu_blk_initialize_config(BlockDriverState *bs, - config->num_queues = cpu_to_le16(num_queues); - config->max_discard_sectors = cpu_to_le32(32768); - config->max_discard_seg = cpu_to_le32(1); -- config->discard_sector_alignment = cpu_to_le32(config->blk_size >> 9); -+ config->discard_sector_alignment = cpu_to_le32(blk_size >> 9); - config->max_write_zeroes_sectors = cpu_to_le32(32768); - config->max_write_zeroes_seg = cpu_to_le32(1); - } --- -2.27.0 - diff --git a/kvm-block-export-fix-vhost-user-blk-export-sector-number.patch b/kvm-block-export-fix-vhost-user-blk-export-sector-number.patch deleted file mode 100644 index dee1102..0000000 --- a/kvm-block-export-fix-vhost-user-blk-export-sector-number.patch +++ /dev/null @@ -1,53 +0,0 @@ -From e158a830fa229937fcb2ef755b50695abd64533a Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Mon, 15 Mar 2021 18:16:27 -0400 -Subject: [PATCH 11/15] block/export: fix vhost-user-blk export sector number - calculation - -RH-Author: Stefan Hajnoczi -Message-id: <20210315181629.212884-5-stefanha@redhat.com> -Patchwork-id: 101341 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 4/6] block/export: fix vhost-user-blk export sector number calculation -Bugzilla: 1937004 -RH-Acked-by: Danilo de Paula -RH-Acked-by: Kevin Wolf -RH-Acked-by: Max Reitz - -The driver is supposed to honor the blk_size field but the protocol -still uses 512-byte sector numbers. It is incorrect to multiply -req->sector_num by blk_size. - -VIRTIO 1.1 5.2.5 Device Initialization says: - - blk_size can be read to determine the optimal sector size for the - driver to use. This does not affect the units used in the protocol - (always 512 bytes), but awareness of the correct value can affect - performance. - -Fixes: 3578389bcf76c824a5d82e6586a6f0c71e56f2aa ("block/export: vhost-user block device backend server") -Signed-off-by: Stefan Hajnoczi -Message-Id: <20210223144653.811468-10-stefanha@redhat.com> -Signed-off-by: Kevin Wolf -(cherry picked from commit e44362ce317bcc46d409ed6c4a5ed2b46804bcbf) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Danilo C. L. de Paula ---- - block/export/vhost-user-blk-server.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c -index feb139e067..bb07f499c8 100644 ---- a/block/export/vhost-user-blk-server.c -+++ b/block/export/vhost-user-blk-server.c -@@ -144,7 +144,7 @@ static void coroutine_fn vu_blk_virtio_process_req(void *opaque) - break; - } - -- int64_t offset = req->sector_num * vexp->blk_size; -+ int64_t offset = req->sector_num << VIRTIO_BLK_SECTOR_BITS; - QEMUIOVector qiov; - if (is_write) { - qemu_iovec_init_external(&qiov, out_iov, out_num); --- -2.27.0 - diff --git a/kvm-block-export-port-virtio-blk-discard-write-zeroes-in.patch b/kvm-block-export-port-virtio-blk-discard-write-zeroes-in.patch deleted file mode 100644 index 7af3e89..0000000 --- a/kvm-block-export-port-virtio-blk-discard-write-zeroes-in.patch +++ /dev/null @@ -1,199 +0,0 @@ -From 400ddccbcd8ddc13c85dbb7796b15fe9d6a01c1f Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Mon, 15 Mar 2021 18:16:28 -0400 -Subject: [PATCH 12/15] block/export: port virtio-blk discard/write zeroes - input validation - -RH-Author: Stefan Hajnoczi -Message-id: <20210315181629.212884-6-stefanha@redhat.com> -Patchwork-id: 101342 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 5/6] block/export: port virtio-blk discard/write zeroes input validation -Bugzilla: 1937004 -RH-Acked-by: Danilo de Paula -RH-Acked-by: Kevin Wolf -RH-Acked-by: Max Reitz - -Validate discard/write zeroes the same way we do for virtio-blk. Some of -these checks are mandated by the VIRTIO specification, others are -internal to QEMU. - -Signed-off-by: Stefan Hajnoczi -Message-Id: <20210223144653.811468-11-stefanha@redhat.com> -Signed-off-by: Kevin Wolf -(cherry picked from commit db4eadf9f10e19f864d70d1df3a90fbda31b8c06) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Danilo C. L. de Paula ---- - block/export/vhost-user-blk-server.c | 116 +++++++++++++++++++++------ - 1 file changed, 93 insertions(+), 23 deletions(-) - -diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c -index bb07f499c8..937bb5e9b4 100644 ---- a/block/export/vhost-user-blk-server.c -+++ b/block/export/vhost-user-blk-server.c -@@ -29,6 +29,8 @@ - - enum { - VHOST_USER_BLK_NUM_QUEUES_DEFAULT = 1, -+ VHOST_USER_BLK_MAX_DISCARD_SECTORS = 32768, -+ VHOST_USER_BLK_MAX_WRITE_ZEROES_SECTORS = 32768, - }; - struct virtio_blk_inhdr { - unsigned char status; -@@ -65,30 +67,102 @@ static void vu_blk_req_complete(VuBlkReq *req) - free(req); - } - -+static bool vu_blk_sect_range_ok(VuBlkExport *vexp, uint64_t sector, -+ size_t size) -+{ -+ uint64_t nb_sectors = size >> BDRV_SECTOR_BITS; -+ uint64_t total_sectors; -+ -+ if (nb_sectors > BDRV_REQUEST_MAX_SECTORS) { -+ return false; -+ } -+ if ((sector << VIRTIO_BLK_SECTOR_BITS) % vexp->blk_size) { -+ return false; -+ } -+ blk_get_geometry(vexp->export.blk, &total_sectors); -+ if (sector > total_sectors || nb_sectors > total_sectors - sector) { -+ return false; -+ } -+ return true; -+} -+ - static int coroutine_fn --vu_blk_discard_write_zeroes(BlockBackend *blk, struct iovec *iov, -+vu_blk_discard_write_zeroes(VuBlkExport *vexp, struct iovec *iov, - uint32_t iovcnt, uint32_t type) - { -+ BlockBackend *blk = vexp->export.blk; - struct virtio_blk_discard_write_zeroes desc; -- ssize_t size = iov_to_buf(iov, iovcnt, 0, &desc, sizeof(desc)); -+ ssize_t size; -+ uint64_t sector; -+ uint32_t num_sectors; -+ uint32_t max_sectors; -+ uint32_t flags; -+ int bytes; -+ -+ /* Only one desc is currently supported */ -+ if (unlikely(iov_size(iov, iovcnt) > sizeof(desc))) { -+ return VIRTIO_BLK_S_UNSUPP; -+ } -+ -+ size = iov_to_buf(iov, iovcnt, 0, &desc, sizeof(desc)); - if (unlikely(size != sizeof(desc))) { -- error_report("Invalid size %zd, expect %zu", size, sizeof(desc)); -- return -EINVAL; -+ error_report("Invalid size %zd, expected %zu", size, sizeof(desc)); -+ return VIRTIO_BLK_S_IOERR; - } - -- uint64_t range[2] = { le64_to_cpu(desc.sector) << 9, -- le32_to_cpu(desc.num_sectors) << 9 }; -- if (type == VIRTIO_BLK_T_DISCARD) { -- if (blk_co_pdiscard(blk, range[0], range[1]) == 0) { -- return 0; -+ sector = le64_to_cpu(desc.sector); -+ num_sectors = le32_to_cpu(desc.num_sectors); -+ flags = le32_to_cpu(desc.flags); -+ max_sectors = (type == VIRTIO_BLK_T_WRITE_ZEROES) ? -+ VHOST_USER_BLK_MAX_WRITE_ZEROES_SECTORS : -+ VHOST_USER_BLK_MAX_DISCARD_SECTORS; -+ -+ /* This check ensures that 'bytes' fits in an int */ -+ if (unlikely(num_sectors > max_sectors)) { -+ return VIRTIO_BLK_S_IOERR; -+ } -+ -+ bytes = num_sectors << VIRTIO_BLK_SECTOR_BITS; -+ -+ if (unlikely(!vu_blk_sect_range_ok(vexp, sector, bytes))) { -+ return VIRTIO_BLK_S_IOERR; -+ } -+ -+ /* -+ * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for discard -+ * and write zeroes commands if any unknown flag is set. -+ */ -+ if (unlikely(flags & ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) { -+ return VIRTIO_BLK_S_UNSUPP; -+ } -+ -+ if (type == VIRTIO_BLK_T_WRITE_ZEROES) { -+ int blk_flags = 0; -+ -+ if (flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP) { -+ blk_flags |= BDRV_REQ_MAY_UNMAP; -+ } -+ -+ if (blk_co_pwrite_zeroes(blk, sector << VIRTIO_BLK_SECTOR_BITS, -+ bytes, blk_flags) == 0) { -+ return VIRTIO_BLK_S_OK; - } -- } else if (type == VIRTIO_BLK_T_WRITE_ZEROES) { -- if (blk_co_pwrite_zeroes(blk, range[0], range[1], 0) == 0) { -- return 0; -+ } else if (type == VIRTIO_BLK_T_DISCARD) { -+ /* -+ * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for -+ * discard commands if the unmap flag is set. -+ */ -+ if (unlikely(flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) { -+ return VIRTIO_BLK_S_UNSUPP; -+ } -+ -+ if (blk_co_pdiscard(blk, sector << VIRTIO_BLK_SECTOR_BITS, -+ bytes) == 0) { -+ return VIRTIO_BLK_S_OK; - } - } - -- return -EINVAL; -+ return VIRTIO_BLK_S_IOERR; - } - - static void coroutine_fn vu_blk_virtio_process_req(void *opaque) -@@ -177,19 +251,13 @@ static void coroutine_fn vu_blk_virtio_process_req(void *opaque) - } - case VIRTIO_BLK_T_DISCARD: - case VIRTIO_BLK_T_WRITE_ZEROES: { -- int rc; -- - if (!vexp->writable) { - req->in->status = VIRTIO_BLK_S_IOERR; - break; - } - -- rc = vu_blk_discard_write_zeroes(blk, &elem->out_sg[1], out_num, type); -- if (rc == 0) { -- req->in->status = VIRTIO_BLK_S_OK; -- } else { -- req->in->status = VIRTIO_BLK_S_IOERR; -- } -+ req->in->status = vu_blk_discard_write_zeroes(vexp, out_iov, out_num, -+ type); - break; - } - default: -@@ -360,11 +428,13 @@ vu_blk_initialize_config(BlockDriverState *bs, - config->min_io_size = cpu_to_le16(1); - config->opt_io_size = cpu_to_le32(1); - config->num_queues = cpu_to_le16(num_queues); -- config->max_discard_sectors = cpu_to_le32(32768); -+ config->max_discard_sectors = -+ cpu_to_le32(VHOST_USER_BLK_MAX_DISCARD_SECTORS); - config->max_discard_seg = cpu_to_le32(1); - config->discard_sector_alignment = - cpu_to_le32(blk_size >> VIRTIO_BLK_SECTOR_BITS); -- config->max_write_zeroes_sectors = cpu_to_le32(32768); -+ config->max_write_zeroes_sectors -+ = cpu_to_le32(VHOST_USER_BLK_MAX_WRITE_ZEROES_SECTORS); - config->max_write_zeroes_seg = cpu_to_le32(1); - } - --- -2.27.0 - diff --git a/kvm-block-export-port-virtio-blk-read-write-range-check.patch b/kvm-block-export-port-virtio-blk-read-write-range-check.patch deleted file mode 100644 index f35ef1f..0000000 --- a/kvm-block-export-port-virtio-blk-read-write-range-check.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 03aeb30096eb0d48e0b493ed4925b99b0e27979e Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Mon, 15 Mar 2021 18:16:29 -0400 -Subject: [PATCH 13/15] block/export: port virtio-blk read/write range check - -RH-Author: Stefan Hajnoczi -Message-id: <20210315181629.212884-7-stefanha@redhat.com> -Patchwork-id: 101343 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 6/6] block/export: port virtio-blk read/write range check -Bugzilla: 1937004 -RH-Acked-by: Danilo de Paula -RH-Acked-by: Kevin Wolf -RH-Acked-by: Max Reitz - -Check that the sector number and byte count are valid. - -Signed-off-by: Stefan Hajnoczi -Message-Id: <20210223144653.811468-13-stefanha@redhat.com> -Signed-off-by: Kevin Wolf -(cherry picked from commit 05ae4e674e3d47342a7660ae7bc55b393e09f4c7) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Danilo C. L. de Paula ---- - block/export/vhost-user-blk-server.c | 19 ++++++++++++++++--- - 1 file changed, 16 insertions(+), 3 deletions(-) - -diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c -index 937bb5e9b4..dbe3cfb9e8 100644 ---- a/block/export/vhost-user-blk-server.c -+++ b/block/export/vhost-user-blk-server.c -@@ -209,6 +209,8 @@ static void coroutine_fn vu_blk_virtio_process_req(void *opaque) - switch (type & ~VIRTIO_BLK_T_BARRIER) { - case VIRTIO_BLK_T_IN: - case VIRTIO_BLK_T_OUT: { -+ QEMUIOVector qiov; -+ int64_t offset; - ssize_t ret = 0; - bool is_write = type & VIRTIO_BLK_T_OUT; - req->sector_num = le64_to_cpu(req->out.sector); -@@ -218,13 +220,24 @@ static void coroutine_fn vu_blk_virtio_process_req(void *opaque) - break; - } - -- int64_t offset = req->sector_num << VIRTIO_BLK_SECTOR_BITS; -- QEMUIOVector qiov; - if (is_write) { - qemu_iovec_init_external(&qiov, out_iov, out_num); -- ret = blk_co_pwritev(blk, offset, qiov.size, &qiov, 0); - } else { - qemu_iovec_init_external(&qiov, in_iov, in_num); -+ } -+ -+ if (unlikely(!vu_blk_sect_range_ok(vexp, -+ req->sector_num, -+ qiov.size))) { -+ req->in->status = VIRTIO_BLK_S_IOERR; -+ break; -+ } -+ -+ offset = req->sector_num << VIRTIO_BLK_SECTOR_BITS; -+ -+ if (is_write) { -+ ret = blk_co_pwritev(blk, offset, qiov.size, &qiov, 0); -+ } else { - ret = blk_co_preadv(blk, offset, qiov.size, &qiov, 0); - } - if (ret >= 0) { --- -2.27.0 - diff --git a/kvm-block-export-use-VIRTIO_BLK_SECTOR_BITS.patch b/kvm-block-export-use-VIRTIO_BLK_SECTOR_BITS.patch deleted file mode 100644 index 45b022f..0000000 --- a/kvm-block-export-use-VIRTIO_BLK_SECTOR_BITS.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 38097598172fa6b5b66224ee3a17dcc7d8ff6488 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Mon, 15 Mar 2021 18:16:26 -0400 -Subject: [PATCH 10/15] block/export: use VIRTIO_BLK_SECTOR_BITS - -RH-Author: Stefan Hajnoczi -Message-id: <20210315181629.212884-4-stefanha@redhat.com> -Patchwork-id: 101339 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 3/6] block/export: use VIRTIO_BLK_SECTOR_BITS -Bugzilla: 1937004 -RH-Acked-by: Danilo de Paula -RH-Acked-by: Kevin Wolf -RH-Acked-by: Max Reitz - -Use VIRTIO_BLK_SECTOR_BITS and VIRTIO_BLK_SECTOR_SIZE when dealing with -virtio-blk sector numbers. Although the values happen to be the same as -BDRV_SECTOR_BITS and BDRV_SECTOR_SIZE, they are conceptually different. -This makes it clearer when we are dealing with virtio-blk sector units. - -Use VIRTIO_BLK_SECTOR_BITS in vu_blk_initialize_config(). Later patches -will use it the new constants the virtqueue request processing code -path. - -Suggested-by: Max Reitz -Signed-off-by: Stefan Hajnoczi -Message-Id: <20210223144653.811468-9-stefanha@redhat.com> -Signed-off-by: Kevin Wolf -(cherry picked from commit 524bac0744e5abf95856fb9e31c01fd2ef102188) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Danilo C. L. de Paula ---- - block/export/vhost-user-blk-server.c | 15 ++++++++++++--- - 1 file changed, 12 insertions(+), 3 deletions(-) - -diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c -index 3003cff189..feb139e067 100644 ---- a/block/export/vhost-user-blk-server.c -+++ b/block/export/vhost-user-blk-server.c -@@ -20,6 +20,13 @@ - #include "sysemu/block-backend.h" - #include "util/block-helpers.h" - -+/* -+ * Sector units are 512 bytes regardless of the -+ * virtio_blk_config->blk_size value. -+ */ -+#define VIRTIO_BLK_SECTOR_BITS 9 -+#define VIRTIO_BLK_SECTOR_SIZE (1ull << VIRTIO_BLK_SECTOR_BITS) -+ - enum { - VHOST_USER_BLK_NUM_QUEUES_DEFAULT = 1, - }; -@@ -345,7 +352,8 @@ vu_blk_initialize_config(BlockDriverState *bs, - uint32_t blk_size, - uint16_t num_queues) - { -- config->capacity = cpu_to_le64(bdrv_getlength(bs) >> BDRV_SECTOR_BITS); -+ config->capacity = -+ cpu_to_le64(bdrv_getlength(bs) >> VIRTIO_BLK_SECTOR_BITS); - config->blk_size = cpu_to_le32(blk_size); - config->size_max = cpu_to_le32(0); - config->seg_max = cpu_to_le32(128 - 2); -@@ -354,7 +362,8 @@ vu_blk_initialize_config(BlockDriverState *bs, - config->num_queues = cpu_to_le16(num_queues); - config->max_discard_sectors = cpu_to_le32(32768); - config->max_discard_seg = cpu_to_le32(1); -- config->discard_sector_alignment = cpu_to_le32(blk_size >> 9); -+ config->discard_sector_alignment = -+ cpu_to_le32(blk_size >> VIRTIO_BLK_SECTOR_BITS); - config->max_write_zeroes_sectors = cpu_to_le32(32768); - config->max_write_zeroes_seg = cpu_to_le32(1); - } -@@ -381,7 +390,7 @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts, - if (vu_opts->has_logical_block_size) { - logical_block_size = vu_opts->logical_block_size; - } else { -- logical_block_size = BDRV_SECTOR_SIZE; -+ logical_block_size = VIRTIO_BLK_SECTOR_SIZE; - } - check_block_size(exp->id, "logical-block-size", logical_block_size, - &local_err); --- -2.27.0 - diff --git a/kvm-block-move-blk_exp_close_all-to-qemu_cleanup.patch b/kvm-block-move-blk_exp_close_all-to-qemu_cleanup.patch deleted file mode 100644 index dcda5bc..0000000 --- a/kvm-block-move-blk_exp_close_all-to-qemu_cleanup.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 661245e1baf416570295fad0db1fdd5ad8485e33 Mon Sep 17 00:00:00 2001 -From: Sergio Lopez Pascual -Date: Thu, 11 Feb 2021 14:42:08 -0300 -Subject: [PATCH 6/6] block: move blk_exp_close_all() to qemu_cleanup() - -RH-Author: Sergio Lopez Pascual -Message-id: <20210211144208.58930-6-slp@redhat.com> -Patchwork-id: 101052 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 5/5] block: move blk_exp_close_all() to qemu_cleanup() -Bugzilla: 1918966 1918968 -RH-Acked-by: Max Reitz -RH-Acked-by: Kevin Wolf -RH-Acked-by: Eric Blake - -Move blk_exp_close_all() from bdrv_close() to qemu_cleanup(), before -bdrv_drain_all_begin(). - -Export drivers may have coroutines yielding at some point in the block -layer, so we need to shut them down before draining the block layer, -as otherwise they may get stuck blk_wait_while_drained(). - -RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1900505 -Signed-off-by: Sergio Lopez -Message-Id: <20210201125032.44713-3-slp@redhat.com> -Signed-off-by: Kevin Wolf -(cherry picked from commit 1895b977f9a69419ae45cfc25805f71efae32eaf) -Signed-off-by: Sergio Lopez -Signed-off-by: Eduardo Lima (Etrunko) ---- - block.c | 1 - - qemu-nbd.c | 1 + - softmmu/vl.c | 9 +++++++++ - storage-daemon/qemu-storage-daemon.c | 1 + - 4 files changed, 11 insertions(+), 1 deletion(-) - -diff --git a/block.c b/block.c -index 8bfa446f9c..57c60efc7f 100644 ---- a/block.c -+++ b/block.c -@@ -4472,7 +4472,6 @@ static void bdrv_close(BlockDriverState *bs) - void bdrv_close_all(void) - { - assert(job_next(NULL) == NULL); -- blk_exp_close_all(); - - /* Drop references from requests still in flight, such as canceled block - * jobs whose AIO context has not been polled yet */ -diff --git a/qemu-nbd.c b/qemu-nbd.c -index a7075c5419..1d337b7504 100644 ---- a/qemu-nbd.c -+++ b/qemu-nbd.c -@@ -509,6 +509,7 @@ static const char *socket_activation_validate_opts(const char *device, - static void qemu_nbd_shutdown(void) - { - job_cancel_sync_all(); -+ blk_exp_close_all(); - bdrv_close_all(); - } - -diff --git a/softmmu/vl.c b/softmmu/vl.c -index 065d52e8dc..3244ee5e12 100644 ---- a/softmmu/vl.c -+++ b/softmmu/vl.c -@@ -66,6 +66,7 @@ - #include "qemu/log.h" - #include "sysemu/blockdev.h" - #include "hw/block/block.h" -+#include "block/export.h" - #include "migration/misc.h" - #include "migration/snapshot.h" - #include "migration/global_state.h" -@@ -4526,6 +4527,14 @@ void qemu_cleanup(void) - */ - migration_shutdown(); - -+ /* -+ * Close the exports before draining the block layer. The export -+ * drivers may have coroutines yielding on it, so we need to clean -+ * them up before the drain, as otherwise they may be get stuck in -+ * blk_wait_while_drained(). -+ */ -+ blk_exp_close_all(); -+ - /* - * We must cancel all block jobs while the block layer is drained, - * or cancelling will be affected by throttling and thus may block -diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c -index e0c87edbdd..d8d172cc60 100644 ---- a/storage-daemon/qemu-storage-daemon.c -+++ b/storage-daemon/qemu-storage-daemon.c -@@ -314,6 +314,7 @@ int main(int argc, char *argv[]) - main_loop_wait(false); - } - -+ blk_exp_close_all(); - bdrv_drain_all_begin(); - bdrv_close_all(); - --- -2.27.0 - diff --git a/kvm-block-nbd-only-detach-existing-iochannel-from-aio_co.patch b/kvm-block-nbd-only-detach-existing-iochannel-from-aio_co.patch deleted file mode 100644 index 96c0d86..0000000 --- a/kvm-block-nbd-only-detach-existing-iochannel-from-aio_co.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 23d161ad92d783275ad56f3acb663f7a21b809f4 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Mon, 8 Feb 2021 22:56:59 -0300 -Subject: [PATCH 01/54] block/nbd: only detach existing iochannel from - aio_context - -RH-Author: Eric Blake -Message-id: <20210208225701.110110-2-eblake@redhat.com> -Patchwork-id: 101005 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v4 1/3] block/nbd: only detach existing iochannel from aio_context -Bugzilla: 1887883 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Sergio Lopez Pascual -RH-Acked-by: Max Reitz - -From: Roman Kagan - -When the reconnect in NBD client is in progress, the iochannel used for -NBD connection doesn't exist. Therefore an attempt to detach it from -the aio_context of the parent BlockDriverState results in a NULL pointer -dereference. - -The problem is triggerable, in particular, when an outgoing migration is -about to finish, and stopping the dataplane tries to move the -BlockDriverState from the iothread aio_context to the main loop. If the -NBD connection is lost before this point, and the NBD client has entered -the reconnect procedure, QEMU crashes: - - #0 qemu_aio_coroutine_enter (ctx=0x5618056c7580, co=0x0) - at /build/qemu-6MF7tq/qemu-5.0.1/util/qemu-coroutine.c:109 - #1 0x00005618034b1b68 in nbd_client_attach_aio_context_bh ( - opaque=0x561805ed4c00) at /build/qemu-6MF7tq/qemu-5.0.1/block/nbd.c:164 - #2 0x000056180353116b in aio_wait_bh (opaque=0x7f60e1e63700) - at /build/qemu-6MF7tq/qemu-5.0.1/util/aio-wait.c:55 - #3 0x0000561803530633 in aio_bh_call (bh=0x7f60d40a7e80) - at /build/qemu-6MF7tq/qemu-5.0.1/util/async.c:136 - #4 aio_bh_poll (ctx=ctx@entry=0x5618056c7580) - at /build/qemu-6MF7tq/qemu-5.0.1/util/async.c:164 - #5 0x0000561803533e5a in aio_poll (ctx=ctx@entry=0x5618056c7580, - blocking=blocking@entry=true) - at /build/qemu-6MF7tq/qemu-5.0.1/util/aio-posix.c:650 - #6 0x000056180353128d in aio_wait_bh_oneshot (ctx=0x5618056c7580, - cb=, opaque=) - at /build/qemu-6MF7tq/qemu-5.0.1/util/aio-wait.c:71 - #7 0x000056180345c50a in bdrv_attach_aio_context (new_context=0x5618056c7580, - bs=0x561805ed4c00) at /build/qemu-6MF7tq/qemu-5.0.1/block.c:6172 - #8 bdrv_set_aio_context_ignore (bs=bs@entry=0x561805ed4c00, - new_context=new_context@entry=0x5618056c7580, - ignore=ignore@entry=0x7f60e1e63780) - at /build/qemu-6MF7tq/qemu-5.0.1/block.c:6237 - #9 0x000056180345c969 in bdrv_child_try_set_aio_context ( - bs=bs@entry=0x561805ed4c00, ctx=0x5618056c7580, - ignore_child=, errp=) - at /build/qemu-6MF7tq/qemu-5.0.1/block.c:6332 - #10 0x00005618034957db in blk_do_set_aio_context (blk=0x56180695b3f0, - new_context=0x5618056c7580, update_root_node=update_root_node@entry=true, - errp=errp@entry=0x0) - at /build/qemu-6MF7tq/qemu-5.0.1/block/block-backend.c:1989 - #11 0x00005618034980bd in blk_set_aio_context (blk=, - new_context=, errp=errp@entry=0x0) - at /build/qemu-6MF7tq/qemu-5.0.1/block/block-backend.c:2010 - #12 0x0000561803197953 in virtio_blk_data_plane_stop (vdev=) - at /build/qemu-6MF7tq/qemu-5.0.1/hw/block/dataplane/virtio-blk.c:292 - #13 0x00005618033d67bf in virtio_bus_stop_ioeventfd (bus=0x5618056d9f08) - at /build/qemu-6MF7tq/qemu-5.0.1/hw/virtio/virtio-bus.c:245 - #14 0x00005618031c9b2e in virtio_vmstate_change (opaque=0x5618056d9f90, - running=0, state=) - at /build/qemu-6MF7tq/qemu-5.0.1/hw/virtio/virtio.c:3220 - #15 0x0000561803208bfd in vm_state_notify (running=running@entry=0, - state=state@entry=RUN_STATE_FINISH_MIGRATE) - at /build/qemu-6MF7tq/qemu-5.0.1/softmmu/vl.c:1275 - #16 0x0000561803155c02 in do_vm_stop (state=RUN_STATE_FINISH_MIGRATE, - send_stop=) at /build/qemu-6MF7tq/qemu-5.0.1/cpus.c:1032 - #17 0x00005618033e3765 in migration_completion (s=0x5618056e6960) - at /build/qemu-6MF7tq/qemu-5.0.1/migration/migration.c:2914 - #18 migration_iteration_run (s=0x5618056e6960) - at /build/qemu-6MF7tq/qemu-5.0.1/migration/migration.c:3275 - #19 migration_thread (opaque=opaque@entry=0x5618056e6960) - at /build/qemu-6MF7tq/qemu-5.0.1/migration/migration.c:3439 - #20 0x0000561803536ad6 in qemu_thread_start (args=) - at /build/qemu-6MF7tq/qemu-5.0.1/util/qemu-thread-posix.c:519 - #21 0x00007f61085d06ba in start_thread () - from /lib/x86_64-linux-gnu/libpthread.so.0 - #22 0x00007f610830641d in sysctl () from /lib/x86_64-linux-gnu/libc.so.6 - #23 0x0000000000000000 in ?? () - -Fix it by checking that the iochannel is non-null before trying to -detach it from the aio_context. If it is null, no detaching is needed, -and it will get reattached in the proper aio_context once the connection -is reestablished. - -Signed-off-by: Roman Kagan -Reviewed-by: Vladimir Sementsov-Ogievskiy -Message-Id: <20210129073859.683063-2-rvkagan@yandex-team.ru> -Signed-off-by: Eric Blake -(cherry picked from commit 3b5e4db6734d30e551101c0941b2a6140862ba40) -Signed-off-by: Eric Blake -Signed-off-by: Eduardo Lima (Etrunko) ---- - block/nbd.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/block/nbd.c b/block/nbd.c -index 42536702b6..ed7b6df10b 100644 ---- a/block/nbd.c -+++ b/block/nbd.c -@@ -234,7 +234,14 @@ static void nbd_client_detach_aio_context(BlockDriverState *bs) - - /* Timer is deleted in nbd_client_co_drain_begin() */ - assert(!s->reconnect_delay_timer); -- qio_channel_detach_aio_context(QIO_CHANNEL(s->ioc)); -+ /* -+ * If reconnect is in progress we may have no ->ioc. It will be -+ * re-instantiated in the proper aio context once the connection is -+ * reestablished. -+ */ -+ if (s->ioc) { -+ qio_channel_detach_aio_context(QIO_CHANNEL(s->ioc)); -+ } - } - - static void nbd_client_attach_aio_context_bh(void *opaque) --- -2.27.0 - diff --git a/kvm-block-nbd-only-enter-connection-coroutine-if-it-s-pr.patch b/kvm-block-nbd-only-enter-connection-coroutine-if-it-s-pr.patch deleted file mode 100644 index 6ab629c..0000000 --- a/kvm-block-nbd-only-enter-connection-coroutine-if-it-s-pr.patch +++ /dev/null @@ -1,124 +0,0 @@ -From ed5dbeb52152217fc7fe9023327dbacfac8b2322 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Mon, 8 Feb 2021 22:57:00 -0300 -Subject: [PATCH 02/54] block/nbd: only enter connection coroutine if it's - present - -RH-Author: Eric Blake -Message-id: <20210208225701.110110-3-eblake@redhat.com> -Patchwork-id: 101008 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v4 2/3] block/nbd: only enter connection coroutine if it's present -Bugzilla: 1887883 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Sergio Lopez Pascual -RH-Acked-by: Max Reitz - -From: Roman Kagan - -When an NBD block driver state is moved from one aio_context to another -(e.g. when doing a drain in a migration thread), -nbd_client_attach_aio_context_bh is executed that enters the connection -coroutine. - -However, the assumption that ->connection_co is always present here -appears incorrect: the connection may have encountered an error other -than -EIO in the underlying transport, and thus may have decided to quit -rather than keep trying to reconnect, and therefore it may have -terminated the connection coroutine. As a result an attempt to reassign -the client in this state (NBD_CLIENT_QUIT) to a different aio_context -leads to a null pointer dereference: - - #0 qio_channel_detach_aio_context (ioc=0x0) - at /build/qemu-gYtjVn/qemu-5.0.1/io/channel.c:452 - #1 0x0000562a242824b3 in bdrv_detach_aio_context (bs=0x562a268d6a00) - at /build/qemu-gYtjVn/qemu-5.0.1/block.c:6151 - #2 bdrv_set_aio_context_ignore (bs=bs@entry=0x562a268d6a00, - new_context=new_context@entry=0x562a260c9580, - ignore=ignore@entry=0x7feeadc9b780) - at /build/qemu-gYtjVn/qemu-5.0.1/block.c:6230 - #3 0x0000562a24282969 in bdrv_child_try_set_aio_context - (bs=bs@entry=0x562a268d6a00, ctx=0x562a260c9580, - ignore_child=, errp=) - at /build/qemu-gYtjVn/qemu-5.0.1/block.c:6332 - #4 0x0000562a242bb7db in blk_do_set_aio_context (blk=0x562a2735d0d0, - new_context=0x562a260c9580, - update_root_node=update_root_node@entry=true, errp=errp@entry=0x0) - at /build/qemu-gYtjVn/qemu-5.0.1/block/block-backend.c:1989 - #5 0x0000562a242be0bd in blk_set_aio_context (blk=, - new_context=, errp=errp@entry=0x0) - at /build/qemu-gYtjVn/qemu-5.0.1/block/block-backend.c:2010 - #6 0x0000562a23fbd953 in virtio_blk_data_plane_stop (vdev=) - at /build/qemu-gYtjVn/qemu-5.0.1/hw/block/dataplane/virtio-blk.c:292 - #7 0x0000562a241fc7bf in virtio_bus_stop_ioeventfd (bus=0x562a260dbf08) - at /build/qemu-gYtjVn/qemu-5.0.1/hw/virtio/virtio-bus.c:245 - #8 0x0000562a23fefb2e in virtio_vmstate_change (opaque=0x562a260dbf90, - running=0, state=) - at /build/qemu-gYtjVn/qemu-5.0.1/hw/virtio/virtio.c:3220 - #9 0x0000562a2402ebfd in vm_state_notify (running=running@entry=0, - state=state@entry=RUN_STATE_FINISH_MIGRATE) - at /build/qemu-gYtjVn/qemu-5.0.1/softmmu/vl.c:1275 - #10 0x0000562a23f7bc02 in do_vm_stop (state=RUN_STATE_FINISH_MIGRATE, - send_stop=) - at /build/qemu-gYtjVn/qemu-5.0.1/cpus.c:1032 - #11 0x0000562a24209765 in migration_completion (s=0x562a260e83a0) - at /build/qemu-gYtjVn/qemu-5.0.1/migration/migration.c:2914 - #12 migration_iteration_run (s=0x562a260e83a0) - at /build/qemu-gYtjVn/qemu-5.0.1/migration/migration.c:3275 - #13 migration_thread (opaque=opaque@entry=0x562a260e83a0) - at /build/qemu-gYtjVn/qemu-5.0.1/migration/migration.c:3439 - #14 0x0000562a2435ca96 in qemu_thread_start (args=) - at /build/qemu-gYtjVn/qemu-5.0.1/util/qemu-thread-posix.c:519 - #15 0x00007feed31466ba in start_thread (arg=0x7feeadc9c700) - at pthread_create.c:333 - #16 0x00007feed2e7c41d in __GI___sysctl (name=0x0, nlen=608471908, - oldval=0x562a2452b138, oldlenp=0x0, newval=0x562a2452c5e0 - <__func__.28102>, newlen=0) - at ../sysdeps/unix/sysv/linux/sysctl.c:30 - #17 0x0000000000000000 in ?? () - -Fix it by checking that the connection coroutine is non-null before -trying to enter it. If it is null, no entering is needed, as the -connection is probably going down anyway. - -Signed-off-by: Roman Kagan -Reviewed-by: Vladimir Sementsov-Ogievskiy -Message-Id: <20210129073859.683063-3-rvkagan@yandex-team.ru> -Signed-off-by: Eric Blake -(cherry picked from commit ddde5ee769fcc84b96f879d7b94f35268f69ca3b) -Signed-off-by: Eric Blake -Signed-off-by: Eduardo Lima (Etrunko) ---- - block/nbd.c | 16 +++++++++------- - 1 file changed, 9 insertions(+), 7 deletions(-) - -diff --git a/block/nbd.c b/block/nbd.c -index ed7b6df10b..1bdba9fc49 100644 ---- a/block/nbd.c -+++ b/block/nbd.c -@@ -249,13 +249,15 @@ static void nbd_client_attach_aio_context_bh(void *opaque) - BlockDriverState *bs = opaque; - BDRVNBDState *s = (BDRVNBDState *)bs->opaque; - -- /* -- * The node is still drained, so we know the coroutine has yielded in -- * nbd_read_eof(), the only place where bs->in_flight can reach 0, or it is -- * entered for the first time. Both places are safe for entering the -- * coroutine. -- */ -- qemu_aio_coroutine_enter(bs->aio_context, s->connection_co); -+ if (s->connection_co) { -+ /* -+ * The node is still drained, so we know the coroutine has yielded in -+ * nbd_read_eof(), the only place where bs->in_flight can reach 0, or -+ * it is entered for the first time. Both places are safe for entering -+ * the coroutine. -+ */ -+ qemu_aio_coroutine_enter(bs->aio_context, s->connection_co); -+ } - bdrv_dec_in_flight(bs); - } - --- -2.27.0 - diff --git a/kvm-config-enable-VFIO_CCW.patch b/kvm-config-enable-VFIO_CCW.patch deleted file mode 100644 index 50f6fc2..0000000 --- a/kvm-config-enable-VFIO_CCW.patch +++ /dev/null @@ -1,42 +0,0 @@ -From f6e6416e8267d302ba5ec40c2a26bc25cc0d1d55 Mon Sep 17 00:00:00 2001 -From: Cornelia Huck -Date: Fri, 29 Jan 2021 14:40:05 -0500 -Subject: [PATCH 5/5] config: enable VFIO_CCW - -RH-Author: Cornelia Huck -Message-id: <20210129144005.698097-1-cohuck@redhat.com> -Patchwork-id: 100941 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH] config: enable VFIO_CCW -Bugzilla: 1922170 -RH-Acked-by: Alex Williamson -RH-Acked-by: David Hildenbrand -RH-Acked-by: Thomas Huth - -BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1922170 -BRANCH: rhel-av-8.4.0 -UPSTREAM: n/a -BREW: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=34609010 - -Enable vfio-ccw in RHEL AV builds. - -Signed-off-by: Cornelia Huck -Signed-off-by: Eduardo Lima (Etrunko) ---- - default-configs/devices/s390x-rh-devices.mak | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/default-configs/devices/s390x-rh-devices.mak b/default-configs/devices/s390x-rh-devices.mak -index c3c73fe752..08a15f3e01 100644 ---- a/default-configs/devices/s390x-rh-devices.mak -+++ b/default-configs/devices/s390x-rh-devices.mak -@@ -9,6 +9,7 @@ CONFIG_SCSI=y - CONFIG_TERMINAL3270=y - CONFIG_VFIO=y - CONFIG_VFIO_AP=y -+CONFIG_VFIO_CCW=y - CONFIG_VFIO_PCI=y - CONFIG_VHOST_USER=y - CONFIG_VIRTIO_CCW=y --- -2.18.4 - diff --git a/kvm-default-configs-Enable-vhost-user-blk.patch b/kvm-default-configs-Enable-vhost-user-blk.patch deleted file mode 100644 index b56f834..0000000 --- a/kvm-default-configs-Enable-vhost-user-blk.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 5aadfd88a3438cee837d2e7e96fa0801d885d119 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Fri, 19 Feb 2021 16:14:09 -0500 -Subject: [PATCH 18/54] default-configs: Enable vhost-user-blk - -RH-Author: Kevin Wolf -Message-id: <20210219161409.53788-2-kwolf@redhat.com> -Patchwork-id: 101166 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/1] default-configs: Enable vhost-user-blk -Bugzilla: 1930033 -RH-Acked-by: Thomas Huth -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Max Reitz - -Now that we have qemu-storage-daemon with a vhost-user-blk export, -we want to be able to use that in guests. So enable vhost-user-blk in -our build configuration. - -Signed-off-by: Kevin Wolf -Signed-off-by: Danilo C. L. de Paula ---- - default-configs/devices/x86_64-rh-devices.mak | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/default-configs/devices/x86_64-rh-devices.mak b/default-configs/devices/x86_64-rh-devices.mak -index e80877d4e2..993e2c1d2f 100644 ---- a/default-configs/devices/x86_64-rh-devices.mak -+++ b/default-configs/devices/x86_64-rh-devices.mak -@@ -87,6 +87,7 @@ CONFIG_VGA=y - CONFIG_VGA_CIRRUS=y - CONFIG_VGA_PCI=y - CONFIG_VHOST_USER=y -+CONFIG_VHOST_USER_BLK=y - CONFIG_VIRTIO_PCI=y - CONFIG_VIRTIO_VGA=y - CONFIG_VMMOUSE=y --- -2.27.0 - diff --git a/kvm-docs-Add-qemu-storage-daemon-1-manpage-to-meson.buil.patch b/kvm-docs-Add-qemu-storage-daemon-1-manpage-to-meson.buil.patch deleted file mode 100644 index b70409f..0000000 --- a/kvm-docs-Add-qemu-storage-daemon-1-manpage-to-meson.buil.patch +++ /dev/null @@ -1,50 +0,0 @@ -From b3dbe8179b0f73d09bb90cbf92e991a187ef3534 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Tue, 16 Feb 2021 16:19:41 -0500 -Subject: [PATCH 15/54] docs: Add qemu-storage-daemon(1) manpage to meson.build -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Kevin Wolf -Message-id: <20210216161943.126728-4-kwolf@redhat.com> -Patchwork-id: 101104 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 3/5] docs: Add qemu-storage-daemon(1) manpage to meson.build -Bugzilla: 1901323 -RH-Acked-by: Sergio Lopez Pascual -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Max Reitz - -From: Peter Maydell - -In commit 1982e1602d15 we added a new qemu-storage-daemon(1) manpage. -At the moment new manpages have to be listed both in the conf.py for -Sphinx and also in docs/meson.build for Meson. We forgot the second -of those -- correct the omission. - -Signed-off-by: Peter Maydell -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: Alex Bennée -Message-id: 20210108161416.21129-2-peter.maydell@linaro.org -(cherry picked from commit fa56cf7e86f99d5557a4fb730e375777b89d8b50) -Signed-off-by: Kevin Wolf -Signed-off-by: Danilo C. L. de Paula ---- - docs/meson.build | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/docs/meson.build b/docs/meson.build -index 71641b4fe0..fae9849b79 100644 ---- a/docs/meson.build -+++ b/docs/meson.build -@@ -62,6 +62,7 @@ if build_docs - 'qemu-img.1': (have_tools ? 'man1' : ''), - 'qemu-nbd.8': (have_tools ? 'man8' : ''), - 'qemu-pr-helper.8': (have_tools ? 'man8' : ''), -+ 'qemu-storage-daemon.1': (have_tools ? 'man1' : ''), - 'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''), - 'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''), - 'virtiofsd.1': (have_virtiofsd ? 'man1' : ''), --- -2.27.0 - diff --git a/kvm-docs-add-qemu-storage-daemon-1-man-page.patch b/kvm-docs-add-qemu-storage-daemon-1-man-page.patch deleted file mode 100644 index f0cbc3f..0000000 --- a/kvm-docs-add-qemu-storage-daemon-1-man-page.patch +++ /dev/null @@ -1,218 +0,0 @@ -From f3831252e618e420ea24e53dbdee8eb51e8cad3e Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Tue, 16 Feb 2021 16:19:40 -0500 -Subject: [PATCH 14/54] docs: add qemu-storage-daemon(1) man page - -RH-Author: Kevin Wolf -Message-id: <20210216161943.126728-3-kwolf@redhat.com> -Patchwork-id: 101102 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 2/5] docs: add qemu-storage-daemon(1) man page -Bugzilla: 1901323 -RH-Acked-by: Sergio Lopez Pascual -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Max Reitz - -From: Stefan Hajnoczi - -Document the qemu-storage-daemon tool. Most of the command-line options -are identical to their QEMU counterparts. Perhaps Sphinx hxtool -integration could be extended to extract documentation for individual -command-line options so they can be shared. For now the -qemu-storage-daemon simply refers to the qemu(1) man page where the -command-line options are identical. - -Signed-off-by: Stefan Hajnoczi -Message-Id: <20201209103802.350848-3-stefanha@redhat.com> -Signed-off-by: Kevin Wolf -(cherry picked from commit 1982e1602d15313cd82f225e821c37733ece3404) -Signed-off-by: Kevin Wolf -Signed-off-by: Danilo C. L. de Paula ---- - docs/tools/conf.py | 2 + - docs/tools/index.rst | 1 + - docs/tools/qemu-storage-daemon.rst | 148 +++++++++++++++++++++++++++++ - 3 files changed, 151 insertions(+) - create mode 100644 docs/tools/qemu-storage-daemon.rst - -diff --git a/docs/tools/conf.py b/docs/tools/conf.py -index 4760d36ff2..7072d99324 100644 ---- a/docs/tools/conf.py -+++ b/docs/tools/conf.py -@@ -20,6 +20,8 @@ html_theme_options['description'] = \ - man_pages = [ - ('qemu-img', 'qemu-img', u'QEMU disk image utility', - ['Fabrice Bellard'], 1), -+ ('qemu-storage-daemon', 'qemu-storage-daemon', u'QEMU storage daemon', -+ [], 1), - ('qemu-nbd', 'qemu-nbd', u'QEMU Disk Network Block Device Server', - ['Anthony Liguori '], 8), - ('qemu-pr-helper', 'qemu-pr-helper', 'QEMU persistent reservation helper', -diff --git a/docs/tools/index.rst b/docs/tools/index.rst -index b99f86c7c6..3a5829c17a 100644 ---- a/docs/tools/index.rst -+++ b/docs/tools/index.rst -@@ -11,6 +11,7 @@ Contents: - :maxdepth: 2 - - qemu-img -+ qemu-storage-daemon - qemu-nbd - qemu-pr-helper - qemu-trace-stap -diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst -new file mode 100644 -index 0000000000..f63627eaf6 ---- /dev/null -+++ b/docs/tools/qemu-storage-daemon.rst -@@ -0,0 +1,148 @@ -+QEMU Storage Daemon -+=================== -+ -+Synopsis -+-------- -+ -+**qemu-storage-daemon** [options] -+ -+Description -+----------- -+ -+qemu-storage-daemon provides disk image functionality from QEMU, qemu-img, and -+qemu-nbd in a long-running process controlled via QMP commands without running -+a virtual machine. It can export disk images, run block job operations, and -+perform other disk-related operations. The daemon is controlled via a QMP -+monitor and initial configuration from the command-line. -+ -+The daemon offers the following subset of QEMU features: -+ -+* Block nodes -+* Block jobs -+* Block exports -+* Throttle groups -+* Character devices -+* Crypto and secrets -+* QMP -+* IOThreads -+ -+Commands can be sent over a QEMU Monitor Protocol (QMP) connection. See the -+:manpage:`qemu-storage-daemon-qmp-ref(7)` manual page for a description of the -+commands. -+ -+The daemon runs until it is stopped using the ``quit`` QMP command or -+SIGINT/SIGHUP/SIGTERM. -+ -+**Warning:** Never modify images in use by a running virtual machine or any -+other process; this may destroy the image. Also, be aware that querying an -+image that is being modified by another process may encounter inconsistent -+state. -+ -+Options -+------- -+ -+.. program:: qemu-storage-daemon -+ -+Standard options: -+ -+.. option:: -h, --help -+ -+ Display help and exit -+ -+.. option:: -V, --version -+ -+ Display version information and exit -+ -+.. option:: -T, --trace [[enable=]PATTERN][,events=FILE][,file=FILE] -+ -+ .. include:: ../qemu-option-trace.rst.inc -+ -+.. option:: --blockdev BLOCKDEVDEF -+ -+ is a block node definition. See the :manpage:`qemu(1)` manual page for a -+ description of block node properties and the :manpage:`qemu-block-drivers(7)` -+ manual page for a description of driver-specific parameters. -+ -+.. option:: --chardev CHARDEVDEF -+ -+ is a character device definition. See the :manpage:`qemu(1)` manual page for -+ a description of character device properties. A common character device -+ definition configures a UNIX domain socket:: -+ -+ --chardev socket,id=char1,path=/tmp/qmp.sock,server,nowait -+ -+.. option:: --export [type=]nbd,id=,node-name=[,name=][,writable=on|off][,bitmap=] -+ --export [type=]vhost-user-blk,id=,node-name=,addr.type=unix,addr.path=[,writable=on|off][,logical-block-size=][,num-queues=] -+ --export [type=]vhost-user-blk,id=,node-name=,addr.type=fd,addr.str=[,writable=on|off][,logical-block-size=][,num-queues=] -+ -+ is a block export definition. ``node-name`` is the block node that should be -+ exported. ``writable`` determines whether or not the export allows write -+ requests for modifying data (the default is off). -+ -+ The ``nbd`` export type requires ``--nbd-server`` (see below). ``name`` is -+ the NBD export name. ``bitmap`` is the name of a dirty bitmap reachable from -+ the block node, so the NBD client can use NBD_OPT_SET_META_CONTEXT with the -+ metadata context name "qemu:dirty-bitmap:BITMAP" to inspect the bitmap. -+ -+ The ``vhost-user-blk`` export type takes a vhost-user socket address on which -+ it accept incoming connections. Both -+ ``addr.type=unix,addr.path=`` for UNIX domain sockets and -+ ``addr.type=fd,addr.str=`` for file descriptor passing are supported. -+ ``logical-block-size`` sets the logical block size in bytes (the default is -+ 512). ``num-queues`` sets the number of virtqueues (the default is 1). -+ -+.. option:: --monitor MONITORDEF -+ -+ is a QMP monitor definition. See the :manpage:`qemu(1)` manual page for -+ a description of QMP monitor properties. A common QMP monitor definition -+ configures a monitor on character device ``char1``:: -+ -+ --monitor chardev=char1 -+ -+.. option:: --nbd-server addr.type=inet,addr.host=,addr.port=[,tls-creds=][,tls-authz=][,max-connections=] -+ --nbd-server addr.type=unix,addr.path=[,tls-creds=][,tls-authz=][,max-connections=] -+ -+ is a server for NBD exports. Both TCP and UNIX domain sockets are supported. -+ TLS encryption can be configured using ``--object`` tls-creds-* and authz-* -+ secrets (see below). -+ -+ To configure an NBD server on UNIX domain socket path ``/tmp/nbd.sock``:: -+ -+ --nbd-server addr.type=unix,addr.path=/tmp/nbd.sock -+ -+.. option:: --object help -+ --object ,help -+ --object [,=...] -+ -+ is a QEMU user creatable object definition. List object types with ``help``. -+ List object properties with ``,help``. See the :manpage:`qemu(1)` -+ manual page for a description of the object properties. -+ -+Examples -+-------- -+Launch the daemon with QMP monitor socket ``qmp.sock`` so clients can execute -+QMP commands:: -+ -+ $ qemu-storage-daemon \ -+ --chardev socket,path=qmp.sock,server,nowait,id=char1 \ -+ --monitor chardev=char1 -+ -+Export raw image file ``disk.img`` over NBD UNIX domain socket ``nbd.sock``:: -+ -+ $ qemu-storage-daemon \ -+ --blockdev driver=file,node-name=disk,filename=disk.img \ -+ --nbd-server addr.type=unix,addr.path=nbd.sock \ -+ --export type=nbd,id=export,node-name=disk,writable=on -+ -+Export a qcow2 image file ``disk.qcow2`` as a vhosts-user-blk device over UNIX -+domain socket ``vhost-user-blk.sock``:: -+ -+ $ qemu-storage-daemon \ -+ --blockdev driver=file,node-name=file,filename=disk.qcow2 \ -+ --blockdev driver=qcow2,node-name=qcow2,file=file \ -+ --export type=vhost-user-blk,id=export,addr.type=unix,addr.path=vhost-user-blk.sock,node-name=qcow2 -+ -+See also -+-------- -+ -+:manpage:`qemu(1)`, :manpage:`qemu-block-drivers(7)`, :manpage:`qemu-storage-daemon-qmp-ref(7)` --- -2.27.0 - diff --git a/kvm-docs-generate-qemu-storage-daemon-qmp-ref-7-man-page.patch b/kvm-docs-generate-qemu-storage-daemon-qmp-ref-7-man-page.patch deleted file mode 100644 index fbc0235..0000000 --- a/kvm-docs-generate-qemu-storage-daemon-qmp-ref-7-man-page.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 5425716387734e0a782ac633021cd85eb4d4b914 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Tue, 16 Feb 2021 16:19:39 -0500 -Subject: [PATCH 13/54] docs: generate qemu-storage-daemon-qmp-ref(7) man page - -RH-Author: Kevin Wolf -Message-id: <20210216161943.126728-2-kwolf@redhat.com> -Patchwork-id: 101101 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/5] docs: generate qemu-storage-daemon-qmp-ref(7) man page -Bugzilla: 1901323 -RH-Acked-by: Sergio Lopez Pascual -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Max Reitz - -From: Stefan Hajnoczi - -Although individual qemu-storage-daemon QMP commands are identical to -QEMU QMP commands, qemu-storage-daemon only supports a subset of QEMU's -QMP commands. Generate a manual page of just the commands supported by -qemu-storage-daemon so that users know exactly what is available in -qemu-storage-daemon. - -Add an h1 heading in storage-daemon/qapi/qapi-schema.json so that -block-core.json is at the h2 heading level. - -Signed-off-by: Stefan Hajnoczi -Message-Id: <20201209103802.350848-2-stefanha@redhat.com> -Signed-off-by: Kevin Wolf -(cherry picked from commit 23c02ace3508dba5f781ed9ecfde400e462f3a37) -Signed-off-by: Kevin Wolf -Signed-off-by: Danilo C. L. de Paula ---- - docs/interop/conf.py | 2 ++ - docs/interop/index.rst | 1 + - docs/interop/qemu-storage-daemon-qmp-ref.rst | 13 +++++++++++++ - docs/meson.build | 1 + - storage-daemon/qapi/qapi-schema.json | 3 +++ - 5 files changed, 20 insertions(+) - create mode 100644 docs/interop/qemu-storage-daemon-qmp-ref.rst - -diff --git a/docs/interop/conf.py b/docs/interop/conf.py -index 2634ca3410..f4370aaa13 100644 ---- a/docs/interop/conf.py -+++ b/docs/interop/conf.py -@@ -23,4 +23,6 @@ man_pages = [ - [], 7), - ('qemu-qmp-ref', 'qemu-qmp-ref', 'QEMU QMP Reference Manual', - [], 7), -+ ('qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref', -+ 'QEMU Storage Daemon QMP Reference Manual', [], 7), - ] -diff --git a/docs/interop/index.rst b/docs/interop/index.rst -index cd78d679d8..95d56495f6 100644 ---- a/docs/interop/index.rst -+++ b/docs/interop/index.rst -@@ -20,6 +20,7 @@ Contents: - qemu-ga - qemu-ga-ref - qemu-qmp-ref -+ qemu-storage-daemon-qmp-ref - vhost-user - vhost-user-gpu - vhost-vdpa -diff --git a/docs/interop/qemu-storage-daemon-qmp-ref.rst b/docs/interop/qemu-storage-daemon-qmp-ref.rst -new file mode 100644 -index 0000000000..caf9dad23a ---- /dev/null -+++ b/docs/interop/qemu-storage-daemon-qmp-ref.rst -@@ -0,0 +1,13 @@ -+QEMU Storage Daemon QMP Reference Manual -+======================================== -+ -+.. -+ TODO: the old Texinfo manual used to note that this manual -+ is GPL-v2-or-later. We should make that reader-visible -+ both here and in our Sphinx manuals more generally. -+ -+.. -+ TODO: display the QEMU version, both here and in our Sphinx manuals -+ more generally. -+ -+.. qapi-doc:: storage-daemon/qapi/qapi-schema.json -diff --git a/docs/meson.build b/docs/meson.build -index bb8fe4c9e4..71641b4fe0 100644 ---- a/docs/meson.build -+++ b/docs/meson.build -@@ -56,6 +56,7 @@ if build_docs - 'qemu-ga.8': (have_tools ? 'man8' : ''), - 'qemu-ga-ref.7': 'man7', - 'qemu-qmp-ref.7': 'man7', -+ 'qemu-storage-daemon-qmp-ref.7': (have_tools ? 'man7' : ''), - }, - 'tools': { - 'qemu-img.1': (have_tools ? 'man1' : ''), -diff --git a/storage-daemon/qapi/qapi-schema.json b/storage-daemon/qapi/qapi-schema.json -index c6ad5ae1e3..28117c3aac 100644 ---- a/storage-daemon/qapi/qapi-schema.json -+++ b/storage-daemon/qapi/qapi-schema.json -@@ -15,6 +15,9 @@ - - { 'include': '../../qapi/pragma.json' } - -+## -+# = Block devices -+## - { 'include': '../../qapi/block-core.json' } - { 'include': '../../qapi/block-export.json' } - { 'include': '../../qapi/char.json' } --- -2.27.0 - diff --git a/kvm-docs-set-CONFDIR-when-running-sphinx.patch b/kvm-docs-set-CONFDIR-when-running-sphinx.patch deleted file mode 100644 index db8c0c9..0000000 --- a/kvm-docs-set-CONFDIR-when-running-sphinx.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 16130479cc03434a85111608d9d2b0e179dc8b98 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 8 Feb 2021 09:37:30 -0500 -Subject: [PATCH 7/7] docs: set CONFDIR when running sphinx -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20210208093730.1166952-1-marcandre.lureau@redhat.com> -Patchwork-id: 101004 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH] docs: set CONFDIR when running sphinx -Bugzilla: 1902537 -RH-Acked-by: Eduardo Lima (Etrunko) -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Philippe Mathieu-Daudé - -From: Marc-André Lureau - -The default configuration path /etc/qemu can be overriden with configure -options, and the generated documentation used to reflect it. - -Fixes regression introduced in commit -f8aa24ea9a82da38370470c6bc0eaa393999edfe ("meson: sphinx-build"). - -Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1902537 -Signed-off-by: Marc-André Lureau -Message-Id: <20201201183704.299697-1-marcandre.lureau@redhat.com> -Signed-off-by: Paolo Bonzini - -BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1902537 -Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=34816282 - -(cherry picked from commit daf07a6714b111340fe2d0234d1a5287d6ebe0ec) -Signed-off-by: Marc-André Lureau -Signed-off-by: Eduardo Lima (Etrunko) ---- - docs/meson.build | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/docs/meson.build b/docs/meson.build -index ebd85d59f9..bb8fe4c9e4 100644 ---- a/docs/meson.build -+++ b/docs/meson.build -@@ -9,7 +9,7 @@ endif - # Check if tools are available to build documentation. - build_docs = false - if sphinx_build.found() -- SPHINX_ARGS = [sphinx_build] -+ SPHINX_ARGS = ['env', 'CONFDIR=' + qemu_confdir, sphinx_build] - # If we're making warnings fatal, apply this to Sphinx runs as well - if get_option('werror') - SPHINX_ARGS += [ '-W' ] --- -2.18.4 - diff --git a/kvm-failover-Caller-of-this-two-functions-already-have-p.patch b/kvm-failover-Caller-of-this-two-functions-already-have-p.patch deleted file mode 100644 index de38731..0000000 --- a/kvm-failover-Caller-of-this-two-functions-already-have-p.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 4f94bc7cc479dba60fba841608b3da74b940a26d Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:44 -0500 -Subject: [PATCH 47/54] failover: Caller of this two functions already have - primary_dev - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-25-lvivier@redhat.com> -Patchwork-id: 101246 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 24/27] failover: Caller of this two functions already have primary_dev -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -Pass it as an argument. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-26-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 0e9a65c5b168b993b845ec2acb2568328c2353da) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 27 ++++++++++++++------------- - 1 file changed, 14 insertions(+), 13 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 746ed3fb71..b37e9cd1d9 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -3093,17 +3093,17 @@ void virtio_net_set_netclient_name(VirtIONet *n, const char *name, - n->netclient_type = g_strdup(type); - } - --static bool failover_unplug_primary(VirtIONet *n) -+static bool failover_unplug_primary(VirtIONet *n, DeviceState *dev) - { - HotplugHandler *hotplug_ctrl; - PCIDevice *pci_dev; - Error *err = NULL; - -- hotplug_ctrl = qdev_get_hotplug_handler(n->primary_dev); -+ hotplug_ctrl = qdev_get_hotplug_handler(dev); - if (hotplug_ctrl) { -- pci_dev = PCI_DEVICE(n->primary_dev); -+ pci_dev = PCI_DEVICE(dev); - pci_dev->partially_hotplugged = true; -- hotplug_handler_unplug_request(hotplug_ctrl, n->primary_dev, &err); -+ hotplug_handler_unplug_request(hotplug_ctrl, dev, &err); - if (err) { - error_report_err(err); - return false; -@@ -3114,30 +3114,31 @@ static bool failover_unplug_primary(VirtIONet *n) - return true; - } - --static bool failover_replug_primary(VirtIONet *n, Error **errp) -+static bool failover_replug_primary(VirtIONet *n, DeviceState *dev, -+ Error **errp) - { - Error *err = NULL; - HotplugHandler *hotplug_ctrl; -- PCIDevice *pdev = PCI_DEVICE(n->primary_dev); -+ PCIDevice *pdev = PCI_DEVICE(dev); - BusState *primary_bus; - - if (!pdev->partially_hotplugged) { - return true; - } -- primary_bus = n->primary_dev->parent_bus; -+ primary_bus = dev->parent_bus; - if (!primary_bus) { - error_setg(errp, "virtio_net: couldn't find primary bus"); - return false; - } -- qdev_set_parent_bus(n->primary_dev, primary_bus, &error_abort); -+ qdev_set_parent_bus(dev, primary_bus, &error_abort); - qatomic_set(&n->failover_primary_hidden, false); -- hotplug_ctrl = qdev_get_hotplug_handler(n->primary_dev); -+ hotplug_ctrl = qdev_get_hotplug_handler(dev); - if (hotplug_ctrl) { -- hotplug_handler_pre_plug(hotplug_ctrl, n->primary_dev, &err); -+ hotplug_handler_pre_plug(hotplug_ctrl, dev, &err); - if (err) { - goto out; - } -- hotplug_handler_plug(hotplug_ctrl, n->primary_dev, &err); -+ hotplug_handler_plug(hotplug_ctrl, dev, &err); - } - - out: -@@ -3161,7 +3162,7 @@ static void virtio_net_handle_migration_primary(VirtIONet *n, - } - - if (migration_in_setup(s) && !should_be_hidden) { -- if (failover_unplug_primary(n)) { -+ if (failover_unplug_primary(n, n->primary_dev)) { - vmstate_unregister(VMSTATE_IF(n->primary_dev), - qdev_get_vmsd(n->primary_dev), - n->primary_dev); -@@ -3172,7 +3173,7 @@ static void virtio_net_handle_migration_primary(VirtIONet *n, - } - } else if (migration_has_failed(s)) { - /* We already unplugged the device let's plug it back */ -- if (!failover_replug_primary(n, &err)) { -+ if (!failover_replug_primary(n, n->primary_dev, &err)) { - if (err) { - error_report_err(err); - } --- -2.27.0 - diff --git a/kvm-failover-Remove-external-partially_hotplugged-proper.patch b/kvm-failover-Remove-external-partially_hotplugged-proper.patch deleted file mode 100644 index 833b268..0000000 --- a/kvm-failover-Remove-external-partially_hotplugged-proper.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 03ad2d1426775c5c993f59512932c4bbf62206c1 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:25 -0500 -Subject: [PATCH 28/54] failover: Remove external partially_hotplugged property - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-6-lvivier@redhat.com> -Patchwork-id: 101251 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 05/27] failover: Remove external partially_hotplugged property -Bugzilla: 1819991 -RH-Acked-by: Jens Freimann -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -It was only set "once", and with the wrong value. As far as I can see, -libvirt still don't use it. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-7-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 594d308b9314b446ed2ccc42de7b4d57ba1b7118) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 3f658d6246..6ca85627d8 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -3135,10 +3135,6 @@ static bool failover_replug_primary(VirtIONet *n, Error **errp) - } - qdev_set_parent_bus(n->primary_dev, primary_bus, &error_abort); - qatomic_set(&n->primary_should_be_hidden, false); -- if (!qemu_opt_set_bool(n->primary_device_opts, -- "partially_hotplugged", true, errp)) { -- return false; -- } - hotplug_ctrl = qdev_get_hotplug_handler(n->primary_dev); - if (hotplug_ctrl) { - hotplug_handler_pre_plug(hotplug_ctrl, n->primary_dev, &err); --- -2.27.0 - diff --git a/kvm-failover-Remove-memory-leak.patch b/kvm-failover-Remove-memory-leak.patch deleted file mode 100644 index c6d6701..0000000 --- a/kvm-failover-Remove-memory-leak.patch +++ /dev/null @@ -1,60 +0,0 @@ -From e9380df03375e871de088ad5aee8fd19d6ad3794 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:32 -0500 -Subject: [PATCH 35/54] failover: Remove memory leak - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-13-lvivier@redhat.com> -Patchwork-id: 101261 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 12/27] failover: Remove memory leak -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -Two things, at this point: - -* n->primary_device_id has to be set, otherwise - virtio_net_find_primary don't work. So we have a leak here. - -* it has to be exactly the same that prim_dev->id because what - qdev_find_recursive() does is just compare this two values. - -So remove the unneeded assignment and leaky bits. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-14-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 7b3dc2f8c0b817bbe78ba347130b3c99fe2c4470) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 6e5a56a230..70fa372c08 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -854,9 +854,7 @@ static DeviceState *virtio_connect_failover_devices(VirtIONet *n, Error **errp) - Error *err = NULL; - - prim_dev = virtio_net_find_primary(n, &err); -- if (prim_dev) { -- n->primary_device_id = g_strdup(prim_dev->id); -- } else { -+ if (!prim_dev) { - error_propagate(errp, err); - } - --- -2.27.0 - diff --git a/kvm-failover-Remove-primary_dev-member.patch b/kvm-failover-Remove-primary_dev-member.patch deleted file mode 100644 index aff570e..0000000 --- a/kvm-failover-Remove-primary_dev-member.patch +++ /dev/null @@ -1,158 +0,0 @@ -From 52dce3568320900c79e34eb2093058e5c3f60aa9 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:46 -0500 -Subject: [PATCH 49/54] failover: Remove primary_dev member - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-27-lvivier@redhat.com> -Patchwork-id: 101250 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 26/27] failover: Remove primary_dev member -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -Only three uses remained, and we can remove them on that case. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-28-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 21e8709b29cd981c74565e75276ed476c954cbbf) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 55 +++++++++++++++------------------- - include/hw/virtio/virtio-net.h | 1 - - 2 files changed, 24 insertions(+), 32 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 9203d81780..044ac95f6f 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -832,13 +832,31 @@ static char *failover_find_primary_device_id(VirtIONet *n) - return fid.id; - } - -+/** -+ * Find the primary device for this failover virtio-net -+ * -+ * @n: VirtIONet device -+ * @errp: returns an error if this function fails -+ */ -+static DeviceState *failover_find_primary_device(VirtIONet *n) -+{ -+ char *id = failover_find_primary_device_id(n); -+ -+ if (!id) { -+ return NULL; -+ } -+ -+ return qdev_find_recursive(sysbus_get_default(), id); -+} -+ - static void failover_add_primary(VirtIONet *n, Error **errp) - { - Error *err = NULL; - QemuOpts *opts; - char *id; -+ DeviceState *dev = failover_find_primary_device(n); - -- if (n->primary_dev) { -+ if (dev) { - return; - } - -@@ -848,7 +866,7 @@ static void failover_add_primary(VirtIONet *n, Error **errp) - } - opts = qemu_opts_find(qemu_find_opts("device"), id); - if (opts) { -- n->primary_dev = qdev_device_add(opts, &err); -+ dev = qdev_device_add(opts, &err); - if (err) { - qemu_opts_del(opts); - } -@@ -861,23 +879,6 @@ static void failover_add_primary(VirtIONet *n, Error **errp) - error_propagate(errp, err); - } - --/** -- * Find the primary device for this failover virtio-net -- * -- * @n: VirtIONet device -- * @errp: returns an error if this function fails -- */ --static DeviceState *failover_find_primary_device(VirtIONet *n) --{ -- char *id = failover_find_primary_device_id(n); -- -- if (!id) { -- return NULL; -- } -- -- return qdev_find_recursive(sysbus_get_default(), id); --} -- - static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) - { - VirtIONet *n = VIRTIO_NET(vdev); -@@ -933,19 +934,9 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) - qatomic_set(&n->failover_primary_hidden, false); - failover_add_primary(n, &err); - if (err) { -- n->primary_dev = failover_find_primary_device(n); -- failover_add_primary(n, &err); -- if (err) { -- goto out_err; -- } -+ warn_report_err(err); - } - } -- return; -- --out_err: -- if (err) { -- warn_report_err(err); -- } - } - - static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, -@@ -3420,13 +3411,15 @@ static int virtio_net_pre_save(void *opaque) - static bool primary_unplug_pending(void *opaque) - { - DeviceState *dev = opaque; -+ DeviceState *primary; - VirtIODevice *vdev = VIRTIO_DEVICE(dev); - VirtIONet *n = VIRTIO_NET(vdev); - - if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_STANDBY)) { - return false; - } -- return n->primary_dev ? n->primary_dev->pending_deleted_event : false; -+ primary = failover_find_primary_device(n); -+ return primary ? primary->pending_deleted_event : false; - } - - static bool dev_unplug_pending(void *opaque) -diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h -index efef64e02f..7e96d193aa 100644 ---- a/include/hw/virtio/virtio-net.h -+++ b/include/hw/virtio/virtio-net.h -@@ -202,7 +202,6 @@ struct VirtIONet { - AnnounceTimer announce_timer; - bool needs_vnet_hdr_swap; - bool mtu_bypass_backend; -- DeviceState *primary_dev; - /* primary failover device is hidden*/ - bool failover_primary_hidden; - bool failover; --- -2.27.0 - diff --git a/kvm-failover-Remove-primary_device_dict.patch b/kvm-failover-Remove-primary_device_dict.patch deleted file mode 100644 index 74c9aa6..0000000 --- a/kvm-failover-Remove-primary_device_dict.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 277c3c13377cc7f41d4121fdce918df3005fc063 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:31 -0500 -Subject: [PATCH 34/54] failover: Remove primary_device_dict - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-12-lvivier@redhat.com> -Patchwork-id: 101262 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 11/27] failover: Remove primary_device_dict -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -It was only used once. And we have there opts->id, so no need for it. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-13-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 9673a88e97d1eb428872bd261dbf56a0f3c2fd71) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 17 ++++------------- - include/hw/virtio/virtio-net.h | 1 - - 2 files changed, 4 insertions(+), 14 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 953d5c2bc8..6e5a56a230 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -3186,28 +3186,21 @@ static int virtio_net_primary_should_be_hidden(DeviceListener *listener, - if (!device_opts) { - return -1; - } -- n->primary_device_dict = qemu_opts_to_qdict(device_opts, -- n->primary_device_dict); - standby_id = qemu_opt_get(device_opts, "failover_pair_id"); - if (g_strcmp0(standby_id, n->netclient_name) == 0) { - match_found = true; - } else { - match_found = false; - hide = false; -- n->primary_device_dict = NULL; - goto out; - } - - /* failover_primary_hidden is set during feature negotiation */ - hide = qatomic_read(&n->failover_primary_hidden); -- -- if (n->primary_device_dict) { -- g_free(n->primary_device_id); -- n->primary_device_id = g_strdup(qdict_get_try_str( -- n->primary_device_dict, "id")); -- if (!n->primary_device_id) { -- warn_report("primary_device_id not set"); -- } -+ g_free(n->primary_device_id); -+ n->primary_device_id = g_strdup(device_opts->id); -+ if (!n->primary_device_id) { -+ warn_report("primary_device_id not set"); - } - - out: -@@ -3396,8 +3389,6 @@ static void virtio_net_device_unrealize(DeviceState *dev) - if (n->failover) { - device_listener_unregister(&n->primary_listener); - g_free(n->primary_device_id); -- qobject_unref(n->primary_device_dict); -- n->primary_device_dict = NULL; - } - - max_queues = n->multiqueue ? n->max_queues : 1; -diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h -index a055f39dd6..fe353d8299 100644 ---- a/include/hw/virtio/virtio-net.h -+++ b/include/hw/virtio/virtio-net.h -@@ -202,7 +202,6 @@ struct VirtIONet { - AnnounceTimer announce_timer; - bool needs_vnet_hdr_swap; - bool mtu_bypass_backend; -- QDict *primary_device_dict; - DeviceState *primary_dev; - char *primary_device_id; - /* primary failover device is hidden*/ --- -2.27.0 - diff --git a/kvm-failover-Remove-primary_device_opts.patch b/kvm-failover-Remove-primary_device_opts.patch deleted file mode 100644 index e57fb51..0000000 --- a/kvm-failover-Remove-primary_device_opts.patch +++ /dev/null @@ -1,110 +0,0 @@ -From ec36f213983c0ea89fe8db8b44d1105df0bd3dc2 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:29 -0500 -Subject: [PATCH 32/54] failover: Remove primary_device_opts - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-10-lvivier@redhat.com> -Patchwork-id: 101259 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 09/27] failover: Remove primary_device_opts -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -It was really only used once, in failover_add_primary(). Just search -for it on global opts when it is needed. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-11-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 19e49bc2e984bd065719fc3595f35368b3ae87cd) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 21 +++++---------------- - include/hw/virtio/virtio-net.h | 1 - - 2 files changed, 5 insertions(+), 17 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index e334f05352..2a99b0e0f6 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -791,17 +791,17 @@ static inline uint64_t virtio_net_supported_guest_offloads(VirtIONet *n) - static void failover_add_primary(VirtIONet *n, Error **errp) - { - Error *err = NULL; -+ QemuOpts *opts; - - if (n->primary_dev) { - return; - } - -- n->primary_device_opts = qemu_opts_find(qemu_find_opts("device"), -- n->primary_device_id); -- if (n->primary_device_opts) { -- n->primary_dev = qdev_device_add(n->primary_device_opts, &err); -+ opts = qemu_opts_find(qemu_find_opts("device"), n->primary_device_id); -+ if (opts) { -+ n->primary_dev = qdev_device_add(opts, &err); - if (err) { -- qemu_opts_del(n->primary_device_opts); -+ qemu_opts_del(opts); - } - } else { - error_setg(errp, "Primary device not found"); -@@ -856,7 +856,6 @@ static DeviceState *virtio_connect_failover_devices(VirtIONet *n, Error **errp) - prim_dev = virtio_net_find_primary(n, &err); - if (prim_dev) { - n->primary_device_id = g_strdup(prim_dev->id); -- n->primary_device_opts = prim_dev->opts; - } else { - error_propagate(errp, err); - } -@@ -3113,14 +3112,6 @@ static bool failover_replug_primary(VirtIONet *n, Error **errp) - if (!pdev->partially_hotplugged) { - return true; - } -- if (!n->primary_device_opts) { -- n->primary_device_opts = qemu_opts_from_qdict(qemu_find_opts("device"), -- n->primary_device_dict, -- errp); -- if (!n->primary_device_opts) { -- return false; -- } -- } - primary_bus = n->primary_dev->parent_bus; - if (!primary_bus) { - error_setg(errp, "virtio_net: couldn't find primary bus"); -@@ -3211,8 +3202,6 @@ static int virtio_net_primary_should_be_hidden(DeviceListener *listener, - goto out; - } - -- n->primary_device_opts = device_opts; -- - /* failover_primary_hidden is set during feature negotiation */ - hide = qatomic_read(&n->failover_primary_hidden); - -diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h -index ca68be759f..7159e6c0a0 100644 ---- a/include/hw/virtio/virtio-net.h -+++ b/include/hw/virtio/virtio-net.h -@@ -202,7 +202,6 @@ struct VirtIONet { - AnnounceTimer announce_timer; - bool needs_vnet_hdr_swap; - bool mtu_bypass_backend; -- QemuOpts *primary_device_opts; - QDict *primary_device_dict; - DeviceState *primary_dev; - char *primary_device_id; --- -2.27.0 - diff --git a/kvm-failover-Remove-unused-parameter.patch b/kvm-failover-Remove-unused-parameter.patch deleted file mode 100644 index b95c033..0000000 --- a/kvm-failover-Remove-unused-parameter.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 69ba4fc743b29e9e3f595c1e96596204abc1aa0e Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:24 -0500 -Subject: [PATCH 27/54] failover: Remove unused parameter - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-5-lvivier@redhat.com> -Patchwork-id: 101243 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 04/27] failover: Remove unused parameter -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Jens Freimann -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-6-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 82ceb65799855efb0db965a6ef86d81ae1c8bcd7) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 8 +++----- - 1 file changed, 3 insertions(+), 5 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 786d313330..3f658d6246 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -855,9 +855,7 @@ static DeviceState *virtio_net_find_primary(VirtIONet *n, Error **errp) - return dev; - } - --static DeviceState *virtio_connect_failover_devices(VirtIONet *n, -- DeviceState *dev, -- Error **errp) -+static DeviceState *virtio_connect_failover_devices(VirtIONet *n, Error **errp) - { - DeviceState *prim_dev = NULL; - Error *err = NULL; -@@ -928,7 +926,7 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) - qatomic_set(&n->primary_should_be_hidden, false); - failover_add_primary(n, &err); - if (err) { -- n->primary_dev = virtio_connect_failover_devices(n, n->qdev, &err); -+ n->primary_dev = virtio_connect_failover_devices(n, &err); - if (err) { - goto out_err; - } -@@ -3164,7 +3162,7 @@ static void virtio_net_handle_migration_primary(VirtIONet *n, - should_be_hidden = qatomic_read(&n->primary_should_be_hidden); - - if (!n->primary_dev) { -- n->primary_dev = virtio_connect_failover_devices(n, n->qdev, &err); -+ n->primary_dev = virtio_connect_failover_devices(n, &err); - if (!n->primary_dev) { - return; - } --- -2.27.0 - diff --git a/kvm-failover-Rename-bool-to-failover_primary_hidden.patch b/kvm-failover-Rename-bool-to-failover_primary_hidden.patch deleted file mode 100644 index f2c3ff1..0000000 --- a/kvm-failover-Rename-bool-to-failover_primary_hidden.patch +++ /dev/null @@ -1,113 +0,0 @@ -From 6d228bc32fa1e6c9619dc99dc10bfa3a9116bbf0 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:27 -0500 -Subject: [PATCH 30/54] failover: Rename bool to failover_primary_hidden - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-8-lvivier@redhat.com> -Patchwork-id: 101260 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 07/27] failover: Rename bool to failover_primary_hidden -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Jens Freimann -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -You should not use passive naming variables. -And once there, be able to search for them. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-9-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit e2bde83e23d3cfc1d90911c74500fd2e3b0b04fa) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 14 +++++++------- - include/hw/virtio/virtio-net.h | 3 ++- - 2 files changed, 9 insertions(+), 8 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 3e82108d42..c221671852 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -916,7 +916,7 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) - - if (virtio_has_feature(features, VIRTIO_NET_F_STANDBY)) { - qapi_event_send_failover_negotiated(n->netclient_name); -- qatomic_set(&n->primary_should_be_hidden, false); -+ qatomic_set(&n->failover_primary_hidden, false); - failover_add_primary(n, &err); - if (err) { - n->primary_dev = virtio_connect_failover_devices(n, &err); -@@ -3127,7 +3127,7 @@ static bool failover_replug_primary(VirtIONet *n, Error **errp) - return false; - } - qdev_set_parent_bus(n->primary_dev, primary_bus, &error_abort); -- qatomic_set(&n->primary_should_be_hidden, false); -+ qatomic_set(&n->failover_primary_hidden, false); - hotplug_ctrl = qdev_get_hotplug_handler(n->primary_dev); - if (hotplug_ctrl) { - hotplug_handler_pre_plug(hotplug_ctrl, n->primary_dev, &err); -@@ -3148,7 +3148,7 @@ static void virtio_net_handle_migration_primary(VirtIONet *n, - bool should_be_hidden; - Error *err = NULL; - -- should_be_hidden = qatomic_read(&n->primary_should_be_hidden); -+ should_be_hidden = qatomic_read(&n->failover_primary_hidden); - - if (!n->primary_dev) { - n->primary_dev = virtio_connect_failover_devices(n, &err); -@@ -3163,7 +3163,7 @@ static void virtio_net_handle_migration_primary(VirtIONet *n, - qdev_get_vmsd(n->primary_dev), - n->primary_dev); - qapi_event_send_unplug_primary(n->primary_device_id); -- qatomic_set(&n->primary_should_be_hidden, true); -+ qatomic_set(&n->failover_primary_hidden, true); - } else { - warn_report("couldn't unplug primary device"); - } -@@ -3213,8 +3213,8 @@ static int virtio_net_primary_should_be_hidden(DeviceListener *listener, - - n->primary_device_opts = device_opts; - -- /* primary_should_be_hidden is set during feature negotiation */ -- hide = qatomic_read(&n->primary_should_be_hidden); -+ /* failover_primary_hidden is set during feature negotiation */ -+ hide = qatomic_read(&n->failover_primary_hidden); - - if (n->primary_device_dict) { - g_free(n->primary_device_id); -@@ -3271,7 +3271,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) - if (n->failover) { - n->primary_listener.should_be_hidden = - virtio_net_primary_should_be_hidden; -- qatomic_set(&n->primary_should_be_hidden, true); -+ qatomic_set(&n->failover_primary_hidden, true); - device_listener_register(&n->primary_listener); - n->migration_state.notify = virtio_net_migration_state_notifier; - add_migration_state_change_notifier(&n->migration_state); -diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h -index c8da637d40..ca68be759f 100644 ---- a/include/hw/virtio/virtio-net.h -+++ b/include/hw/virtio/virtio-net.h -@@ -207,7 +207,8 @@ struct VirtIONet { - DeviceState *primary_dev; - char *primary_device_id; - char *standby_id; -- bool primary_should_be_hidden; -+ /* primary failover device is hidden*/ -+ bool failover_primary_hidden; - bool failover; - DeviceListener primary_listener; - Notifier migration_state; --- -2.27.0 - diff --git a/kvm-failover-Rename-function-to-hide_device.patch b/kvm-failover-Rename-function-to-hide_device.patch deleted file mode 100644 index bbc86b8..0000000 --- a/kvm-failover-Rename-function-to-hide_device.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 1fbde79ae60990ff0439f3f3bb060f7d723e4910 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:35 -0500 -Subject: [PATCH 38/54] failover: Rename function to hide_device() - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-16-lvivier@redhat.com> -Patchwork-id: 101264 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 15/27] failover: Rename function to hide_device() -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -You should not use pasive. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-17-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit b91ad981b867e15171234efc3f2ab4074d377cef) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/core/qdev.c | 4 ++-- - hw/net/virtio-net.c | 7 +++---- - include/hw/qdev-core.h | 28 +++++++++++++++------------- - 3 files changed, 20 insertions(+), 19 deletions(-) - -diff --git a/hw/core/qdev.c b/hw/core/qdev.c -index 8f4b8f3cc1..cbdff0b6c6 100644 ---- a/hw/core/qdev.c -+++ b/hw/core/qdev.c -@@ -217,8 +217,8 @@ bool qdev_should_hide_device(QemuOpts *opts) - DeviceListener *listener; - - QTAILQ_FOREACH(listener, &device_listeners, link) { -- if (listener->should_be_hidden) { -- if (listener->should_be_hidden(listener, opts)) { -+ if (listener->hide_device) { -+ if (listener->hide_device(listener, opts)) { - return true; - } - } -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 9f12d33da0..747614ff2a 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -3161,8 +3161,8 @@ static void virtio_net_migration_state_notifier(Notifier *notifier, void *data) - virtio_net_handle_migration_primary(n, s); - } - --static bool virtio_net_primary_should_be_hidden(DeviceListener *listener, -- QemuOpts *device_opts) -+static bool failover_hide_primary_device(DeviceListener *listener, -+ QemuOpts *device_opts) - { - VirtIONet *n = container_of(listener, VirtIONet, primary_listener); - bool hide; -@@ -3220,8 +3220,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) - } - - if (n->failover) { -- n->primary_listener.should_be_hidden = -- virtio_net_primary_should_be_hidden; -+ n->primary_listener.hide_device = failover_hide_primary_device; - qatomic_set(&n->failover_primary_hidden, true); - device_listener_register(&n->primary_listener); - n->migration_state.notify = virtio_net_migration_state_notifier; -diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h -index 250f4edef6..6ac86db44e 100644 ---- a/include/hw/qdev-core.h -+++ b/include/hw/qdev-core.h -@@ -81,16 +81,17 @@ typedef void (*BusUnrealize)(BusState *bus); - * - * - * # Hiding a device # -- * To hide a device, a DeviceListener function should_be_hidden() needs to -+ * To hide a device, a DeviceListener function hide_device() needs to - * be registered. -- * It can be used to defer adding a device and therefore hide it from the -- * guest. The handler registering to this DeviceListener can save the QOpts -- * passed to it for re-using it later and must return that it wants the device -- * to be/remain hidden or not. When the handler function decides the device -- * shall not be hidden it will be added in qdev_device_add() and -- * realized as any other device. Otherwise qdev_device_add() will return early -- * without adding the device. The guest will not see a "hidden" device -- * until it was marked don't hide and qdev_device_add called again. -+ * It can be used to defer adding a device and therefore hide it from -+ * the guest. The handler registering to this DeviceListener can save -+ * the QOpts passed to it for re-using it later. It must return if it -+ * wants the device to be hidden or visible. When the handler function -+ * decides the device shall be visible it will be added with -+ * qdev_device_add() and realized as any other device. Otherwise -+ * qdev_device_add() will return early without adding the device. The -+ * guest will not see a "hidden" device until it was marked visible -+ * and qdev_device_add called again. - * - */ - struct DeviceClass { -@@ -196,11 +197,12 @@ struct DeviceListener { - void (*realize)(DeviceListener *listener, DeviceState *dev); - void (*unrealize)(DeviceListener *listener, DeviceState *dev); - /* -- * This callback is called upon init of the DeviceState and allows to -- * inform qdev that a device should be hidden, depending on the device -- * opts, for example, to hide a standby device. -+ * This callback is called upon init of the DeviceState and -+ * informs qdev if a device should be visible or hidden. We can -+ * hide a failover device depending for example on the device -+ * opts. - */ -- bool (*should_be_hidden)(DeviceListener *listener, QemuOpts *device_opts); -+ bool (*hide_device)(DeviceListener *listener, QemuOpts *device_opts); - QTAILQ_ENTRY(DeviceListener) link; - }; - --- -2.27.0 - diff --git a/kvm-failover-Rename-to-failover_find_primary_device.patch b/kvm-failover-Rename-to-failover_find_primary_device.patch deleted file mode 100644 index 89e6060..0000000 --- a/kvm-failover-Rename-to-failover_find_primary_device.patch +++ /dev/null @@ -1,77 +0,0 @@ -From e1ea7c178c1762dca02e2c85f57ccfad1063c753 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:37 -0500 -Subject: [PATCH 40/54] failover: Rename to failover_find_primary_device() - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-18-lvivier@redhat.com> -Patchwork-id: 101263 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 17/27] failover: Rename to failover_find_primary_device() -Bugzilla: 1819991 -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -This commit: -* Rename them to failover_find_primary_devices() so - - it starts with failover_ - - it don't connect anything, just find the primary device -* Create documentation for the function - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-19-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 85d3b93196e43c4493c118aa9e3a82fe657636b5) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 12 +++++++++--- - 1 file changed, 9 insertions(+), 3 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index c6200b924e..ff82f1017d 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -826,7 +826,13 @@ static int is_my_primary(void *opaque, QemuOpts *opts, Error **errp) - return ret; - } - --static DeviceState *virtio_net_find_primary(VirtIONet *n, Error **errp) -+/** -+ * Find the primary device for this failover virtio-net -+ * -+ * @n: VirtIONet device -+ * @errp: returns an error if this function fails -+ */ -+static DeviceState *failover_find_primary_device(VirtIONet *n, Error **errp) - { - Error *err = NULL; - -@@ -891,7 +897,7 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) - qatomic_set(&n->failover_primary_hidden, false); - failover_add_primary(n, &err); - if (err) { -- n->primary_dev = virtio_net_find_primary(n, &err); -+ n->primary_dev = failover_find_primary_device(n, &err); - if (err) { - goto out_err; - } -@@ -3115,7 +3121,7 @@ static void virtio_net_handle_migration_primary(VirtIONet *n, - should_be_hidden = qatomic_read(&n->failover_primary_hidden); - - if (!n->primary_dev) { -- n->primary_dev = virtio_net_find_primary(n, &err); -+ n->primary_dev = failover_find_primary_device(n, &err); - if (!n->primary_dev) { - return; - } --- -2.27.0 - diff --git a/kvm-failover-Use-always-atomics-for-primary_should_be_hi.patch b/kvm-failover-Use-always-atomics-for-primary_should_be_hi.patch deleted file mode 100644 index 41fa84a..0000000 --- a/kvm-failover-Use-always-atomics-for-primary_should_be_hi.patch +++ /dev/null @@ -1,49 +0,0 @@ -From be9147ddedc35a458b976a71fd947634ab71bb44 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:22 -0500 -Subject: [PATCH 25/54] failover: Use always atomics for - primary_should_be_hidden - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-3-lvivier@redhat.com> -Patchwork-id: 101247 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 02/27] failover: Use always atomics for primary_should_be_hidden -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Jens Freimann -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-4-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 587f2fcb93eddf69736e00731a2da018a0e0a726) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 1011a524bf..a0fa63e7cb 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -3136,7 +3136,7 @@ static bool failover_replug_primary(VirtIONet *n, Error **errp) - return false; - } - qdev_set_parent_bus(n->primary_dev, n->primary_bus, &error_abort); -- n->primary_should_be_hidden = false; -+ qatomic_set(&n->primary_should_be_hidden, false); - if (!qemu_opt_set_bool(n->primary_device_opts, - "partially_hotplugged", true, errp)) { - return false; --- -2.27.0 - diff --git a/kvm-failover-We-don-t-need-to-cache-primary_device_id-an.patch b/kvm-failover-We-don-t-need-to-cache-primary_device_id-an.patch deleted file mode 100644 index 1012001..0000000 --- a/kvm-failover-We-don-t-need-to-cache-primary_device_id-an.patch +++ /dev/null @@ -1,128 +0,0 @@ -From 845e4811506c58b8f1f4cfcb183994f1d0f4d66b Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:43 -0500 -Subject: [PATCH 46/54] failover: We don't need to cache primary_device_id - anymore - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-24-lvivier@redhat.com> -Patchwork-id: 101258 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 23/27] failover: We don't need to cache primary_device_id anymore -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-25-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 3abad4a221e050d43fa8540677b285057642baaf) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 20 ++++++++++---------- - include/hw/virtio/virtio-net.h | 1 - - 2 files changed, 10 insertions(+), 11 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 2c502c13fd..746ed3fb71 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -824,6 +824,7 @@ static char *failover_find_primary_device_id(VirtIONet *n) - Error *err = NULL; - FailoverId fid; - -+ fid.n = n; - if (!qemu_opts_foreach(qemu_find_opts("device"), - failover_set_primary, &fid, &err)) { - return NULL; -@@ -835,12 +836,17 @@ static void failover_add_primary(VirtIONet *n, Error **errp) - { - Error *err = NULL; - QemuOpts *opts; -+ char *id; - - if (n->primary_dev) { - return; - } - -- opts = qemu_opts_find(qemu_find_opts("device"), n->primary_device_id); -+ id = failover_find_primary_device_id(n); -+ if (!id) { -+ return; -+ } -+ opts = qemu_opts_find(qemu_find_opts("device"), id); - if (opts) { - n->primary_dev = qdev_device_add(opts, &err); - if (err) { -@@ -868,9 +874,8 @@ static DeviceState *failover_find_primary_device(VirtIONet *n) - if (!id) { - return NULL; - } -- n->primary_device_id = g_strdup(id); - -- return qdev_find_recursive(sysbus_get_default(), n->primary_device_id); -+ return qdev_find_recursive(sysbus_get_default(), id); - } - - static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) -@@ -3160,7 +3165,7 @@ static void virtio_net_handle_migration_primary(VirtIONet *n, - vmstate_unregister(VMSTATE_IF(n->primary_dev), - qdev_get_vmsd(n->primary_dev), - n->primary_dev); -- qapi_event_send_unplug_primary(n->primary_device_id); -+ qapi_event_send_unplug_primary(n->primary_dev->id); - qatomic_set(&n->failover_primary_hidden, true); - } else { - warn_report("couldn't unplug primary device"); -@@ -3186,7 +3191,6 @@ static bool failover_hide_primary_device(DeviceListener *listener, - QemuOpts *device_opts) - { - VirtIONet *n = container_of(listener, VirtIONet, primary_listener); -- bool hide; - const char *standby_id; - - if (!device_opts) { -@@ -3198,10 +3202,7 @@ static bool failover_hide_primary_device(DeviceListener *listener, - } - - /* failover_primary_hidden is set during feature negotiation */ -- hide = qatomic_read(&n->failover_primary_hidden); -- g_free(n->primary_device_id); -- n->primary_device_id = g_strdup(device_opts->id); -- return hide; -+ return qatomic_read(&n->failover_primary_hidden); - } - - static void virtio_net_device_realize(DeviceState *dev, Error **errp) -@@ -3378,7 +3379,6 @@ static void virtio_net_device_unrealize(DeviceState *dev) - - if (n->failover) { - device_listener_unregister(&n->primary_listener); -- g_free(n->primary_device_id); - } - - max_queues = n->multiqueue ? n->max_queues : 1; -diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h -index fe353d8299..efef64e02f 100644 ---- a/include/hw/virtio/virtio-net.h -+++ b/include/hw/virtio/virtio-net.h -@@ -203,7 +203,6 @@ struct VirtIONet { - bool needs_vnet_hdr_swap; - bool mtu_bypass_backend; - DeviceState *primary_dev; -- char *primary_device_id; - /* primary failover device is hidden*/ - bool failover_primary_hidden; - bool failover; --- -2.27.0 - diff --git a/kvm-failover-fix-indentantion.patch b/kvm-failover-fix-indentantion.patch deleted file mode 100644 index 194ae92..0000000 --- a/kvm-failover-fix-indentantion.patch +++ /dev/null @@ -1,171 +0,0 @@ -From 619e58f19e3e20c4144eb1259ce2f338d09176c1 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:21 -0500 -Subject: [PATCH 24/54] failover: fix indentantion - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-2-lvivier@redhat.com> -Patchwork-id: 101240 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 01/27] failover: fix indentantion -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Jens Freimann -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -Once there, remove not needed cast. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-3-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 1c775d65d4bff3a5a9876e398b2e689bc45aa1f7) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 33 +++++++++++++++------------------ - softmmu/qdev-monitor.c | 4 ++-- - 2 files changed, 17 insertions(+), 20 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 9179013ac4..1011a524bf 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -797,7 +797,7 @@ static void failover_add_primary(VirtIONet *n, Error **errp) - } - - n->primary_device_opts = qemu_opts_find(qemu_find_opts("device"), -- n->primary_device_id); -+ n->primary_device_id); - if (n->primary_device_opts) { - n->primary_dev = qdev_device_add(n->primary_device_opts, &err); - if (err) { -@@ -814,9 +814,9 @@ static void failover_add_primary(VirtIONet *n, Error **errp) - } else { - error_setg(errp, "Primary device not found"); - error_append_hint(errp, "Virtio-net failover will not work. Make " -- "sure primary device has parameter" -- " failover_pair_id=\n"); --} -+ "sure primary device has parameter" -+ " failover_pair_id=\n"); -+ } - error_propagate(errp, err); - } - -@@ -824,7 +824,6 @@ static int is_my_primary(void *opaque, QemuOpts *opts, Error **errp) - { - VirtIONet *n = opaque; - int ret = 0; -- - const char *standby_id = qemu_opt_get(opts, "failover_pair_id"); - - if (standby_id != NULL && (g_strcmp0(standby_id, n->netclient_name) == 0)) { -@@ -841,14 +840,14 @@ static DeviceState *virtio_net_find_primary(VirtIONet *n, Error **errp) - Error *err = NULL; - - if (qemu_opts_foreach(qemu_find_opts("device"), -- is_my_primary, n, &err)) { -+ is_my_primary, n, &err)) { - if (err) { - error_propagate(errp, err); - return NULL; - } - if (n->primary_device_id) { - dev = qdev_find_recursive(sysbus_get_default(), -- n->primary_device_id); -+ n->primary_device_id); - } else { - error_setg(errp, "Primary device id not found"); - return NULL; -@@ -857,8 +856,6 @@ static DeviceState *virtio_net_find_primary(VirtIONet *n, Error **errp) - return dev; - } - -- -- - static DeviceState *virtio_connect_failover_devices(VirtIONet *n, - DeviceState *dev, - Error **errp) -@@ -3126,9 +3123,9 @@ static bool failover_replug_primary(VirtIONet *n, Error **errp) - return true; - } - if (!n->primary_device_opts) { -- n->primary_device_opts = qemu_opts_from_qdict( -- qemu_find_opts("device"), -- n->primary_device_dict, errp); -+ n->primary_device_opts = qemu_opts_from_qdict(qemu_find_opts("device"), -+ n->primary_device_dict, -+ errp); - if (!n->primary_device_opts) { - return false; - } -@@ -3176,8 +3173,8 @@ static void virtio_net_handle_migration_primary(VirtIONet *n, - if (migration_in_setup(s) && !should_be_hidden) { - if (failover_unplug_primary(n)) { - vmstate_unregister(VMSTATE_IF(n->primary_dev), -- qdev_get_vmsd(n->primary_dev), -- n->primary_dev); -+ qdev_get_vmsd(n->primary_dev), -+ n->primary_dev); - qapi_event_send_unplug_primary(n->primary_device_id); - qatomic_set(&n->primary_should_be_hidden, true); - } else { -@@ -3201,7 +3198,7 @@ static void virtio_net_migration_state_notifier(Notifier *notifier, void *data) - } - - static int virtio_net_primary_should_be_hidden(DeviceListener *listener, -- QemuOpts *device_opts) -+ QemuOpts *device_opts) - { - VirtIONet *n = container_of(listener, VirtIONet, primary_listener); - bool match_found = false; -@@ -3211,11 +3208,11 @@ static int virtio_net_primary_should_be_hidden(DeviceListener *listener, - return -1; - } - n->primary_device_dict = qemu_opts_to_qdict(device_opts, -- n->primary_device_dict); -+ n->primary_device_dict); - if (n->primary_device_dict) { - g_free(n->standby_id); - n->standby_id = g_strdup(qdict_get_try_str(n->primary_device_dict, -- "failover_pair_id")); -+ "failover_pair_id")); - } - if (g_strcmp0(n->standby_id, n->netclient_name) == 0) { - match_found = true; -@@ -3235,7 +3232,7 @@ static int virtio_net_primary_should_be_hidden(DeviceListener *listener, - if (n->primary_device_dict) { - g_free(n->primary_device_id); - n->primary_device_id = g_strdup(qdict_get_try_str( -- n->primary_device_dict, "id")); -+ n->primary_device_dict, "id")); - if (!n->primary_device_id) { - warn_report("primary_device_id not set"); - } -diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c -index bf79d0bbcd..a25f5d612c 100644 ---- a/softmmu/qdev-monitor.c -+++ b/softmmu/qdev-monitor.c -@@ -573,10 +573,10 @@ void qdev_set_id(DeviceState *dev, const char *id) - } - - static int is_failover_device(void *opaque, const char *name, const char *value, -- Error **errp) -+ Error **errp) - { - if (strcmp(name, "failover_pair_id") == 0) { -- QemuOpts *opts = (QemuOpts *)opaque; -+ QemuOpts *opts = opaque; - - if (qdev_should_hide_device(opts)) { - return 1; --- -2.27.0 - diff --git a/kvm-failover-g_strcmp0-knows-how-to-handle-NULL.patch b/kvm-failover-g_strcmp0-knows-how-to-handle-NULL.patch deleted file mode 100644 index 20c58c0..0000000 --- a/kvm-failover-g_strcmp0-knows-how-to-handle-NULL.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 97b7137652441a3d458f3d9f7bc326047de185c3 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:28 -0500 -Subject: [PATCH 31/54] failover: g_strcmp0() knows how to handle NULL - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-9-lvivier@redhat.com> -Patchwork-id: 101249 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 08/27] failover: g_strcmp0() knows how to handle NULL -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Jens Freimann -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-10-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 518eda9fda49da910d47f5baf66a1c0d1d30cebd) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index c221671852..e334f05352 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -818,7 +818,7 @@ static int is_my_primary(void *opaque, QemuOpts *opts, Error **errp) - int ret = 0; - const char *standby_id = qemu_opt_get(opts, "failover_pair_id"); - -- if (standby_id != NULL && (g_strcmp0(standby_id, n->netclient_name) == 0)) { -+ if (g_strcmp0(standby_id, n->netclient_name) == 0) { - n->primary_device_id = g_strdup(opts->id); - ret = 1; - } --- -2.27.0 - diff --git a/kvm-failover-make-sure-that-id-always-exist.patch b/kvm-failover-make-sure-that-id-always-exist.patch deleted file mode 100644 index ce1ed0a..0000000 --- a/kvm-failover-make-sure-that-id-always-exist.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 06c77533c61f65886bf0a9236d8f13085b2f3e51 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:40 -0500 -Subject: [PATCH 43/54] failover: make sure that id always exist - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-21-lvivier@redhat.com> -Patchwork-id: 101257 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 20/27] failover: make sure that id always exist -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -We check that it exist at device creation time, so we don't have to -check anywhere else. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-22-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit fec037c1e2da0a7ea54eabce65cc14d461fdc5eb) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 3 --- - softmmu/qdev-monitor.c | 4 ++++ - 2 files changed, 4 insertions(+), 3 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index ff82f1017d..c708c03cf6 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -3173,9 +3173,6 @@ static bool failover_hide_primary_device(DeviceListener *listener, - hide = qatomic_read(&n->failover_primary_hidden); - g_free(n->primary_device_id); - n->primary_device_id = g_strdup(device_opts->id); -- if (!n->primary_device_id) { -- warn_report("primary_device_id not set"); -- } - return hide; - } - -diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c -index 0e10f0466f..301089eaea 100644 ---- a/softmmu/qdev-monitor.c -+++ b/softmmu/qdev-monitor.c -@@ -613,6 +613,10 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) - } - - if (qemu_opt_get(opts, "failover_pair_id")) { -+ if (!opts->id) { -+ error_setg(errp, "Device with failover_pair_id don't have id"); -+ return NULL; -+ } - if (qdev_should_hide_device(opts)) { - if (bus && !qbus_is_hotpluggable(bus)) { - error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name); --- -2.27.0 - diff --git a/kvm-failover-primary-bus-is-only-used-once-and-where-it-.patch b/kvm-failover-primary-bus-is-only-used-once-and-where-it-.patch deleted file mode 100644 index b19d5d0..0000000 --- a/kvm-failover-primary-bus-is-only-used-once-and-where-it-.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 0c0190ed0d933a6900230427c374e4b93faab73b Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:23 -0500 -Subject: [PATCH 26/54] failover: primary bus is only used once, and where it - is set - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-4-lvivier@redhat.com> -Patchwork-id: 101245 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 03/27] failover: primary bus is only used once, and where it is set -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Jens Freimann -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -Just remove the struct member. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-5-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 78274682b79d48e8de76c817c67c3cfbb76dc2ee) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 8 ++++---- - include/hw/virtio/virtio-net.h | 1 - - 2 files changed, 4 insertions(+), 5 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index a0fa63e7cb..786d313330 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -804,7 +804,6 @@ static void failover_add_primary(VirtIONet *n, Error **errp) - qemu_opts_del(n->primary_device_opts); - } - if (n->primary_dev) { -- n->primary_bus = n->primary_dev->parent_bus; - if (err) { - qdev_unplug(n->primary_dev, &err); - qdev_set_id(n->primary_dev, ""); -@@ -3118,6 +3117,7 @@ static bool failover_replug_primary(VirtIONet *n, Error **errp) - Error *err = NULL; - HotplugHandler *hotplug_ctrl; - PCIDevice *pdev = PCI_DEVICE(n->primary_dev); -+ BusState *primary_bus; - - if (!pdev->partially_hotplugged) { - return true; -@@ -3130,12 +3130,12 @@ static bool failover_replug_primary(VirtIONet *n, Error **errp) - return false; - } - } -- n->primary_bus = n->primary_dev->parent_bus; -- if (!n->primary_bus) { -+ primary_bus = n->primary_dev->parent_bus; -+ if (!primary_bus) { - error_setg(errp, "virtio_net: couldn't find primary bus"); - return false; - } -- qdev_set_parent_bus(n->primary_dev, n->primary_bus, &error_abort); -+ qdev_set_parent_bus(n->primary_dev, primary_bus, &error_abort); - qatomic_set(&n->primary_should_be_hidden, false); - if (!qemu_opt_set_bool(n->primary_device_opts, - "partially_hotplugged", true, errp)) { -diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h -index f4852ac27b..c8da637d40 100644 ---- a/include/hw/virtio/virtio-net.h -+++ b/include/hw/virtio/virtio-net.h -@@ -205,7 +205,6 @@ struct VirtIONet { - QemuOpts *primary_device_opts; - QDict *primary_device_dict; - DeviceState *primary_dev; -- BusState *primary_bus; - char *primary_device_id; - char *standby_id; - bool primary_should_be_hidden; --- -2.27.0 - diff --git a/kvm-failover-qdev_device_add-returns-err-or-dev-set.patch b/kvm-failover-qdev_device_add-returns-err-or-dev-set.patch deleted file mode 100644 index 7b0dbf2..0000000 --- a/kvm-failover-qdev_device_add-returns-err-or-dev-set.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 63f2415d2cee7bcf24e7f3dc515c5155731071e6 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:26 -0500 -Subject: [PATCH 29/54] failover: qdev_device_add() returns err or dev set - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-7-lvivier@redhat.com> -Patchwork-id: 101252 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 06/27] failover: qdev_device_add() returns err or dev set -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Jens Freimann -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -Never both. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-8-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 3d1c7a9782d19052505aabc8f2c134ccd6f3f3fb) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 7 ------- - 1 file changed, 7 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 6ca85627d8..3e82108d42 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -803,13 +803,6 @@ static void failover_add_primary(VirtIONet *n, Error **errp) - if (err) { - qemu_opts_del(n->primary_device_opts); - } -- if (n->primary_dev) { -- if (err) { -- qdev_unplug(n->primary_dev, &err); -- qdev_set_id(n->primary_dev, ""); -- -- } -- } - } else { - error_setg(errp, "Primary device not found"); - error_append_hint(errp, "Virtio-net failover will not work. Make " --- -2.27.0 - diff --git a/kvm-failover-remove-failover_find_primary_device-error-p.patch b/kvm-failover-remove-failover_find_primary_device-error-p.patch deleted file mode 100644 index aa16347..0000000 --- a/kvm-failover-remove-failover_find_primary_device-error-p.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 96883a1a05766ac6c1a2a064f40aab6c0bd54861 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:41 -0500 -Subject: [PATCH 44/54] failover: remove failover_find_primary_device() error - parameter - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-22-lvivier@redhat.com> -Patchwork-id: 101265 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 21/27] failover: remove failover_find_primary_device() error parameter -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -It can never give one error. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-23-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 0a0a27d66bcb275e5b984d8758880a7eff75464e) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 9 +++------ - 1 file changed, 3 insertions(+), 6 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index c708c03cf6..b994796734 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -832,7 +832,7 @@ static int is_my_primary(void *opaque, QemuOpts *opts, Error **errp) - * @n: VirtIONet device - * @errp: returns an error if this function fails - */ --static DeviceState *failover_find_primary_device(VirtIONet *n, Error **errp) -+static DeviceState *failover_find_primary_device(VirtIONet *n) - { - Error *err = NULL; - -@@ -897,10 +897,7 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) - qatomic_set(&n->failover_primary_hidden, false); - failover_add_primary(n, &err); - if (err) { -- n->primary_dev = failover_find_primary_device(n, &err); -- if (err) { -- goto out_err; -- } -+ n->primary_dev = failover_find_primary_device(n); - failover_add_primary(n, &err); - if (err) { - goto out_err; -@@ -3121,7 +3118,7 @@ static void virtio_net_handle_migration_primary(VirtIONet *n, - should_be_hidden = qatomic_read(&n->failover_primary_hidden); - - if (!n->primary_dev) { -- n->primary_dev = failover_find_primary_device(n, &err); -+ n->primary_dev = failover_find_primary_device(n); - if (!n->primary_dev) { - return; - } --- -2.27.0 - diff --git a/kvm-failover-remove-standby_id-variable.patch b/kvm-failover-remove-standby_id-variable.patch deleted file mode 100644 index c16f2ff..0000000 --- a/kvm-failover-remove-standby_id-variable.patch +++ /dev/null @@ -1,89 +0,0 @@ -From cead8b9c03911360666ac3bb56d7b1db068ade36 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:30 -0500 -Subject: [PATCH 33/54] failover: remove standby_id variable - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-11-lvivier@redhat.com> -Patchwork-id: 101248 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 10/27] failover: remove standby_id variable -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -We can calculate it, and we only use it once anyways. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-12-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 4f0303aed87f83715055e558176046a8a3d9b987) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 11 +++-------- - include/hw/virtio/virtio-net.h | 1 - - 2 files changed, 3 insertions(+), 9 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 2a99b0e0f6..953d5c2bc8 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -3181,23 +3181,19 @@ static int virtio_net_primary_should_be_hidden(DeviceListener *listener, - VirtIONet *n = container_of(listener, VirtIONet, primary_listener); - bool match_found = false; - bool hide = false; -+ const char *standby_id; - - if (!device_opts) { - return -1; - } - n->primary_device_dict = qemu_opts_to_qdict(device_opts, - n->primary_device_dict); -- if (n->primary_device_dict) { -- g_free(n->standby_id); -- n->standby_id = g_strdup(qdict_get_try_str(n->primary_device_dict, -- "failover_pair_id")); -- } -- if (g_strcmp0(n->standby_id, n->netclient_name) == 0) { -+ standby_id = qemu_opt_get(device_opts, "failover_pair_id"); -+ if (g_strcmp0(standby_id, n->netclient_name) == 0) { - match_found = true; - } else { - match_found = false; - hide = false; -- g_free(n->standby_id); - n->primary_device_dict = NULL; - goto out; - } -@@ -3400,7 +3396,6 @@ static void virtio_net_device_unrealize(DeviceState *dev) - if (n->failover) { - device_listener_unregister(&n->primary_listener); - g_free(n->primary_device_id); -- g_free(n->standby_id); - qobject_unref(n->primary_device_dict); - n->primary_device_dict = NULL; - } -diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h -index 7159e6c0a0..a055f39dd6 100644 ---- a/include/hw/virtio/virtio-net.h -+++ b/include/hw/virtio/virtio-net.h -@@ -205,7 +205,6 @@ struct VirtIONet { - QDict *primary_device_dict; - DeviceState *primary_dev; - char *primary_device_id; -- char *standby_id; - /* primary failover device is hidden*/ - bool failover_primary_hidden; - bool failover; --- -2.27.0 - diff --git a/kvm-failover-should_be_hidden-should-take-a-bool.patch b/kvm-failover-should_be_hidden-should-take-a-bool.patch deleted file mode 100644 index b0fb927..0000000 --- a/kvm-failover-should_be_hidden-should-take-a-bool.patch +++ /dev/null @@ -1,144 +0,0 @@ -From 8dadc3183e8e75e47b5f5e39823b9eaf950cf4fe Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:34 -0500 -Subject: [PATCH 37/54] failover: should_be_hidden() should take a bool - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-15-lvivier@redhat.com> -Patchwork-id: 101241 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 14/27] failover: should_be_hidden() should take a bool -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -We didn't use at all the -1 value, and we don't really care. It was -only used for the cases when this is not the device that we are -searching for. And in that case we should not hide the device. - -Once there, simplify virtio-Snet_primary_should_be_hidden. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-16-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 89631fed27bd76b0292d8b2a78291ea96185c87d) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/core/qdev.c | 19 +++++-------------- - hw/net/virtio-net.c | 27 +++++++-------------------- - include/hw/qdev-core.h | 2 +- - 3 files changed, 13 insertions(+), 35 deletions(-) - -diff --git a/hw/core/qdev.c b/hw/core/qdev.c -index 262bca716f..8f4b8f3cc1 100644 ---- a/hw/core/qdev.c -+++ b/hw/core/qdev.c -@@ -214,26 +214,17 @@ void device_listener_unregister(DeviceListener *listener) - - bool qdev_should_hide_device(QemuOpts *opts) - { -- int rc = -1; - DeviceListener *listener; - - QTAILQ_FOREACH(listener, &device_listeners, link) { -- if (listener->should_be_hidden) { -- /* -- * should_be_hidden_will return -- * 1 if device matches opts and it should be hidden -- * 0 if device matches opts and should not be hidden -- * -1 if device doesn't match ops -- */ -- rc = listener->should_be_hidden(listener, opts); -- } -- -- if (rc > 0) { -- break; -+ if (listener->should_be_hidden) { -+ if (listener->should_be_hidden(listener, opts)) { -+ return true; -+ } - } - } - -- return rc > 0; -+ return false; - } - - void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 881907d1bd..9f12d33da0 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -3161,24 +3161,19 @@ static void virtio_net_migration_state_notifier(Notifier *notifier, void *data) - virtio_net_handle_migration_primary(n, s); - } - --static int virtio_net_primary_should_be_hidden(DeviceListener *listener, -- QemuOpts *device_opts) -+static bool virtio_net_primary_should_be_hidden(DeviceListener *listener, -+ QemuOpts *device_opts) - { - VirtIONet *n = container_of(listener, VirtIONet, primary_listener); -- bool match_found = false; -- bool hide = false; -+ bool hide; - const char *standby_id; - - if (!device_opts) { -- return -1; -+ return false; - } - standby_id = qemu_opt_get(device_opts, "failover_pair_id"); -- if (g_strcmp0(standby_id, n->netclient_name) == 0) { -- match_found = true; -- } else { -- match_found = false; -- hide = false; -- goto out; -+ if (g_strcmp0(standby_id, n->netclient_name) != 0) { -+ return false; - } - - /* failover_primary_hidden is set during feature negotiation */ -@@ -3188,15 +3183,7 @@ static int virtio_net_primary_should_be_hidden(DeviceListener *listener, - if (!n->primary_device_id) { - warn_report("primary_device_id not set"); - } -- --out: -- if (match_found && hide) { -- return 1; -- } else if (match_found && !hide) { -- return 0; -- } else { -- return -1; -- } -+ return hide; - } - - static void virtio_net_device_realize(DeviceState *dev, Error **errp) -diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h -index 5e737195b5..250f4edef6 100644 ---- a/include/hw/qdev-core.h -+++ b/include/hw/qdev-core.h -@@ -200,7 +200,7 @@ struct DeviceListener { - * inform qdev that a device should be hidden, depending on the device - * opts, for example, to hide a standby device. - */ -- int (*should_be_hidden)(DeviceListener *listener, QemuOpts *device_opts); -+ bool (*should_be_hidden)(DeviceListener *listener, QemuOpts *device_opts); - QTAILQ_ENTRY(DeviceListener) link; - }; - --- -2.27.0 - diff --git a/kvm-failover-simplify-failover_unplug_primary.patch b/kvm-failover-simplify-failover_unplug_primary.patch deleted file mode 100644 index 523b8ab..0000000 --- a/kvm-failover-simplify-failover_unplug_primary.patch +++ /dev/null @@ -1,86 +0,0 @@ -From cf70ee739171e208243b5b06a57d2517df8c3d91 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:45 -0500 -Subject: [PATCH 48/54] failover: simplify failover_unplug_primary - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-26-lvivier@redhat.com> -Patchwork-id: 101242 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 25/27] failover: simplify failover_unplug_primary -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -We can calculate device just once. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-27-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 07a5d816d50f5f876d5fcd43724a6ff17cf59a4f) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 25 ++++++++++--------------- - 1 file changed, 10 insertions(+), 15 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index b37e9cd1d9..9203d81780 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -3146,34 +3146,29 @@ out: - return !err; - } - --static void virtio_net_handle_migration_primary(VirtIONet *n, -- MigrationState *s) -+static void virtio_net_handle_migration_primary(VirtIONet *n, MigrationState *s) - { - bool should_be_hidden; - Error *err = NULL; -+ DeviceState *dev = failover_find_primary_device(n); - -- should_be_hidden = qatomic_read(&n->failover_primary_hidden); -- -- if (!n->primary_dev) { -- n->primary_dev = failover_find_primary_device(n); -- if (!n->primary_dev) { -- return; -- } -+ if (!dev) { -+ return; - } - -+ should_be_hidden = qatomic_read(&n->failover_primary_hidden); -+ - if (migration_in_setup(s) && !should_be_hidden) { -- if (failover_unplug_primary(n, n->primary_dev)) { -- vmstate_unregister(VMSTATE_IF(n->primary_dev), -- qdev_get_vmsd(n->primary_dev), -- n->primary_dev); -- qapi_event_send_unplug_primary(n->primary_dev->id); -+ if (failover_unplug_primary(n, dev)) { -+ vmstate_unregister(VMSTATE_IF(dev), qdev_get_vmsd(dev), dev); -+ qapi_event_send_unplug_primary(dev->id); - qatomic_set(&n->failover_primary_hidden, true); - } else { - warn_report("couldn't unplug primary device"); - } - } else if (migration_has_failed(s)) { - /* We already unplugged the device let's plug it back */ -- if (!failover_replug_primary(n, n->primary_dev, &err)) { -+ if (!failover_replug_primary(n, dev, &err)) { - if (err) { - error_report_err(err); - } --- -2.27.0 - diff --git a/kvm-failover-simplify-qdev_device_add-failover-case.patch b/kvm-failover-simplify-qdev_device_add-failover-case.patch deleted file mode 100644 index dd04f26..0000000 --- a/kvm-failover-simplify-qdev_device_add-failover-case.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 27a1972d1a5961a8218d5a52fba16b67816635fe Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:38 -0500 -Subject: [PATCH 41/54] failover: simplify qdev_device_add() failover case - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-19-lvivier@redhat.com> -Patchwork-id: 101255 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 18/27] failover: simplify qdev_device_add() failover case -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -Just put allthe logic inside the same if. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-20-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 5f2ef3b0d032797b6bad9449dfece3a8111a8529) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - softmmu/qdev-monitor.c | 11 ++++++----- - 1 file changed, 6 insertions(+), 5 deletions(-) - -diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c -index a25f5d612c..12b7540f17 100644 ---- a/softmmu/qdev-monitor.c -+++ b/softmmu/qdev-monitor.c -@@ -600,7 +600,6 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) - const char *driver, *path; - DeviceState *dev = NULL; - BusState *bus = NULL; -- bool hide; - - driver = qemu_opt_get(opts, "driver"); - if (!driver) { -@@ -634,14 +633,16 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) - return NULL; - } - } -- hide = should_hide_device(opts); - -- if ((hide || qdev_hotplug) && bus && !qbus_is_hotpluggable(bus)) { -- error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name); -+ if (should_hide_device(opts)) { -+ if (bus && !qbus_is_hotpluggable(bus)) { -+ error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name); -+ } - return NULL; - } - -- if (hide) { -+ if (qdev_hotplug && bus && !qbus_is_hotpluggable(bus)) { -+ error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name); - return NULL; - } - --- -2.27.0 - diff --git a/kvm-failover-simplify-qdev_device_add.patch b/kvm-failover-simplify-qdev_device_add.patch deleted file mode 100644 index d69b72e..0000000 --- a/kvm-failover-simplify-qdev_device_add.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 7822f8042e26cca6c1307e26c6f08d5f99636d90 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:39 -0500 -Subject: [PATCH 42/54] failover: simplify qdev_device_add() - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-20-lvivier@redhat.com> -Patchwork-id: 101256 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 19/27] failover: simplify qdev_device_add() -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -We don't need to walk the opts by hand. qmp_opt_get() already does -that. And then we can remove the functions that did that walk. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-21-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 2e28095369f4eab516852fd49dde17c3bfd782f9) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - softmmu/qdev-monitor.c | 32 ++++++-------------------------- - 1 file changed, 6 insertions(+), 26 deletions(-) - -diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c -index 12b7540f17..0e10f0466f 100644 ---- a/softmmu/qdev-monitor.c -+++ b/softmmu/qdev-monitor.c -@@ -572,28 +572,6 @@ void qdev_set_id(DeviceState *dev, const char *id) - } - } - --static int is_failover_device(void *opaque, const char *name, const char *value, -- Error **errp) --{ -- if (strcmp(name, "failover_pair_id") == 0) { -- QemuOpts *opts = opaque; -- -- if (qdev_should_hide_device(opts)) { -- return 1; -- } -- } -- -- return 0; --} -- --static bool should_hide_device(QemuOpts *opts) --{ -- if (qemu_opt_foreach(opts, is_failover_device, opts, NULL) == 0) { -- return false; -- } -- return true; --} -- - DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) - { - DeviceClass *dc; -@@ -634,11 +612,13 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) - } - } - -- if (should_hide_device(opts)) { -- if (bus && !qbus_is_hotpluggable(bus)) { -- error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name); -+ if (qemu_opt_get(opts, "failover_pair_id")) { -+ if (qdev_should_hide_device(opts)) { -+ if (bus && !qbus_is_hotpluggable(bus)) { -+ error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name); -+ } -+ return NULL; - } -- return NULL; - } - - if (qdev_hotplug && bus && !qbus_is_hotpluggable(bus)) { --- -2.27.0 - diff --git a/kvm-failover-simplify-virtio_net_find_primary.patch b/kvm-failover-simplify-virtio_net_find_primary.patch deleted file mode 100644 index 63e35aa..0000000 --- a/kvm-failover-simplify-virtio_net_find_primary.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 24bd4b43c3f59c9c28f924da8ef7a9dacc0f2f52 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:33 -0500 -Subject: [PATCH 36/54] failover: simplify virtio_net_find_primary() - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-14-lvivier@redhat.com> -Patchwork-id: 101253 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 13/27] failover: simplify virtio_net_find_primary() -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -a - is_my_primary() never sets one error -b - If we return 1, primary_device_id is always set - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-15-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 7cf05b7ed8e84e89b873701e3dfcd56aa81b2d13) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 18 +++--------------- - 1 file changed, 3 insertions(+), 15 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 70fa372c08..881907d1bd 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -828,24 +828,12 @@ static int is_my_primary(void *opaque, QemuOpts *opts, Error **errp) - - static DeviceState *virtio_net_find_primary(VirtIONet *n, Error **errp) - { -- DeviceState *dev = NULL; - Error *err = NULL; - -- if (qemu_opts_foreach(qemu_find_opts("device"), -- is_my_primary, n, &err)) { -- if (err) { -- error_propagate(errp, err); -- return NULL; -- } -- if (n->primary_device_id) { -- dev = qdev_find_recursive(sysbus_get_default(), -- n->primary_device_id); -- } else { -- error_setg(errp, "Primary device id not found"); -- return NULL; -- } -+ if (!qemu_opts_foreach(qemu_find_opts("device"), is_my_primary, n, &err)) { -+ return NULL; - } -- return dev; -+ return qdev_find_recursive(sysbus_get_default(), n->primary_device_id); - } - - static DeviceState *virtio_connect_failover_devices(VirtIONet *n, Error **errp) --- -2.27.0 - diff --git a/kvm-failover-split-failover_find_primary_device_id.patch b/kvm-failover-split-failover_find_primary_device_id.patch deleted file mode 100644 index 2b7efbb..0000000 --- a/kvm-failover-split-failover_find_primary_device_id.patch +++ /dev/null @@ -1,128 +0,0 @@ -From 2e3e87787776632d521ec5f08758973d42fc208e Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:42 -0500 -Subject: [PATCH 45/54] failover: split failover_find_primary_device_id() - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-23-lvivier@redhat.com> -Patchwork-id: 101244 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 22/27] failover: split failover_find_primary_device_id() -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -So we can calculate the device id when we need it. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-24-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit f5e1847ba50a8d1adf66c0cf312e53c162e52487) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 63 +++++++++++++++++++++++++++++++++------------ - 1 file changed, 47 insertions(+), 16 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index b994796734..2c502c13fd 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -788,6 +788,49 @@ static inline uint64_t virtio_net_supported_guest_offloads(VirtIONet *n) - return virtio_net_guest_offloads_by_features(vdev->guest_features); - } - -+typedef struct { -+ VirtIONet *n; -+ char *id; -+} FailoverId; -+ -+/** -+ * Set the id of the failover primary device -+ * -+ * @opaque: FailoverId to setup -+ * @opts: opts for device we are handling -+ * @errp: returns an error if this function fails -+ */ -+static int failover_set_primary(void *opaque, QemuOpts *opts, Error **errp) -+{ -+ FailoverId *fid = opaque; -+ const char *standby_id = qemu_opt_get(opts, "failover_pair_id"); -+ -+ if (g_strcmp0(standby_id, fid->n->netclient_name) == 0) { -+ fid->id = g_strdup(opts->id); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+/** -+ * Find the primary device id for this failover virtio-net -+ * -+ * @n: VirtIONet device -+ * @errp: returns an error if this function fails -+ */ -+static char *failover_find_primary_device_id(VirtIONet *n) -+{ -+ Error *err = NULL; -+ FailoverId fid; -+ -+ if (!qemu_opts_foreach(qemu_find_opts("device"), -+ failover_set_primary, &fid, &err)) { -+ return NULL; -+ } -+ return fid.id; -+} -+ - static void failover_add_primary(VirtIONet *n, Error **errp) - { - Error *err = NULL; -@@ -812,20 +855,6 @@ static void failover_add_primary(VirtIONet *n, Error **errp) - error_propagate(errp, err); - } - --static int is_my_primary(void *opaque, QemuOpts *opts, Error **errp) --{ -- VirtIONet *n = opaque; -- int ret = 0; -- const char *standby_id = qemu_opt_get(opts, "failover_pair_id"); -- -- if (g_strcmp0(standby_id, n->netclient_name) == 0) { -- n->primary_device_id = g_strdup(opts->id); -- ret = 1; -- } -- -- return ret; --} -- - /** - * Find the primary device for this failover virtio-net - * -@@ -834,11 +863,13 @@ static int is_my_primary(void *opaque, QemuOpts *opts, Error **errp) - */ - static DeviceState *failover_find_primary_device(VirtIONet *n) - { -- Error *err = NULL; -+ char *id = failover_find_primary_device_id(n); - -- if (!qemu_opts_foreach(qemu_find_opts("device"), is_my_primary, n, &err)) { -+ if (!id) { - return NULL; - } -+ n->primary_device_id = g_strdup(id); -+ - return qdev_find_recursive(sysbus_get_default(), n->primary_device_id); - } - --- -2.27.0 - diff --git a/kvm-failover-virtio_net_connect_failover_devices-does-no.patch b/kvm-failover-virtio_net_connect_failover_devices-does-no.patch deleted file mode 100644 index e04a77f..0000000 --- a/kvm-failover-virtio_net_connect_failover_devices-does-no.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 385df1f898e08c9cf0c90e543978cc68ee0c1097 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:36 -0500 -Subject: [PATCH 39/54] failover: virtio_net_connect_failover_devices() does - nothing - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-17-lvivier@redhat.com> -Patchwork-id: 101254 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 16/27] failover: virtio_net_connect_failover_devices() does nothing -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -From: Juan Quintela - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -It just calls virtio_net_find_primary(), so just update the callers. - -Signed-off-by: Juan Quintela -Message-Id: <20201118083748.1328-18-quintela@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 0763db4f2df3a92336d78e8b68a665f7d1a1bc66) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 17 ++--------------- - 1 file changed, 2 insertions(+), 15 deletions(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 747614ff2a..c6200b924e 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -836,19 +836,6 @@ static DeviceState *virtio_net_find_primary(VirtIONet *n, Error **errp) - return qdev_find_recursive(sysbus_get_default(), n->primary_device_id); - } - --static DeviceState *virtio_connect_failover_devices(VirtIONet *n, Error **errp) --{ -- DeviceState *prim_dev = NULL; -- Error *err = NULL; -- -- prim_dev = virtio_net_find_primary(n, &err); -- if (!prim_dev) { -- error_propagate(errp, err); -- } -- -- return prim_dev; --} -- - static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) - { - VirtIONet *n = VIRTIO_NET(vdev); -@@ -904,7 +891,7 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) - qatomic_set(&n->failover_primary_hidden, false); - failover_add_primary(n, &err); - if (err) { -- n->primary_dev = virtio_connect_failover_devices(n, &err); -+ n->primary_dev = virtio_net_find_primary(n, &err); - if (err) { - goto out_err; - } -@@ -3128,7 +3115,7 @@ static void virtio_net_handle_migration_primary(VirtIONet *n, - should_be_hidden = qatomic_read(&n->failover_primary_hidden); - - if (!n->primary_dev) { -- n->primary_dev = virtio_connect_failover_devices(n, &err); -+ n->primary_dev = virtio_net_find_primary(n, &err); - if (!n->primary_dev) { - return; - } --- -2.27.0 - diff --git a/kvm-hw-arm-smmuv3-Fix-addr_mask-for-range-based-invalida.patch b/kvm-hw-arm-smmuv3-Fix-addr_mask-for-range-based-invalida.patch deleted file mode 100644 index 1ac03d4..0000000 --- a/kvm-hw-arm-smmuv3-Fix-addr_mask-for-range-based-invalida.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 9768ea83a3f23f112514ad34d4abcd6e9590bb71 Mon Sep 17 00:00:00 2001 -From: Auger Eric -Date: Wed, 3 Feb 2021 20:31:27 -0500 -Subject: [PATCH 4/7] hw/arm/smmuv3: Fix addr_mask for range-based invalidation -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Auger Eric -Message-id: <20210203203127.3613-1-eric.auger@redhat.com> -Patchwork-id: 100971 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH] hw/arm/smmuv3: Fix addr_mask for range-based invalidation -Bugzilla: 1834152 -RH-Acked-by: Gavin Shan -RH-Acked-by: Philippe Mathieu-Daudé -RH-Acked-by: Andrew Jones - -From: Zenghui Yu - -BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1834152 -BRANCH: rhel-av-8.4.0 -UPSTREAM: yes -BREW: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=34711554 - -When handling guest range-based IOTLB invalidation, we should decode the TG -field into the corresponding translation granule size so that we can pass -the correct invalidation range to backend. Set @granule to (tg * 2 + 10) to -properly emulate the architecture. - -Fixes: d52915616c05 ("hw/arm/smmuv3: Get prepared for range invalidation") -Signed-off-by: Zenghui Yu -Acked-by: Eric Auger -Message-id: 20210130043220.1345-1-yuzenghui@huawei.com -Signed-off-by: Peter Maydell -(cherry picked from commit dcda883cd21125c699419a3fc0fe182ea989d9c4) -Signed-off-by: Eric Auger -Signed-off-by: Eduardo Lima (Etrunko) ---- - hw/arm/smmuv3.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index bbca0e9f20..98b99d4fe8 100644 ---- a/hw/arm/smmuv3.c -+++ b/hw/arm/smmuv3.c -@@ -801,7 +801,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, - { - SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu); - IOMMUTLBEvent event; -- uint8_t granule = tg; -+ uint8_t granule; - - if (!tg) { - SMMUEventInfo event = {.inval_ste_allowed = true}; -@@ -821,6 +821,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr, - return; - } - granule = tt->granule_sz; -+ } else { -+ granule = tg * 2 + 10; - } - - event.type = IOMMU_NOTIFIER_UNMAP; --- -2.18.4 - diff --git a/kvm-hw-intc-arm_gic-Fix-interrupt-ID-in-GICD_SGIR-regist.patch b/kvm-hw-intc-arm_gic-Fix-interrupt-ID-in-GICD_SGIR-regist.patch deleted file mode 100644 index a6227d9..0000000 --- a/kvm-hw-intc-arm_gic-Fix-interrupt-ID-in-GICD_SGIR-regist.patch +++ /dev/null @@ -1,80 +0,0 @@ -From efdd1b8911d5ae5c0eacbc63fd4fe85f0cc4614b Mon Sep 17 00:00:00 2001 -From: Jon Maloy -Date: Sun, 14 Mar 2021 15:54:19 -0400 -Subject: [PATCH 06/15] hw/intc/arm_gic: Fix interrupt ID in GICD_SGIR register -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Jon Maloy -Message-id: <20210314155419.911760-2-jmaloy@redhat.com> -Patchwork-id: 101336 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/1] hw/intc/arm_gic: Fix interrupt ID in GICD_SGIR register -Bugzilla: 1936948 -RH-Acked-by: Auger Eric -RH-Acked-by: Andrew Jones -RH-Acked-by: Philippe Mathieu-Daudé - -From: Philippe Mathieu-Daudé - -Per the ARM Generic Interrupt Controller Architecture specification -(document "ARM IHI 0048B.b (ID072613)"), the SGIINTID field is 4 bit, -not 10: - - - 4.3 Distributor register descriptions - - 4.3.15 Software Generated Interrupt Register, GICD_SG - - - Table 4-21 GICD_SGIR bit assignments - - The Interrupt ID of the SGI to forward to the specified CPU - interfaces. The value of this field is the Interrupt ID, in - the range 0-15, for example a value of 0b0011 specifies - Interrupt ID 3. - -Correct the irq mask to fix an undefined behavior (which eventually -lead to a heap-buffer-overflow, see [Buglink]): - - $ echo 'writel 0x8000f00 0xff4affb0' | qemu-system-aarch64 -M virt,accel=qtest -qtest stdio - [I 1612088147.116987] OPENED - [R +0.278293] writel 0x8000f00 0xff4affb0 - ../hw/intc/arm_gic.c:1498:13: runtime error: index 944 out of bounds for type 'uint8_t [16][8]' - SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ../hw/intc/arm_gic.c:1498:13 - -This fixes a security issue when running with KVM on Arm with -kernel-irqchip=off. (The default is kernel-irqchip=on, which is -unaffected, and which is also the correct choice for performance.) - -Cc: qemu-stable@nongnu.org -Fixes: CVE-2021-20221 -Fixes: 9ee6e8bb853 ("ARMv7 support.") -Buglink: https://bugs.launchpad.net/qemu/+bug/1913916 -Buglink: https://bugs.launchpad.net/qemu/+bug/1913917 -Reported-by: Alexander Bulekov -Signed-off-by: Philippe Mathieu-Daudé -Message-id: 20210131103401.217160-1-f4bug@amsat.org -Reviewed-by: Peter Maydell -Signed-off-by: Peter Maydell - -(cherry picked from commit edfe2eb4360cde4ed5d95bda7777edcb3510f76a) -Signed-off-by: Jon Maloy -Signed-off-by: Danilo C. L. de Paula ---- - hw/intc/arm_gic.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c -index c60dc6b5e6..fbde60de05 100644 ---- a/hw/intc/arm_gic.c -+++ b/hw/intc/arm_gic.c -@@ -1474,7 +1474,7 @@ static void gic_dist_writel(void *opaque, hwaddr offset, - int target_cpu; - - cpu = gic_get_current_cpu(s); -- irq = value & 0x3ff; -+ irq = value & 0xf; - switch ((value >> 24) & 3) { - case 0: - mask = (value >> 16) & ALL_CPU_MASK; --- -2.27.0 - diff --git a/kvm-i386-Add-the-support-for-AMD-EPYC-3rd-generation-pro.patch b/kvm-i386-Add-the-support-for-AMD-EPYC-3rd-generation-pro.patch deleted file mode 100644 index 2e75110..0000000 --- a/kvm-i386-Add-the-support-for-AMD-EPYC-3rd-generation-pro.patch +++ /dev/null @@ -1,213 +0,0 @@ -From 78375038a68fee2e7b182b4f191d5ba53fbdcd72 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Tue, 23 Feb 2021 15:18:11 -0500 -Subject: [PATCH 52/54] i386: Add the support for AMD EPYC 3rd generation - processors - -RH-Author: Dr. David Alan Gilbert -Message-id: <20210223151811.27968-3-dgilbert@redhat.com> -Patchwork-id: 101198 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 2/2] i386: Add the support for AMD EPYC 3rd generation processors -Bugzilla: 1926785 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Sergio Lopez Pascual -RH-Acked-by: Peter Xu - -From: Babu Moger - -Adds the support for AMD 3rd generation processors. The model -display for the new processor will be EPYC-Milan. - -Adds the following new feature bits on top of the feature bits from -the first and second generation EPYC models. - -pcid : Process context identifiers support -ibrs : Indirect Branch Restricted Speculation -ssbd : Speculative Store Bypass Disable -erms : Enhanced REP MOVSB/STOSB support -fsrm : Fast Short REP MOVSB support -invpcid : Invalidate processor context ID -pku : Protection keys support -svme-addr-chk : SVM instructions address check for #GP handling - -Depends on the following kernel commits: -14c2bf81fcd2 ("KVM: SVM: Fix #GP handling for doubly-nested virtualization") -3b9c723ed7cf ("KVM: SVM: Add support for SVM instruction address check change") -4aa2691dcbd3 ("8ce1c461188799d863398dd2865d KVM: x86: Factor out x86 instruction emulation with decoding") -4407a797e941 ("KVM: SVM: Enable INVPCID feature on AMD") -9715092f8d7e ("KVM: X86: Move handling of INVPCID types to x86") -3f3393b3ce38 ("KVM: X86: Rename and move the function vmx_handle_memory_failure to x86.c") -830bd71f2c06 ("KVM: SVM: Remove set_cr_intercept, clr_cr_intercept and is_cr_intercept") -4c44e8d6c193 ("KVM: SVM: Add new intercept word in vmcb_control_area") -c62e2e94b9d4 ("KVM: SVM: Modify 64 bit intercept field to two 32 bit vectors") -9780d51dc2af ("KVM: SVM: Modify intercept_exceptions to generic intercepts") -30abaa88382c ("KVM: SVM: Change intercept_dr to generic intercepts") -03bfeeb988a9 ("KVM: SVM: Change intercept_cr to generic intercepts") -c45ad7229d13 ("KVM: SVM: Introduce vmcb_(set_intercept/clr_intercept/_is_intercept)") -a90c1ed9f11d ("(pcid) KVM: nSVM: Remove unused field") -fa44b82eb831 ("KVM: x86: Move MPK feature detection to common code") -38f3e775e9c2 ("x86/Kconfig: Update config and kernel doc for MPK feature on AMD") -37486135d3a7 ("KVM: x86: Fix pkru save/restore when guest CR4.PKE=0, move it to x86.c") - -Signed-off-by: Babu Moger -Message-Id: <161290460478.11352.8933244555799318236.stgit@bmoger-ubuntu> -Signed-off-by: Eduardo Habkost -(cherry picked from commit 623972ceae091b31331ae4a1dc94fe5cbb891937) -Signed-off-by: Danilo C. L. de Paula ---- - target/i386/cpu.c | 107 +++++++++++++++++++++++++++++++++++++++++++++- - target/i386/cpu.h | 4 ++ - 2 files changed, 110 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 372cba2942..523a97c0fb 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -1029,7 +1029,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - "clzero", NULL, "xsaveerptr", NULL, - NULL, NULL, NULL, NULL, - NULL, "wbnoinvd", NULL, NULL, -- "ibpb", NULL, NULL, "amd-stibp", -+ "ibpb", NULL, "ibrs", "amd-stibp", - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - "amd-ssbd", "virt-ssbd", "amd-no-ssb", NULL, -@@ -1769,6 +1769,56 @@ static CPUCaches epyc_rome_cache_info = { - }, - }; - -+static CPUCaches epyc_milan_cache_info = { -+ .l1d_cache = &(CPUCacheInfo) { -+ .type = DATA_CACHE, -+ .level = 1, -+ .size = 32 * KiB, -+ .line_size = 64, -+ .associativity = 8, -+ .partitions = 1, -+ .sets = 64, -+ .lines_per_tag = 1, -+ .self_init = 1, -+ .no_invd_sharing = true, -+ }, -+ .l1i_cache = &(CPUCacheInfo) { -+ .type = INSTRUCTION_CACHE, -+ .level = 1, -+ .size = 32 * KiB, -+ .line_size = 64, -+ .associativity = 8, -+ .partitions = 1, -+ .sets = 64, -+ .lines_per_tag = 1, -+ .self_init = 1, -+ .no_invd_sharing = true, -+ }, -+ .l2_cache = &(CPUCacheInfo) { -+ .type = UNIFIED_CACHE, -+ .level = 2, -+ .size = 512 * KiB, -+ .line_size = 64, -+ .associativity = 8, -+ .partitions = 1, -+ .sets = 1024, -+ .lines_per_tag = 1, -+ }, -+ .l3_cache = &(CPUCacheInfo) { -+ .type = UNIFIED_CACHE, -+ .level = 3, -+ .size = 32 * MiB, -+ .line_size = 64, -+ .associativity = 16, -+ .partitions = 1, -+ .sets = 32768, -+ .lines_per_tag = 1, -+ .self_init = true, -+ .inclusive = true, -+ .complex_indexing = true, -+ }, -+}; -+ - /* The following VMX features are not supported by KVM and are left out in the - * CPU definitions: - * -@@ -4101,6 +4151,61 @@ static X86CPUDefinition builtin_x86_defs[] = { - .model_id = "AMD EPYC-Rome Processor", - .cache_info = &epyc_rome_cache_info, - }, -+ { -+ .name = "EPYC-Milan", -+ .level = 0xd, -+ .vendor = CPUID_VENDOR_AMD, -+ .family = 25, -+ .model = 1, -+ .stepping = 1, -+ .features[FEAT_1_EDX] = -+ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH | -+ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE | -+ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE | -+ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE | -+ CPUID_VME | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX | -+ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT | -+ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | -+ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 | -+ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | -+ CPUID_EXT_PCID, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB | -+ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX | -+ CPUID_EXT2_SYSCALL, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH | -+ CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | -+ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM | -+ CPUID_EXT3_TOPOEXT | CPUID_EXT3_PERFCORE, -+ .features[FEAT_8000_0008_EBX] = -+ CPUID_8000_0008_EBX_CLZERO | CPUID_8000_0008_EBX_XSAVEERPTR | -+ CPUID_8000_0008_EBX_WBNOINVD | CPUID_8000_0008_EBX_IBPB | -+ CPUID_8000_0008_EBX_IBRS | CPUID_8000_0008_EBX_STIBP | -+ CPUID_8000_0008_EBX_AMD_SSBD, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | -+ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED | -+ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT | -+ CPUID_7_0_EBX_SHA_NI | CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_ERMS | -+ CPUID_7_0_EBX_INVPCID, -+ .features[FEAT_7_0_ECX] = -+ CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_RDPID | CPUID_7_0_ECX_PKU, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_FSRM, -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | -+ CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .features[FEAT_SVM] = -+ CPUID_SVM_NPT | CPUID_SVM_NRIPSAVE | CPUID_SVM_SVME_ADDR_CHK, -+ .xlevel = 0x8000001E, -+ .model_id = "AMD EPYC-Milan Processor", -+ .cache_info = &epyc_milan_cache_info, -+ }, - }; - - /* KVM-specific features that are automatically added/removed -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 4fdb552f93..92ca64a21b 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -811,8 +811,12 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS]; - #define CPUID_8000_0008_EBX_WBNOINVD (1U << 9) - /* Indirect Branch Prediction Barrier */ - #define CPUID_8000_0008_EBX_IBPB (1U << 12) -+/* Indirect Branch Restricted Speculation */ -+#define CPUID_8000_0008_EBX_IBRS (1U << 14) - /* Single Thread Indirect Branch Predictors */ - #define CPUID_8000_0008_EBX_STIBP (1U << 15) -+/* Speculative Store Bypass Disable */ -+#define CPUID_8000_0008_EBX_AMD_SSBD (1U << 24) - - #define CPUID_XSAVE_XSAVEOPT (1U << 0) - #define CPUID_XSAVE_XSAVEC (1U << 1) --- -2.27.0 - diff --git a/kvm-i386-acpi-restore-device-paths-for-pre-5.1-vms.patch b/kvm-i386-acpi-restore-device-paths-for-pre-5.1-vms.patch deleted file mode 100644 index ef0f424..0000000 --- a/kvm-i386-acpi-restore-device-paths-for-pre-5.1-vms.patch +++ /dev/null @@ -1,177 +0,0 @@ -From 1f6e36fd98ba0610a438c2352117c5b1ed4f01ba Mon Sep 17 00:00:00 2001 -From: Igor Mammedov -Date: Mon, 8 Mar 2021 18:10:41 -0500 -Subject: [PATCH 07/15] i386/acpi: restore device paths for pre-5.1 vms -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Igor Mammedov -Message-id: <20210308181041.2427279-1-imammedo@redhat.com> -Patchwork-id: 101321 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH] i386/acpi: restore device paths for pre-5.1 vms -Bugzilla: 1934158 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Philippe Mathieu-Daudé - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1934158 -Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=35317870 -Upstream: 0a343a5add75f9f90c65e932863d57ddbcb28f5c - - From: Vitaly Cheptsov - Date: Mon Mar 1 22:59:18 2021 +0300 - - After fixing the _UID value for the primary PCI root bridge in - af1b80ae it was discovered that this change updates Windows - configuration in an incompatible way causing network configuration - failure unless DHCP is used. More details provided on the list: - - https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg08484.html - - This change reverts the _UID update from 1 to 0 for q35 and i440fx - VMs before version 5.2 to maintain the original behaviour when - upgrading. - - Cc: qemu-stable@nongnu.org - Cc: qemu-devel@nongnu.org - Reported-by: Thomas Lamprecht - Suggested-by: Michael S. Tsirkin - Signed-off-by: Vitaly Cheptsov - Message-Id: <20210301195919.9333-1-cheptsov@ispras.ru> - Tested-by: Thomas Lamprecht - Reviewed-by: Igor Mammedov - Reviewed-by: Michael S. Tsirkin - Signed-off-by: Michael S. Tsirkin - Fixes: af1b80ae56c9 ("i386/acpi: fix inconsistent QEMU/OVMF device paths") - -(cherry picked from commit 0a343a5add75f9f90c65e932863d57ddbcb28f5c) -Signed-off-by: Igor Mammedov - -Notes: -clean cherrypick + -adding the same quirk to RHEL's pc(7.6)/q35(8.3) machine types -to preserve old UID. pc-q35-rhel8.4.0 will have new UID as defined -by spec (but since it's not been released yet there is no risk of -breaking [non]existing Windows deployments and new installations -should pickup new PCI device enumeration just fine) - -Signed-off-by: Danilo C. L. de Paula ---- - hw/i386/acpi-build.c | 4 ++-- - hw/i386/pc_piix.c | 5 +++++ - hw/i386/pc_q35.c | 5 +++++ - include/hw/i386/pc.h | 1 + - 4 files changed, 13 insertions(+), 2 deletions(-) - -diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c -index b1082bd412..be6a260b85 100644 ---- a/hw/i386/acpi-build.c -+++ b/hw/i386/acpi-build.c -@@ -1516,7 +1516,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, - dev = aml_device("PCI0"); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03"))); - aml_append(dev, aml_name_decl("_ADR", aml_int(0))); -- aml_append(dev, aml_name_decl("_UID", aml_int(0))); -+ aml_append(dev, aml_name_decl("_UID", aml_int(pcmc->pci_root_uid))); - aml_append(sb_scope, dev); - aml_append(dsdt, sb_scope); - -@@ -1533,7 +1533,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); - aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); - aml_append(dev, aml_name_decl("_ADR", aml_int(0))); -- aml_append(dev, aml_name_decl("_UID", aml_int(0))); -+ aml_append(dev, aml_name_decl("_UID", aml_int(pcmc->pci_root_uid))); - aml_append(dev, build_q35_osc_method()); - aml_append(sb_scope, dev); - -diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c -index 6e1f1ba082..819fb5fed9 100644 ---- a/hw/i386/pc_piix.c -+++ b/hw/i386/pc_piix.c -@@ -421,6 +421,7 @@ static void pc_i440fx_machine_options(MachineClass *m) - { - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); - pcmc->default_nic_model = "e1000"; -+ pcmc->pci_root_uid = 0; - - m->family = "pc_piix"; - m->desc = "Standard PC (i440FX + PIIX, 1996)"; -@@ -452,6 +453,7 @@ static void pc_i440fx_5_1_machine_options(MachineClass *m) - compat_props_add(m->compat_props, hw_compat_5_1, hw_compat_5_1_len); - compat_props_add(m->compat_props, pc_compat_5_1, pc_compat_5_1_len); - pcmc->kvmclock_create_always = false; -+ pcmc->pci_root_uid = 1; - } - - DEFINE_I440FX_MACHINE(v5_1, "pc-i440fx-5.1", NULL, -@@ -1020,6 +1022,7 @@ static void pc_machine_rhel7_options(MachineClass *m) - m->family = "pc_piix_Y"; - m->default_machine_opts = "firmware=bios-256k.bin,hpet=off"; - pcmc->default_nic_model = "e1000"; -+ pcmc->pci_root_uid = 0; - m->default_display = "std"; - m->no_parallel = 1; - m->numa_mem_supported = true; -@@ -1046,6 +1049,8 @@ static void pc_machine_rhel760_options(MachineClass *m) - pcmc->pvh_enabled = false; - pcmc->default_cpu_version = CPU_VERSION_LEGACY; - pcmc->kvmclock_create_always = false; -+ /* From pc_i440fx_5_1_machine_options() */ -+ pcmc->pci_root_uid = 1; - compat_props_add(m->compat_props, hw_compat_rhel_8_3, - hw_compat_rhel_8_3_len); - compat_props_add(m->compat_props, pc_rhel_8_3_compat, -diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c -index a8c0496c9f..f848f1484e 100644 ---- a/hw/i386/pc_q35.c -+++ b/hw/i386/pc_q35.c -@@ -332,6 +332,7 @@ static void pc_q35_machine_options(MachineClass *m) - { - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); - pcmc->default_nic_model = "e1000e"; -+ pcmc->pci_root_uid = 0; - - m->family = "pc_q35"; - m->desc = "Standard PC (Q35 + ICH9, 2009)"; -@@ -367,6 +368,7 @@ static void pc_q35_5_1_machine_options(MachineClass *m) - compat_props_add(m->compat_props, hw_compat_5_1, hw_compat_5_1_len); - compat_props_add(m->compat_props, pc_compat_5_1, pc_compat_5_1_len); - pcmc->kvmclock_create_always = false; -+ pcmc->pci_root_uid = 1; - } - - DEFINE_Q35_MACHINE(v5_1, "pc-q35-5.1", NULL, -@@ -578,6 +580,7 @@ static void pc_q35_machine_rhel_options(MachineClass *m) - { - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); - pcmc->default_nic_model = "e1000e"; -+ pcmc->pci_root_uid = 0; - m->family = "pc_q35_Z"; - m->units_per_default_bus = 1; - m->default_machine_opts = "firmware=bios-256k.bin,hpet=off"; -@@ -630,6 +633,8 @@ static void pc_q35_machine_rhel830_options(MachineClass *m) - pc_rhel_8_3_compat_len); - /* From pc_q35_5_1_machine_options() */ - pcmc->kvmclock_create_always = false; -+ /* From pc_q35_5_1_machine_options() */ -+ pcmc->pci_root_uid = 1; - } - - DEFINE_PC_MACHINE(q35_rhel830, "pc-q35-rhel8.3.0", pc_q35_init_rhel830, -diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h -index 68091bea98..d2efc65cec 100644 ---- a/include/hw/i386/pc.h -+++ b/include/hw/i386/pc.h -@@ -99,6 +99,7 @@ struct PCMachineClass { - int legacy_acpi_table_size; - unsigned acpi_data_size; - bool do_not_add_smb_acpi; -+ int pci_root_uid; - - /* SMBIOS compat: */ - bool smbios_defaults; --- -2.27.0 - diff --git a/kvm-migration-dirty-bitmap-Allow-control-of-bitmap-persi.patch b/kvm-migration-dirty-bitmap-Allow-control-of-bitmap-persi.patch deleted file mode 100644 index 940231e..0000000 --- a/kvm-migration-dirty-bitmap-Allow-control-of-bitmap-persi.patch +++ /dev/null @@ -1,167 +0,0 @@ -From 039775f93548382ec1b98f5a6004c3eee02fbd28 Mon Sep 17 00:00:00 2001 -From: Peter Krempa -Date: Mon, 22 Feb 2021 13:35:05 -0500 -Subject: [PATCH 22/54] migration: dirty-bitmap: Allow control of bitmap - persistence - -RH-Author: Peter Krempa -Message-id: -Patchwork-id: 101171 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 2/3] migration: dirty-bitmap: Allow control of bitmap persistence -Bugzilla: 1930757 -RH-Acked-by: John Snow -RH-Acked-by: Kevin Wolf -RH-Acked-by: Eric Blake - -Bitmap's source persistence is transported over the migration stream and -the destination mirrors it. In some cases the destination might want to -persist bitmaps which are not persistent on the source (e.g. the result -of merging bitmaps from a number of layers on the source when migrating -into a squashed image) but currently it would need to create another set -of persistent bitmaps and merge them. - -This patch adds a 'transform' property to the alias map which allows -overriding the persistence of migrated bitmaps both on the source and -destination sides. - -Signed-off-by: Peter Krempa -Message-Id: -Reviewed-by: Eric Blake -[eblake: grammar tweaks, drop dead conditional] -Signed-off-by: Eric Blake -(cherry picked from commit 6e9f21a2aa8a78bc9a512a836a40c79fe50dd2b4) - -https://bugzilla.redhat.com/show_bug.cgi?id=1930757 -Signed-off-by: Danilo C. L. de Paula ---- - migration/block-dirty-bitmap.c | 29 ++++++++++++++++++++++++++--- - qapi/migration.json | 19 ++++++++++++++++++- - 2 files changed, 44 insertions(+), 4 deletions(-) - -diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c -index b39c13ce4e..975093610a 100644 ---- a/migration/block-dirty-bitmap.c -+++ b/migration/block-dirty-bitmap.c -@@ -150,6 +150,7 @@ typedef struct DBMLoadState { - BdrvDirtyBitmap *bitmap; - - bool before_vm_start_handled; /* set in dirty_bitmap_mig_before_vm_start */ -+ BitmapMigrationBitmapAlias *bmap_inner; - - /* - * cancelled -@@ -529,6 +530,7 @@ static int add_bitmaps_to_list(DBMSaveState *s, BlockDriverState *bs, - } - - FOR_EACH_DIRTY_BITMAP(bs, bitmap) { -+ BitmapMigrationBitmapAliasTransform *bitmap_transform = NULL; - bitmap_name = bdrv_dirty_bitmap_name(bitmap); - if (!bitmap_name) { - continue; -@@ -549,6 +551,9 @@ static int add_bitmaps_to_list(DBMSaveState *s, BlockDriverState *bs, - } - - bitmap_alias = bmap_inner->alias; -+ if (bmap_inner->has_transform) { -+ bitmap_transform = bmap_inner->transform; -+ } - } else { - if (strlen(bitmap_name) > UINT8_MAX) { - error_report("Cannot migrate bitmap '%s' on node '%s': " -@@ -574,8 +579,15 @@ static int add_bitmaps_to_list(DBMSaveState *s, BlockDriverState *bs, - if (bdrv_dirty_bitmap_enabled(bitmap)) { - dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_ENABLED; - } -- if (bdrv_dirty_bitmap_get_persistence(bitmap)) { -- dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT; -+ if (bitmap_transform && -+ bitmap_transform->has_persistent) { -+ if (bitmap_transform->persistent) { -+ dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT; -+ } -+ } else { -+ if (bdrv_dirty_bitmap_get_persistence(bitmap)) { -+ dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT; -+ } - } - - QSIMPLEQ_INSERT_TAIL(&s->dbms_list, dbms, entry); -@@ -783,6 +795,7 @@ static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s) - uint32_t granularity = qemu_get_be32(f); - uint8_t flags = qemu_get_byte(f); - LoadBitmapState *b; -+ bool persistent; - - if (s->cancelled) { - return 0; -@@ -807,7 +820,15 @@ static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s) - return -EINVAL; - } - -- if (flags & DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT) { -+ if (s->bmap_inner && -+ s->bmap_inner->has_transform && -+ s->bmap_inner->transform->has_persistent) { -+ persistent = s->bmap_inner->transform->persistent; -+ } else { -+ persistent = flags & DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT; -+ } -+ -+ if (persistent) { - bdrv_dirty_bitmap_set_persistence(s->bitmap, true); - } - -@@ -1091,6 +1112,8 @@ static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s, - } else { - bitmap_name = bmap_inner->name; - } -+ -+ s->bmap_inner = bmap_inner; - } - - if (!s->cancelled) { -diff --git a/qapi/migration.json b/qapi/migration.json -index 3c75820527..19b796ab47 100644 ---- a/qapi/migration.json -+++ b/qapi/migration.json -@@ -525,6 +525,19 @@ - 'data': [ 'none', 'zlib', - { 'name': 'zstd', 'if': 'defined(CONFIG_ZSTD)' } ] } - -+## -+# @BitmapMigrationBitmapAliasTransform: -+# -+# @persistent: If present, the bitmap will be made persistent -+# or transient depending on this parameter. -+# -+# Since: 6.0 -+## -+{ 'struct': 'BitmapMigrationBitmapAliasTransform', -+ 'data': { -+ '*persistent': 'bool' -+ } } -+ - ## - # @BitmapMigrationBitmapAlias: - # -@@ -533,12 +546,16 @@ - # @alias: An alias name for migration (for example the bitmap name on - # the opposite site). - # -+# @transform: Allows the modification of the migrated bitmap. -+# (since 6.0) -+# - # Since: 5.2 - ## - { 'struct': 'BitmapMigrationBitmapAlias', - 'data': { - 'name': 'str', -- 'alias': 'str' -+ 'alias': 'str', -+ '*transform': 'BitmapMigrationBitmapAliasTransform' - } } - - ## --- -2.27.0 - diff --git a/kvm-migration-dirty-bitmap-Use-struct-for-alias-map-inne.patch b/kvm-migration-dirty-bitmap-Use-struct-for-alias-map-inne.patch deleted file mode 100644 index 156117f..0000000 --- a/kvm-migration-dirty-bitmap-Use-struct-for-alias-map-inne.patch +++ /dev/null @@ -1,143 +0,0 @@ -From e49b317a80df94b769c01c2ae488a369921088d2 Mon Sep 17 00:00:00 2001 -From: Peter Krempa -Date: Mon, 22 Feb 2021 13:35:04 -0500 -Subject: [PATCH 21/54] migration: dirty-bitmap: Use struct for alias map inner - members - -RH-Author: Peter Krempa -Message-id: <943503323f3f97d576715d09736376cf07d6efab.1614000630.git.pkrempa@redhat.com> -Patchwork-id: 101170 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/3] migration: dirty-bitmap: Use struct for alias map inner members -Bugzilla: 1930757 -RH-Acked-by: John Snow -RH-Acked-by: Kevin Wolf -RH-Acked-by: Eric Blake - -Currently the alias mapping hash stores just strings of the target -objects internally. In further patches we'll be adding another member -which will need to be stored in the map so pass a copy of the whole -BitmapMigrationBitmapAlias QAPI struct into the map. - -Signed-off-by: Peter Krempa -Message-Id: -Reviewed-by: Eric Blake -[eblake: adjust long lines] -Signed-off-by: Eric Blake -(cherry picked from commit 0d1e450c7b3117ee635a00c81d9a92666ebc7ffa) - -https://bugzilla.redhat.com/show_bug.cgi?id=1930757 -Signed-off-by: Danilo C. L. de Paula ---- - migration/block-dirty-bitmap.c | 33 +++++++++++++++++++++------------ - 1 file changed, 21 insertions(+), 12 deletions(-) - -diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c -index c61d382be8..b39c13ce4e 100644 ---- a/migration/block-dirty-bitmap.c -+++ b/migration/block-dirty-bitmap.c -@@ -75,6 +75,8 @@ - #include "qemu/id.h" - #include "qapi/error.h" - #include "qapi/qapi-commands-migration.h" -+#include "qapi/qapi-visit-migration.h" -+#include "qapi/clone-visitor.h" - #include "trace.h" - - #define CHUNK_SIZE (1 << 10) -@@ -224,6 +226,7 @@ static GHashTable *construct_alias_map(const BitmapMigrationNodeAliasList *bbm, - AliasMapInnerNode *amin; - GHashTable *bitmaps_map; - const char *node_map_from, *node_map_to; -+ GDestroyNotify gdn; - - if (!id_wellformed(bmna->alias)) { - error_setg(errp, "The node alias '%s' is not well-formed", -@@ -263,8 +266,9 @@ static GHashTable *construct_alias_map(const BitmapMigrationNodeAliasList *bbm, - node_map_to = bmna->node_name; - } - -- bitmaps_map = g_hash_table_new_full(g_str_hash, g_str_equal, -- g_free, g_free); -+ gdn = (GDestroyNotify) qapi_free_BitmapMigrationBitmapAlias; -+ bitmaps_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, -+ gdn); - - amin = g_new(AliasMapInnerNode, 1); - *amin = (AliasMapInnerNode){ -@@ -276,7 +280,7 @@ static GHashTable *construct_alias_map(const BitmapMigrationNodeAliasList *bbm, - - for (bmbal = bmna->bitmaps; bmbal; bmbal = bmbal->next) { - const BitmapMigrationBitmapAlias *bmba = bmbal->value; -- const char *bmap_map_from, *bmap_map_to; -+ const char *bmap_map_from; - - if (strlen(bmba->alias) > UINT8_MAX) { - error_setg(errp, -@@ -293,7 +297,6 @@ static GHashTable *construct_alias_map(const BitmapMigrationNodeAliasList *bbm, - - if (name_to_alias) { - bmap_map_from = bmba->name; -- bmap_map_to = bmba->alias; - - if (g_hash_table_contains(bitmaps_map, bmba->name)) { - error_setg(errp, "The bitmap '%s'/'%s' is mapped twice", -@@ -302,7 +305,6 @@ static GHashTable *construct_alias_map(const BitmapMigrationNodeAliasList *bbm, - } - } else { - bmap_map_from = bmba->alias; -- bmap_map_to = bmba->name; - - if (g_hash_table_contains(bitmaps_map, bmba->alias)) { - error_setg(errp, "The bitmap alias '%s'/'%s' is used twice", -@@ -311,8 +313,8 @@ static GHashTable *construct_alias_map(const BitmapMigrationNodeAliasList *bbm, - } - } - -- g_hash_table_insert(bitmaps_map, -- g_strdup(bmap_map_from), g_strdup(bmap_map_to)); -+ g_hash_table_insert(bitmaps_map, g_strdup(bmap_map_from), -+ QAPI_CLONE(BitmapMigrationBitmapAlias, bmba)); - } - } - -@@ -538,11 +540,15 @@ static int add_bitmaps_to_list(DBMSaveState *s, BlockDriverState *bs, - } - - if (bitmap_aliases) { -- bitmap_alias = g_hash_table_lookup(bitmap_aliases, bitmap_name); -- if (!bitmap_alias) { -+ BitmapMigrationBitmapAlias *bmap_inner; -+ -+ bmap_inner = g_hash_table_lookup(bitmap_aliases, bitmap_name); -+ if (!bmap_inner) { - /* Skip bitmaps with no alias */ - continue; - } -+ -+ bitmap_alias = bmap_inner->alias; - } else { - if (strlen(bitmap_name) > UINT8_MAX) { - error_report("Cannot migrate bitmap '%s' on node '%s': " -@@ -1074,13 +1080,16 @@ static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s, - - bitmap_name = s->bitmap_alias; - if (!s->cancelled && bitmap_alias_map) { -- bitmap_name = g_hash_table_lookup(bitmap_alias_map, -- s->bitmap_alias); -- if (!bitmap_name) { -+ BitmapMigrationBitmapAlias *bmap_inner; -+ -+ bmap_inner = g_hash_table_lookup(bitmap_alias_map, s->bitmap_alias); -+ if (!bmap_inner) { - error_report("Error: Unknown bitmap alias '%s' on node " - "'%s' (alias '%s')", s->bitmap_alias, - s->bs->node_name, s->node_alias); - cancel_incoming_locked(s); -+ } else { -+ bitmap_name = bmap_inner->name; - } - } - --- -2.27.0 - diff --git a/kvm-nbd-make-nbd_read-return-EIO-on-error.patch b/kvm-nbd-make-nbd_read-return-EIO-on-error.patch deleted file mode 100644 index 9dacfa9..0000000 --- a/kvm-nbd-make-nbd_read-return-EIO-on-error.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 7b7974468656d2ceba6a7f6dba2b35dfe28a5d1f Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Mon, 8 Feb 2021 22:57:01 -0300 -Subject: [PATCH 03/54] nbd: make nbd_read* return -EIO on error - -RH-Author: Eric Blake -Message-id: <20210208225701.110110-4-eblake@redhat.com> -Patchwork-id: 101007 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v4 3/3] nbd: make nbd_read* return -EIO on error -Bugzilla: 1887883 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Sergio Lopez Pascual -RH-Acked-by: Max Reitz - -From: Roman Kagan - -NBD reconnect logic considers the error code from the functions that -read NBD messages to tell if reconnect should be attempted or not: it is -attempted on -EIO, otherwise the client transitions to NBD_CLIENT_QUIT -state (see nbd_channel_error). This error code is propagated from the -primitives like nbd_read. - -The problem, however, is that nbd_read itself turns every error into -1 -rather than -EIO. As a result, if the NBD server happens to die while -sending the message, the client in QEMU receives less data than it -expects, considers it as a fatal error, and wouldn't attempt -reestablishing the connection. - -Fix it by turning every negative return from qio_channel_read_all into --EIO returned from nbd_read. Apparently that was the original behavior, -but got broken later. Also adjust nbd_readXX to follow. - -Fixes: e6798f06a6 ("nbd: generalize usage of nbd_read") -Signed-off-by: Roman Kagan -Reviewed-by: Vladimir Sementsov-Ogievskiy -Message-Id: <20210129073859.683063-4-rvkagan@yandex-team.ru> -Signed-off-by: Eric Blake -(cherry picked from commit 5082fc82a6bc3fc06a04be47d39777c7cff61e5b) -Signed-off-by: Eric Blake -Signed-off-by: Eduardo Lima (Etrunko) ---- - include/block/nbd.h | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/include/block/nbd.h b/include/block/nbd.h -index 4a52a43ef5..5f34d23bb0 100644 ---- a/include/block/nbd.h -+++ b/include/block/nbd.h -@@ -364,7 +364,7 @@ static inline int nbd_read(QIOChannel *ioc, void *buffer, size_t size, - if (desc) { - error_prepend(errp, "Failed to read %s: ", desc); - } -- return -1; -+ return ret; - } - - return 0; -@@ -375,8 +375,9 @@ static inline int nbd_read##bits(QIOChannel *ioc, \ - uint##bits##_t *val, \ - const char *desc, Error **errp) \ - { \ -- if (nbd_read(ioc, val, sizeof(*val), desc, errp) < 0) { \ -- return -1; \ -+ int ret = nbd_read(ioc, val, sizeof(*val), desc, errp); \ -+ if (ret < 0) { \ -+ return ret; \ - } \ - *val = be##bits##_to_cpu(*val); \ - return 0; \ --- -2.27.0 - diff --git a/kvm-nbd-server-Quiesce-coroutines-on-context-switch.patch b/kvm-nbd-server-Quiesce-coroutines-on-context-switch.patch deleted file mode 100644 index d0080d2..0000000 --- a/kvm-nbd-server-Quiesce-coroutines-on-context-switch.patch +++ /dev/null @@ -1,249 +0,0 @@ -From 7cadf68c46abcd097fcbcecb11a4a04f264d0316 Mon Sep 17 00:00:00 2001 -From: Sergio Lopez Pascual -Date: Thu, 11 Feb 2021 14:42:05 -0300 -Subject: [PATCH 3/6] nbd/server: Quiesce coroutines on context switch - -RH-Author: Sergio Lopez Pascual -Message-id: <20210211144208.58930-3-slp@redhat.com> -Patchwork-id: 101051 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 2/5] nbd/server: Quiesce coroutines on context switch -Bugzilla: 1918966 1918968 -RH-Acked-by: Max Reitz -RH-Acked-by: Kevin Wolf -RH-Acked-by: Eric Blake - -When switching between AIO contexts we need to me make sure that both -recv_coroutine and send_coroutine are not scheduled to run. Otherwise, -QEMU may crash while attaching the new context with an error like -this one: - -aio_co_schedule: Co-routine was already scheduled in 'aio_co_schedule' - -To achieve this we need a local implementation of -'qio_channel_readv_all_eof' named 'nbd_read_eof' (a trick already done -by 'nbd/client.c') that allows us to interrupt the operation and to -know when recv_coroutine is yielding. - -With this in place, we delegate detaching the AIO context to the -owning context with a BH ('nbd_aio_detach_bh') scheduled using -'aio_wait_bh_oneshot'. This BH signals that we need to quiesce the -channel by setting 'client->quiescing' to 'true', and either waits for -the coroutine to finish using AIO_WAIT_WHILE or, if it's yielding in -'nbd_read_eof', actively enters the coroutine to interrupt it. - -RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1900326 -Signed-off-by: Sergio Lopez -Reviewed-by: Eric Blake -Message-Id: <20201214170519.223781-4-slp@redhat.com> -Signed-off-by: Eric Blake -(cherry picked from commit f148ae7d36cbb924447f4b528a94d7799836c749) -Signed-off-by: Sergio Lopez -Signed-off-by: Eduardo Lima (Etrunko) ---- - nbd/server.c | 120 +++++++++++++++++++++++++++++++++++++++++++++------ - 1 file changed, 106 insertions(+), 14 deletions(-) - -diff --git a/nbd/server.c b/nbd/server.c -index 613ed2634a..7229f487d2 100644 ---- a/nbd/server.c -+++ b/nbd/server.c -@@ -132,6 +132,9 @@ struct NBDClient { - CoMutex send_lock; - Coroutine *send_coroutine; - -+ bool read_yielding; -+ bool quiescing; -+ - QTAILQ_ENTRY(NBDClient) next; - int nb_requests; - bool closing; -@@ -1352,14 +1355,60 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) - return 0; - } - --static int nbd_receive_request(QIOChannel *ioc, NBDRequest *request, -+/* nbd_read_eof -+ * Tries to read @size bytes from @ioc. This is a local implementation of -+ * qio_channel_readv_all_eof. We have it here because we need it to be -+ * interruptible and to know when the coroutine is yielding. -+ * Returns 1 on success -+ * 0 on eof, when no data was read (errp is not set) -+ * negative errno on failure (errp is set) -+ */ -+static inline int coroutine_fn -+nbd_read_eof(NBDClient *client, void *buffer, size_t size, Error **errp) -+{ -+ bool partial = false; -+ -+ assert(size); -+ while (size > 0) { -+ struct iovec iov = { .iov_base = buffer, .iov_len = size }; -+ ssize_t len; -+ -+ len = qio_channel_readv(client->ioc, &iov, 1, errp); -+ if (len == QIO_CHANNEL_ERR_BLOCK) { -+ client->read_yielding = true; -+ qio_channel_yield(client->ioc, G_IO_IN); -+ client->read_yielding = false; -+ if (client->quiescing) { -+ return -EAGAIN; -+ } -+ continue; -+ } else if (len < 0) { -+ return -EIO; -+ } else if (len == 0) { -+ if (partial) { -+ error_setg(errp, -+ "Unexpected end-of-file before all bytes were read"); -+ return -EIO; -+ } else { -+ return 0; -+ } -+ } -+ -+ partial = true; -+ size -= len; -+ buffer = (uint8_t *) buffer + len; -+ } -+ return 1; -+} -+ -+static int nbd_receive_request(NBDClient *client, NBDRequest *request, - Error **errp) - { - uint8_t buf[NBD_REQUEST_SIZE]; - uint32_t magic; - int ret; - -- ret = nbd_read(ioc, buf, sizeof(buf), "request", errp); -+ ret = nbd_read_eof(client, buf, sizeof(buf), errp); - if (ret < 0) { - return ret; - } -@@ -1480,11 +1529,37 @@ static void blk_aio_attached(AioContext *ctx, void *opaque) - - QTAILQ_FOREACH(client, &exp->clients, next) { - qio_channel_attach_aio_context(client->ioc, ctx); -+ -+ assert(client->recv_coroutine == NULL); -+ assert(client->send_coroutine == NULL); -+ -+ if (client->quiescing) { -+ client->quiescing = false; -+ nbd_client_receive_next_request(client); -+ } -+ } -+} -+ -+static void nbd_aio_detach_bh(void *opaque) -+{ -+ NBDExport *exp = opaque; -+ NBDClient *client; -+ -+ QTAILQ_FOREACH(client, &exp->clients, next) { -+ qio_channel_detach_aio_context(client->ioc); -+ client->quiescing = true; -+ - if (client->recv_coroutine) { -- aio_co_schedule(ctx, client->recv_coroutine); -+ if (client->read_yielding) { -+ qemu_aio_coroutine_enter(exp->common.ctx, -+ client->recv_coroutine); -+ } else { -+ AIO_WAIT_WHILE(exp->common.ctx, client->recv_coroutine != NULL); -+ } - } -+ - if (client->send_coroutine) { -- aio_co_schedule(ctx, client->send_coroutine); -+ AIO_WAIT_WHILE(exp->common.ctx, client->send_coroutine != NULL); - } - } - } -@@ -1492,13 +1567,10 @@ static void blk_aio_attached(AioContext *ctx, void *opaque) - static void blk_aio_detach(void *opaque) - { - NBDExport *exp = opaque; -- NBDClient *client; - - trace_nbd_blk_aio_detach(exp->name, exp->common.ctx); - -- QTAILQ_FOREACH(client, &exp->clients, next) { -- qio_channel_detach_aio_context(client->ioc); -- } -+ aio_wait_bh_oneshot(exp->common.ctx, nbd_aio_detach_bh, exp); - - exp->common.ctx = NULL; - } -@@ -2151,20 +2223,23 @@ static int nbd_co_send_bitmap(NBDClient *client, uint64_t handle, - - /* nbd_co_receive_request - * Collect a client request. Return 0 if request looks valid, -EIO to drop -- * connection right away, and any other negative value to report an error to -- * the client (although the caller may still need to disconnect after reporting -- * the error). -+ * connection right away, -EAGAIN to indicate we were interrupted and the -+ * channel should be quiesced, and any other negative value to report an error -+ * to the client (although the caller may still need to disconnect after -+ * reporting the error). - */ - static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request, - Error **errp) - { - NBDClient *client = req->client; - int valid_flags; -+ int ret; - - g_assert(qemu_in_coroutine()); - assert(client->recv_coroutine == qemu_coroutine_self()); -- if (nbd_receive_request(client->ioc, request, errp) < 0) { -- return -EIO; -+ ret = nbd_receive_request(client, request, errp); -+ if (ret < 0) { -+ return ret; - } - - trace_nbd_co_receive_request_decode_type(request->handle, request->type, -@@ -2507,6 +2582,17 @@ static coroutine_fn void nbd_trip(void *opaque) - return; - } - -+ if (client->quiescing) { -+ /* -+ * We're switching between AIO contexts. Don't attempt to receive a new -+ * request and kick the main context which may be waiting for us. -+ */ -+ nbd_client_put(client); -+ client->recv_coroutine = NULL; -+ aio_wait_kick(); -+ return; -+ } -+ - req = nbd_request_get(client); - ret = nbd_co_receive_request(req, &request, &local_err); - client->recv_coroutine = NULL; -@@ -2519,6 +2605,11 @@ static coroutine_fn void nbd_trip(void *opaque) - goto done; - } - -+ if (ret == -EAGAIN) { -+ assert(client->quiescing); -+ goto done; -+ } -+ - nbd_client_receive_next_request(client); - if (ret == -EIO) { - goto disconnect; -@@ -2565,7 +2656,8 @@ disconnect: - - static void nbd_client_receive_next_request(NBDClient *client) - { -- if (!client->recv_coroutine && client->nb_requests < MAX_NBD_REQUESTS) { -+ if (!client->recv_coroutine && client->nb_requests < MAX_NBD_REQUESTS && -+ !client->quiescing) { - nbd_client_get(client); - client->recv_coroutine = qemu_coroutine_create(nbd_trip, client); - aio_co_schedule(client->exp->common.ctx, client->recv_coroutine); --- -2.27.0 - diff --git a/kvm-pci-add-romsize-property.patch b/kvm-pci-add-romsize-property.patch deleted file mode 100644 index 961073f..0000000 --- a/kvm-pci-add-romsize-property.patch +++ /dev/null @@ -1,137 +0,0 @@ -From aee681700e512679981e39928d8709eb226a4a6d Mon Sep 17 00:00:00 2001 -From: Peter Xu -Date: Wed, 10 Feb 2021 17:04:45 -0300 -Subject: [PATCH 10/54] pci: add romsize property - -RH-Author: Peter Xu -Message-id: <20210210170445.128304-3-peterx@redhat.com> -Patchwork-id: 101041 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 2/2] pci: add romsize property -Bugzilla: 1917830 -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Paolo Bonzini - -From: Paolo Bonzini - -This property can be useful for distros to set up known-good ROM sizes for -migration purposes. The VM will fail to start if the ROM is too large, -and migration compatibility will not be broken if the ROM is too small. - -Note that even though romsize is a uint32_t, it has to be between 1 -(because empty ROM files are not accepted, and romsize must be greater -than the file) and 2^31 (because values above are not powers of two and -are rejected). - -Signed-off-by: Paolo Bonzini -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: Peter Xu -Message-Id: <20201218182736.1634344-1-pbonzini@redhat.com> -Signed-off-by: Paolo Bonzini -Message-Id: <20210203131828.156467-3-pbonzini@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Reviewed-by: David Edmondson -Acked-by: Laszlo Ersek -(cherry picked from commit 08b1df8ff463e72b0875538fb991d5393047606c) -Signed-off-by: Peter Xu -Signed-off-by: Eduardo Lima (Etrunko) ---- - hw/pci/pci.c | 19 +++++++++++++++++-- - hw/xen/xen_pt_load_rom.c | 14 ++++++++++++-- - include/hw/pci/pci.h | 1 + - 3 files changed, 30 insertions(+), 4 deletions(-) - -diff --git a/hw/pci/pci.c b/hw/pci/pci.c -index e4caad33c5..9619b8d068 100644 ---- a/hw/pci/pci.c -+++ b/hw/pci/pci.c -@@ -67,6 +67,7 @@ static void pcibus_reset(BusState *qbus); - static Property pci_props[] = { - DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), - DEFINE_PROP_STRING("romfile", PCIDevice, romfile), -+ DEFINE_PROP_UINT32("romsize", PCIDevice, romsize, -1), - DEFINE_PROP_UINT32("rombar", PCIDevice, rom_bar, 1), - DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present, - QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false), -@@ -2106,6 +2107,11 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) - bool is_default_rom; - uint16_t class_id; - -+ if (pci_dev->romsize != -1 && !is_power_of_2(pci_dev->romsize)) { -+ error_setg(errp, "ROM size %u is not a power of two", pci_dev->romsize); -+ return; -+ } -+ - /* initialize cap_present for pci_is_express() and pci_config_size(), - * Note that hybrid PCIs are not set automatically and need to manage - * QEMU_PCI_CAP_EXPRESS manually */ -@@ -2371,7 +2377,16 @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom, - g_free(path); - return; - } -- size = pow2ceil(size); -+ if (pdev->romsize != -1) { -+ if (size > pdev->romsize) { -+ error_setg(errp, "romfile \"%s\" (%u bytes) is too large for ROM size %u", -+ pdev->romfile, (uint32_t)size, pdev->romsize); -+ g_free(path); -+ return; -+ } -+ } else { -+ pdev->romsize = pow2ceil(size); -+ } - - vmsd = qdev_get_vmsd(DEVICE(pdev)); - -@@ -2381,7 +2396,7 @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom, - snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev))); - } - pdev->has_rom = true; -- memory_region_init_rom(&pdev->rom, OBJECT(pdev), name, size, &error_fatal); -+ memory_region_init_rom(&pdev->rom, OBJECT(pdev), name, pdev->romsize, &error_fatal); - ptr = memory_region_get_ram_ptr(&pdev->rom); - if (load_image_size(path, ptr, size) < 0) { - error_setg(errp, "failed to load romfile \"%s\"", pdev->romfile); -diff --git a/hw/xen/xen_pt_load_rom.c b/hw/xen/xen_pt_load_rom.c -index a50a80837e..03422a8a71 100644 ---- a/hw/xen/xen_pt_load_rom.c -+++ b/hw/xen/xen_pt_load_rom.c -@@ -53,10 +53,20 @@ void *pci_assign_dev_load_option_rom(PCIDevice *dev, - } - fseek(fp, 0, SEEK_SET); - -+ if (dev->romsize != -1) { -+ if (st.st_size > dev->romsize) { -+ error_report("ROM BAR \"%s\" (%ld bytes) is too large for ROM size %u", -+ rom_file, (long) st.st_size, dev->romsize); -+ goto close_rom; -+ } -+ } else { -+ dev->romsize = st.st_size; -+ } -+ - snprintf(name, sizeof(name), "%s.rom", object_get_typename(owner)); -- memory_region_init_ram(&dev->rom, owner, name, st.st_size, &error_abort); -+ memory_region_init_ram(&dev->rom, owner, name, dev->romsize, &error_abort); - ptr = memory_region_get_ram_ptr(&dev->rom); -- memset(ptr, 0xff, st.st_size); -+ memset(ptr, 0xff, dev->romsize); - - if (!fread(ptr, 1, st.st_size, fp)) { - error_report("pci-assign: Cannot read from host %s", rom_file); -diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h -index 72ce649eee..75a6b15757 100644 ---- a/include/hw/pci/pci.h -+++ b/include/hw/pci/pci.h -@@ -343,6 +343,7 @@ struct PCIDevice { - - /* Location of option rom */ - char *romfile; -+ uint32_t romsize; - bool has_rom; - MemoryRegion rom; - uint32_t rom_bar; --- -2.27.0 - diff --git a/kvm-pci-reject-too-large-ROMs.patch b/kvm-pci-reject-too-large-ROMs.patch deleted file mode 100644 index 739b908..0000000 --- a/kvm-pci-reject-too-large-ROMs.patch +++ /dev/null @@ -1,89 +0,0 @@ -From a6e34aa76d86319d15355fd55fa6d12eb49a816f Mon Sep 17 00:00:00 2001 -From: Peter Xu -Date: Wed, 10 Feb 2021 17:04:44 -0300 -Subject: [PATCH 09/54] pci: reject too large ROMs -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Peter Xu -Message-id: <20210210170445.128304-2-peterx@redhat.com> -Patchwork-id: 101039 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/2] pci: reject too large ROMs -Bugzilla: 1917830 -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Paolo Bonzini - -From: Paolo Bonzini - -get_image_size() returns an int64_t, which pci_add_option_rom() assigns -to an "int" without any range checking. A 32-bit BAR could be up to -2 GiB in size, so reject anything above it. In order to accomodate -a rounded-up size of 2 GiB, change pci_patch_ids's size argument -to unsigned. - -Conflicts: - hw/pci/pci.c: missing 2c65db5e58d ("vl: extract softmmu/datadir.c") so - there's no "#include " yet - -Reviewed-by: Peter Xu -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: Laszlo Ersek -Signed-off-by: Paolo Bonzini -Message-Id: <20210203131828.156467-2-pbonzini@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Reviewed-by: David Edmondson -(cherry picked from commit 7c16b5bbb6c0f797945327d17e4be60f25a4427d) -Signed-off-by: Peter Xu -Signed-off-by: Eduardo Lima (Etrunko) ---- - hw/pci/pci.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/hw/pci/pci.c b/hw/pci/pci.c -index 0131d9d02c..e4caad33c5 100644 ---- a/hw/pci/pci.c -+++ b/hw/pci/pci.c -@@ -24,6 +24,7 @@ - - #include "qemu/osdep.h" - #include "qemu-common.h" -+#include "qemu/units.h" - #include "hw/irq.h" - #include "hw/pci/pci.h" - #include "hw/pci/pci_bridge.h" -@@ -2256,7 +2257,7 @@ static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_t offset) - - /* Patch the PCI vendor and device ids in a PCI rom image if necessary. - This is needed for an option rom which is used for more than one device. */ --static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size) -+static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, uint32_t size) - { - uint16_t vendor_id; - uint16_t device_id; -@@ -2314,7 +2315,7 @@ static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size) - static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom, - Error **errp) - { -- int size; -+ int64_t size; - char *path; - void *ptr; - char name[32]; -@@ -2364,6 +2365,11 @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom, - error_setg(errp, "romfile \"%s\" is empty", pdev->romfile); - g_free(path); - return; -+ } else if (size > 2 * GiB) { -+ error_setg(errp, "romfile \"%s\" too large (size cannot exceed 2 GiB)", -+ pdev->romfile); -+ g_free(path); -+ return; - } - size = pow2ceil(size); - --- -2.27.0 - diff --git a/kvm-pcie-don-t-set-link-state-active-if-the-slot-is-empt.patch b/kvm-pcie-don-t-set-link-state-active-if-the-slot-is-empt.patch deleted file mode 100644 index 6ffcc2c..0000000 --- a/kvm-pcie-don-t-set-link-state-active-if-the-slot-is-empt.patch +++ /dev/null @@ -1,146 +0,0 @@ -From 20eb8dc4f6679e3325e1f1f434b17e2dc6a60eee Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 21:42:47 -0500 -Subject: [PATCH 20/54] pcie: don't set link state active if the slot is empty - -RH-Author: Laurent Vivier -Message-id: <20210225214247.1336554-1-lvivier@redhat.com> -Patchwork-id: 101211 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH] pcie: don't set link state active if the slot is empty -Bugzilla: 1917654 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Alex Williamson - -BZ: https://bugzilla.redhat.com/1917654 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged -BREW: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=35163495 - -When the pcie slot is initialized, by default PCI_EXP_LNKSTA_DLLLA -(Data Link Layer Link Active) is set in PCI_EXP_LNKSTA -(Link Status) without checking if the slot is empty or not. - -This is confusing for the kernel because as it sees the link is up -it tries to read the vendor ID and fails: - -(From https://bugzilla.kernel.org/show_bug.cgi?id=211691) - -[ 1.661105] pcieport 0000:00:02.2: pciehp: Slot Capabilities : 0x0002007b -[ 1.661115] pcieport 0000:00:02.2: pciehp: Slot Status : 0x0010 -[ 1.661123] pcieport 0000:00:02.2: pciehp: Slot Control : 0x07c0 -[ 1.661138] pcieport 0000:00:02.2: pciehp: Slot #0 AttnBtn+ PwrCtrl+ MRL- AttnInd+ PwrInd+ HotPlug+ Surprise+ Interlock+ NoCompl- IbPresDis- LLActRep+ -[ 1.662581] pcieport 0000:00:02.2: pciehp: pciehp_get_power_status: SLOTCTRL 6c value read 7c0 -[ 1.662597] pcieport 0000:00:02.2: pciehp: pciehp_check_link_active: lnk_status = 2204 -[ 1.662703] pcieport 0000:00:02.2: pciehp: pending interrupts 0x0010 from Slot Status -[ 1.662706] pcieport 0000:00:02.2: pciehp: pcie_enable_notification: SLOTCTRL 6c write cmd 1031 -[ 1.662730] pcieport 0000:00:02.2: pciehp: pciehp_check_link_active: lnk_status = 2204 -[ 1.662748] pcieport 0000:00:02.2: pciehp: pciehp_check_link_active: lnk_status = 2204 -[ 1.662750] pcieport 0000:00:02.2: pciehp: Slot(0-2): Link Up -[ 2.896132] pcieport 0000:00:02.2: pciehp: pciehp_check_link_status: lnk_status = 2204 -[ 2.896135] pcieport 0000:00:02.2: pciehp: Slot(0-2): No device found -[ 2.896900] pcieport 0000:00:02.2: pciehp: pending interrupts 0x0010 from Slot Status -[ 2.896903] pcieport 0000:00:02.2: pciehp: pciehp_power_off_slot: SLOTCTRL 6c write cmd 400 -[ 3.656901] pcieport 0000:00:02.2: pciehp: pending interrupts 0x0009 from Slot Status - -This is really a problem with virtio-net failover that hotplugs a VFIO -card during the boot process. The kernel can shutdown the slot while -QEMU is hotplugging it, and this likely ends by an automatic unplug of -the card. At the end of the boot sequence the card has disappeared. - -To fix that, don't set the "Link Active" state in the init function, but -rely on the plug function to do it, as the mechanism has already been -introduced by 2f2b18f60bf1. - -Fixes: 2f2b18f60bf1 ("pcie: set link state inactive/active after hot unplug/plug") -Cc: zhengxiang9@huawei.com -Fixes: 3d67447fe7c2 ("pcie: Fill PCIESlot link fields to support higher speeds and widths") -Cc: alex.williamson@redhat.com -Fixes: b2101eae63ea ("pcie: Set the "link active" in the link status register") -Cc: benh@kernel.crashing.org -Signed-off-by: Laurent Vivier -Message-Id: <20210212135250.2738750-5-lvivier@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit df72184ec15829053b3bb5a0d5801773b6d9ec25) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/pci/pcie.c | 19 +++++++++---------- - 1 file changed, 9 insertions(+), 10 deletions(-) - -diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c -index d4010cf8f3..a733e2fb87 100644 ---- a/hw/pci/pcie.c -+++ b/hw/pci/pcie.c -@@ -75,11 +75,6 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version) - QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1) | - QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT)); - -- if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) { -- pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, -- PCI_EXP_LNKSTA_DLLLA); -- } -- - /* We changed link status bits over time, and changing them across - * migrations is generally fine as hardware changes them too. - * Let's not bother checking. -@@ -125,8 +120,7 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev) - */ - pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP, - PCI_EXP_LNKCAP_DLLLARC); -- pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, -- PCI_EXP_LNKSTA_DLLLA); -+ /* the PCI_EXP_LNKSTA_DLLLA will be set in the hotplug function */ - - /* - * Target Link Speed defaults to the highest link speed supported by -@@ -427,6 +421,7 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, - PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev); - uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap; - PCIDevice *pci_dev = PCI_DEVICE(dev); -+ uint32_t lnkcap = pci_get_long(exp_cap + PCI_EXP_LNKCAP); - - /* Don't send event when device is enabled during qemu machine creation: - * it is present on boot, no hotplug event is necessary. We do send an -@@ -434,7 +429,8 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, - if (!dev->hotplugged) { - pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, - PCI_EXP_SLTSTA_PDS); -- if (pci_dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) { -+ if (pci_dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA || -+ (lnkcap & PCI_EXP_LNKCAP_DLLLARC)) { - pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, - PCI_EXP_LNKSTA_DLLLA); - } -@@ -448,7 +444,8 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, - if (pci_get_function_0(pci_dev)) { - pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, - PCI_EXP_SLTSTA_PDS); -- if (pci_dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) { -+ if (pci_dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA || -+ (lnkcap & PCI_EXP_LNKCAP_DLLLARC)) { - pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, - PCI_EXP_LNKSTA_DLLLA); - } -@@ -640,6 +637,7 @@ void pcie_cap_slot_write_config(PCIDevice *dev, - uint32_t pos = dev->exp.exp_cap; - uint8_t *exp_cap = dev->config + pos; - uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); -+ uint32_t lnkcap = pci_get_long(exp_cap + PCI_EXP_LNKCAP); - - if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) { - /* -@@ -695,7 +693,8 @@ void pcie_cap_slot_write_config(PCIDevice *dev, - - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, - PCI_EXP_SLTSTA_PDS); -- if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) { -+ if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA || -+ (lnkcap & PCI_EXP_LNKCAP_DLLLARC)) { - pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA, - PCI_EXP_LNKSTA_DLLLA); - } --- -2.27.0 - diff --git a/kvm-q35-Increase-max_cpus-to-710-on-pc-q35-rhel8-machine.patch b/kvm-q35-Increase-max_cpus-to-710-on-pc-q35-rhel8-machine.patch deleted file mode 100644 index ac1341e..0000000 --- a/kvm-q35-Increase-max_cpus-to-710-on-pc-q35-rhel8-machine.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 8fa6654712c7cba73fd1c8d93b094d90c1757000 Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Tue, 26 Jan 2021 23:46:44 -0500 -Subject: [PATCH 4/5] q35: Increase max_cpus to 710 on pc-q35-rhel8* machine - types - -RH-Author: Eduardo Habkost -Message-id: <20210126234644.3091529-1-ehabkost@redhat.com> -Patchwork-id: 100791 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH] q35: Increase max_cpus to 710 on pc-q35-rhel8* machine types -Bugzilla: 1904268 -RH-Acked-by: Daniel P. Berrange -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1904268 -Upstream: not applicable -Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=34536802 - -The original goal was to support 1024 VCPUs, but 710 VCPUs is the -maximum number we can reach before hitting SMBIOS table size -limits. - -Signed-off-by: Eduardo Habkost -Signed-off-by: Eduardo Lima (Etrunko) ---- - hw/i386/pc_q35.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c -index 5acb47afcf..72854192a9 100644 ---- a/hw/i386/pc_q35.c -+++ b/hw/i386/pc_q35.c -@@ -589,7 +589,7 @@ static void pc_q35_machine_rhel_options(MachineClass *m) - machine_class_allow_dynamic_sysbus_dev(m, TYPE_INTEL_IOMMU_DEVICE); - machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE); - m->alias = "q35"; -- m->max_cpus = 512; -+ m->max_cpus = 710; - compat_props_add(m->compat_props, pc_rhel_compat, pc_rhel_compat_len); - } - --- -2.18.4 - diff --git a/kvm-qemu-iotests-300-Add-test-case-for-modifying-persist.patch b/kvm-qemu-iotests-300-Add-test-case-for-modifying-persist.patch deleted file mode 100644 index 0cf96d6..0000000 --- a/kvm-qemu-iotests-300-Add-test-case-for-modifying-persist.patch +++ /dev/null @@ -1,154 +0,0 @@ -From b76dbfedc47366039a08f68de82792b9c70a6be9 Mon Sep 17 00:00:00 2001 -From: Peter Krempa -Date: Mon, 22 Feb 2021 13:35:06 -0500 -Subject: [PATCH 23/54] qemu-iotests: 300: Add test case for modifying - persistence of bitmap - -RH-Author: Peter Krempa -Message-id: -Patchwork-id: 101172 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 3/3] qemu-iotests: 300: Add test case for modifying persistence of bitmap -Bugzilla: 1930757 -RH-Acked-by: John Snow -RH-Acked-by: Kevin Wolf -RH-Acked-by: Eric Blake - -Verify that the modification of the bitmap persistence over migration -which is controlled via BitmapMigrationBitmapAliasTransform works -properly. - -Based on TestCrossAliasMigration - -Signed-off-by: Peter Krempa -Message-Id: -Reviewed-by: Eric Blake -[eblake: Adjust test for explicit read_zeroes=False] -Signed-off-by: Eric Blake -(cherry picked from commit ca4bfec41d56a1154da89b105048b3462361d0f0) - -https://bugzilla.redhat.com/show_bug.cgi?id=1930757 -Signed-off-by: Danilo C. L. de Paula ---- - tests/qemu-iotests/300 | 93 ++++++++++++++++++++++++++++++++++++++ - tests/qemu-iotests/300.out | 4 +- - 2 files changed, 95 insertions(+), 2 deletions(-) - -diff --git a/tests/qemu-iotests/300 b/tests/qemu-iotests/300 -index 5b75121b84..b25d8b04c0 100755 ---- a/tests/qemu-iotests/300 -+++ b/tests/qemu-iotests/300 -@@ -588,6 +588,99 @@ class TestCrossAliasMigration(TestDirtyBitmapMigration): - self.verify_dest_has_all_bitmaps() - self.verify_dest_error(None) - -+class TestAliasTransformMigration(TestDirtyBitmapMigration): -+ """ -+ Tests the 'transform' option which modifies bitmap persistence on migration. -+ """ -+ -+ src_node_name = 'node-a' -+ dst_node_name = 'node-b' -+ src_bmap_name = 'bmap-a' -+ dst_bmap_name = 'bmap-b' -+ -+ def setUp(self) -> None: -+ TestDirtyBitmapMigration.setUp(self) -+ -+ # Now create another block device and let both have two bitmaps each -+ result = self.vm_a.qmp('blockdev-add', -+ node_name='node-b', driver='null-co', -+ read_zeroes=False) -+ self.assert_qmp(result, 'return', {}) -+ -+ result = self.vm_b.qmp('blockdev-add', -+ node_name='node-a', driver='null-co', -+ read_zeroes=False) -+ self.assert_qmp(result, 'return', {}) -+ -+ bmaps_to_add = (('node-a', 'bmap-b'), -+ ('node-b', 'bmap-a'), -+ ('node-b', 'bmap-b')) -+ -+ for (node, bmap) in bmaps_to_add: -+ result = self.vm_a.qmp('block-dirty-bitmap-add', -+ node=node, name=bmap) -+ self.assert_qmp(result, 'return', {}) -+ -+ @staticmethod -+ def transform_mapping() -> BlockBitmapMapping: -+ return [ -+ { -+ 'node-name': 'node-a', -+ 'alias': 'node-a', -+ 'bitmaps': [ -+ { -+ 'name': 'bmap-a', -+ 'alias': 'bmap-a', -+ 'transform': -+ { -+ 'persistent': True -+ } -+ }, -+ { -+ 'name': 'bmap-b', -+ 'alias': 'bmap-b' -+ } -+ ] -+ }, -+ { -+ 'node-name': 'node-b', -+ 'alias': 'node-b', -+ 'bitmaps': [ -+ { -+ 'name': 'bmap-a', -+ 'alias': 'bmap-a' -+ }, -+ { -+ 'name': 'bmap-b', -+ 'alias': 'bmap-b' -+ } -+ ] -+ } -+ ] -+ -+ def verify_dest_bitmap_state(self) -> None: -+ bitmaps = self.vm_b.query_bitmaps() -+ -+ for node in bitmaps: -+ bitmaps[node] = sorted(((bmap['name'], bmap['persistent']) for bmap in bitmaps[node])) -+ -+ self.assertEqual(bitmaps, -+ {'node-a': [('bmap-a', True), ('bmap-b', False)], -+ 'node-b': [('bmap-a', False), ('bmap-b', False)]}) -+ -+ def test_transform_on_src(self) -> None: -+ self.set_mapping(self.vm_a, self.transform_mapping()) -+ -+ self.migrate() -+ self.verify_dest_bitmap_state() -+ self.verify_dest_error(None) -+ -+ def test_transform_on_dst(self) -> None: -+ self.set_mapping(self.vm_b, self.transform_mapping()) -+ -+ self.migrate() -+ self.verify_dest_bitmap_state() -+ self.verify_dest_error(None) - - if __name__ == '__main__': - iotests.main(supported_protocols=['file']) -diff --git a/tests/qemu-iotests/300.out b/tests/qemu-iotests/300.out -index cafb8161f7..12e9ab7d57 100644 ---- a/tests/qemu-iotests/300.out -+++ b/tests/qemu-iotests/300.out -@@ -1,5 +1,5 @@ --..................................... -+....................................... - ---------------------------------------------------------------------- --Ran 37 tests -+Ran 39 tests - - OK --- -2.27.0 - diff --git a/kvm-qemu-nbd-Use-SOMAXCONN-for-socket-listen-backlog.patch b/kvm-qemu-nbd-Use-SOMAXCONN-for-socket-listen-backlog.patch deleted file mode 100644 index 573aeaf..0000000 --- a/kvm-qemu-nbd-Use-SOMAXCONN-for-socket-listen-backlog.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 1107799dade18adccfca5097341b6dfb4977e69e Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Mon, 22 Feb 2021 21:34:55 -0500 -Subject: [PATCH 19/54] qemu-nbd: Use SOMAXCONN for socket listen() backlog -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Eric Blake -Message-id: <20210222213455.320104-2-eblake@redhat.com> -Patchwork-id: 101192 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/1] qemu-nbd: Use SOMAXCONN for socket listen() backlog -Bugzilla: 1925345 -RH-Acked-by: Richard Jones -RH-Acked-by: Sergio Lopez Pascual -RH-Acked-by: Daniel P. Berrange - -Our default of a backlog of 1 connection is rather puny; it gets in -the way when we are explicitly allowing multiple clients (such as -qemu-nbd -e N [--shared], or nbd-server-start with its default -"max-connections":0 for unlimited), but is even a problem when we -stick to qemu-nbd's default of only 1 active client but use -t -[--persistent] where a second client can start using the server once -the first finishes. While the effects are less noticeable on TCP -sockets (since the client can poll() to learn when the server is ready -again), it is definitely observable on Unix sockets, where on Linux, a -client will fail with EAGAIN and no recourse but to sleep an arbitrary -amount of time before retrying if the server backlog is already full. - -Since QMP nbd-server-start is always persistent, it now always -requests a backlog of SOMAXCONN; meanwhile, qemu-nbd will request -SOMAXCONN if persistent, otherwise its backlog should be based on the -expected number of clients. - -See https://bugzilla.redhat.com/1925045 for a demonstration of where -our low backlog prevents libnbd from connecting as many parallel -clients as it wants. - -Reported-by: Richard W.M. Jones -Signed-off-by: Eric Blake -CC: qemu-stable@nongnu.org -Message-Id: <20210209152759.209074-2-eblake@redhat.com> -Tested-by: Richard W.M. Jones -Reviewed-by: Daniel P. Berrangé -Signed-off-by: Eric Blake -(cherry picked from commit 582d4210eb2f2ab5baac328fe4b479cd86da1647) -Signed-off-by: Eric Blake -Signed-off-by: Danilo C. L. de Paula ---- - blockdev-nbd.c | 7 ++++++- - qemu-nbd.c | 10 +++++++++- - 2 files changed, 15 insertions(+), 2 deletions(-) - -diff --git a/blockdev-nbd.c b/blockdev-nbd.c -index d8443d235b..b264620b98 100644 ---- a/blockdev-nbd.c -+++ b/blockdev-nbd.c -@@ -134,7 +134,12 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds, - qio_net_listener_set_name(nbd_server->listener, - "nbd-listener"); - -- if (qio_net_listener_open_sync(nbd_server->listener, addr, 1, errp) < 0) { -+ /* -+ * Because this server is persistent, a backlog of SOMAXCONN is -+ * better than trying to size it to max_connections. -+ */ -+ if (qio_net_listener_open_sync(nbd_server->listener, addr, SOMAXCONN, -+ errp) < 0) { - goto error; - } - -diff --git a/qemu-nbd.c b/qemu-nbd.c -index 1d337b7504..ce1dc43d69 100644 ---- a/qemu-nbd.c -+++ b/qemu-nbd.c -@@ -970,8 +970,16 @@ int main(int argc, char **argv) - - server = qio_net_listener_new(); - if (socket_activation == 0) { -+ int backlog; -+ -+ if (persistent) { -+ backlog = SOMAXCONN; -+ } else { -+ backlog = MIN(shared, SOMAXCONN); -+ } - saddr = nbd_build_socket_address(sockpath, bindto, port); -- if (qio_net_listener_open_sync(server, saddr, 1, &local_err) < 0) { -+ if (qio_net_listener_open_sync(server, saddr, backlog, -+ &local_err) < 0) { - object_unref(OBJECT(server)); - error_report_err(local_err); - exit(EXIT_FAILURE); --- -2.27.0 - diff --git a/kvm-qemu-storage-daemon-Enable-object-add.patch b/kvm-qemu-storage-daemon-Enable-object-add.patch deleted file mode 100644 index 8f48b5a..0000000 --- a/kvm-qemu-storage-daemon-Enable-object-add.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 6707057bc09cef526579bddb54ef7d4c3a7883ad Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Tue, 16 Feb 2021 16:19:42 -0500 -Subject: [PATCH 16/54] qemu-storage-daemon: Enable object-add -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Kevin Wolf -Message-id: <20210216161943.126728-5-kwolf@redhat.com> -Patchwork-id: 101103 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 4/5] qemu-storage-daemon: Enable object-add -Bugzilla: 1901323 -RH-Acked-by: Sergio Lopez Pascual -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Max Reitz - -As we don't have a fully QAPIfied version of object-add yet and it still -has 'gen': false in the schema, it needs to be registered explicitly in -init_qmp_commands() to be available for users. - -Fixes: 2af282ec51a27116d0402cab237b8970800f870c -Signed-off-by: Kevin Wolf -Message-Id: <20210204072137.19663-1-kwolf@redhat.com> -Reviewed-by: Daniel P. Berrangé -Signed-off-by: Kevin Wolf -(cherry picked from commit 15d40e9204eb3d89577187f117a1dde2237bdc4d) -Signed-off-by: Kevin Wolf -Signed-off-by: Danilo C. L. de Paula ---- - storage-daemon/qemu-storage-daemon.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c -index d8d172cc60..9021a46b3a 100644 ---- a/storage-daemon/qemu-storage-daemon.c -+++ b/storage-daemon/qemu-storage-daemon.c -@@ -144,6 +144,8 @@ static void init_qmp_commands(void) - qmp_init_marshal(&qmp_commands); - qmp_register_command(&qmp_commands, "query-qmp-schema", - qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG); -+ qmp_register_command(&qmp_commands, "object-add", qmp_object_add, -+ QCO_NO_OPTIONS); - - QTAILQ_INIT(&qmp_cap_negotiation_commands); - qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities", --- -2.27.0 - diff --git a/kvm-qxl-also-notify-the-rendering-is-done-when-skipping-.patch b/kvm-qxl-also-notify-the-rendering-is-done-when-skipping-.patch deleted file mode 100644 index 52532b4..0000000 --- a/kvm-qxl-also-notify-the-rendering-is-done-when-skipping-.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 51c6fc79d712c73bfeec2e4ff6779da3cab649fd Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 1 Mar 2021 08:39:20 -0500 -Subject: [PATCH 2/4] qxl: also notify the rendering is done when skipping it -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20210301083920.895324-3-marcandre.lureau@redhat.com> -Patchwork-id: 101275 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 2/2] qxl: also notify the rendering is done when skipping it -Bugzilla: 1932190 -RH-Acked-by: Philippe Mathieu-Daudé -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Sergio Lopez Pascual - -From: Marc-André Lureau - -Asynchronous handlers may be waiting for the graphic_hw_update_done() to -be called in this case too. - -Fixes: 4d6316218 ("console: add graphic_hw_update_done()") -Signed-off-by: Marc-André Lureau -Message-Id: <20210201201422.446552-3-marcandre.lureau@redhat.com> -Signed-off-by: Gerd Hoffmann - -(cherry picked from commit b577ab2dda3afc7d6a7befabcf226507ff06c17c) -Signed-off-by: Marc-André Lureau -Signed-off-by: Danilo C. L. de Paula ---- - hw/display/qxl-render.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c -index 3ce2e57b8f..d28849b121 100644 ---- a/hw/display/qxl-render.c -+++ b/hw/display/qxl-render.c -@@ -181,6 +181,7 @@ void qxl_render_update(PCIQXLDevice *qxl) - qxl->mode == QXL_MODE_UNDEFINED) { - qxl_render_update_area_unlocked(qxl); - qemu_mutex_unlock(&qxl->ssd.lock); -+ graphic_hw_update_done(qxl->ssd.dcl.con); - return; - } - --- -2.27.0 - diff --git a/kvm-qxl-set-qxl.ssd.dcl.con-on-secondary-devices.patch b/kvm-qxl-set-qxl.ssd.dcl.con-on-secondary-devices.patch deleted file mode 100644 index 55ea413..0000000 --- a/kvm-qxl-set-qxl.ssd.dcl.con-on-secondary-devices.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 94dc0414a7d5dadbbfc29a19617df7facb0ea7d6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 1 Mar 2021 08:39:19 -0500 -Subject: [PATCH 1/4] qxl: set qxl.ssd.dcl.con on secondary devices -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20210301083920.895324-2-marcandre.lureau@redhat.com> -Patchwork-id: 101274 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/2] qxl: set qxl.ssd.dcl.con on secondary devices -Bugzilla: 1932190 -RH-Acked-by: Philippe Mathieu-Daudé -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Sergio Lopez Pascual - -From: Marc-André Lureau - -On secondary QXL devices, the console is only set on qxl.vga.con. But -graphic_hw_update_done() is called with qxl.ssd.dcl.con. - -Like for primary QXL devices, set qxl.sdd.dcl.con = qxl.vga.con. - -Signed-off-by: Marc-André Lureau -Message-Id: <20210201201422.446552-2-marcandre.lureau@redhat.com> -Signed-off-by: Gerd Hoffmann - -(cherry picked from commit c502758670432195d61ff848b1b47b0f78918ae2) -Signed-off-by: Marc-André Lureau -Signed-off-by: Danilo C. L. de Paula ---- - hw/display/qxl.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/display/qxl.c b/hw/display/qxl.c -index 431c107096..50f4756b6a 100644 ---- a/hw/display/qxl.c -+++ b/hw/display/qxl.c -@@ -2266,6 +2266,7 @@ static void qxl_realize_secondary(PCIDevice *dev, Error **errp) - qxl->vga.vram_size, &error_fatal); - qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram); - qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl); -+ qxl->ssd.dcl.con = qxl->vga.con; - qxl->id = qemu_console_get_index(qxl->vga.con); /* == channel_id */ - - qxl_realize_common(qxl, errp); --- -2.27.0 - diff --git a/kvm-redhat-Add-some-devices-for-exporting-upstream-machi.patch b/kvm-redhat-Add-some-devices-for-exporting-upstream-machi.patch deleted file mode 100644 index 46e9ec7..0000000 --- a/kvm-redhat-Add-some-devices-for-exporting-upstream-machi.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 1b6e1cc1f3d8033620bc0c04670d252180bd2c36 Mon Sep 17 00:00:00 2001 -From: Peter Xu -Date: Wed, 10 Feb 2021 17:10:34 -0300 -Subject: [PATCH 11/54] redhat: Add some devices for exporting upstream machine - types - -RH-Author: Peter Xu -Message-id: <20210210171034.129116-2-peterx@redhat.com> -Patchwork-id: 101043 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/1] redhat: Add some devices for exporting upstream machine types -Bugzilla: 1917826 -RH-Acked-by: Sergio Lopez Pascual -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Dr. David Alan Gilbert - -Both "isa-parallel" and "hpet" will be required for the to-be-exported upstream -x86 machine types, so add them back into config. - -Since HPET was disabled for rhel machine types previously, we need to -explicitly do that for RHEL now after we add HPET back. - -Meanwhile, add blockers for the two devices so that they can never be created -on RHEL machine types. That should keep the old behavior for RHEL-AV. - -Signed-off-by: Peter Xu -Signed-off-by: Eduardo Lima (Etrunko) ---- - default-configs/devices/x86_64-softmmu.mak | 6 ++++++ - default-configs/devices/x86_64-upstream-devices.mak | 4 ++++ - hw/char/parallel.c | 9 +++++++++ - hw/i386/pc_piix.c | 2 +- - hw/i386/pc_q35.c | 2 +- - hw/timer/hpet.c | 8 ++++++++ - 6 files changed, 29 insertions(+), 2 deletions(-) - create mode 100644 default-configs/devices/x86_64-upstream-devices.mak - -diff --git a/default-configs/devices/x86_64-softmmu.mak b/default-configs/devices/x86_64-softmmu.mak -index b5de7e5279..e57bcff7d9 100644 ---- a/default-configs/devices/x86_64-softmmu.mak -+++ b/default-configs/devices/x86_64-softmmu.mak -@@ -3,3 +3,9 @@ - #include i386-softmmu.mak - - include x86_64-rh-devices.mak -+ -+# -+# RHEL: this is for the limited upstream machine type support, so to export -+# some more devices than what RHEL machines have. -+# -+include x86_64-upstream-devices.mak -diff --git a/default-configs/devices/x86_64-upstream-devices.mak b/default-configs/devices/x86_64-upstream-devices.mak -new file mode 100644 -index 0000000000..2cd20f54d2 ---- /dev/null -+++ b/default-configs/devices/x86_64-upstream-devices.mak -@@ -0,0 +1,4 @@ -+# We need "isa-parallel" -+CONFIG_PARALLEL=y -+# We need "hpet" -+CONFIG_HPET=y -diff --git a/hw/char/parallel.c b/hw/char/parallel.c -index 8b418abf71..6b3696a237 100644 ---- a/hw/char/parallel.c -+++ b/hw/char/parallel.c -@@ -29,6 +29,7 @@ - #include "chardev/char-parallel.h" - #include "chardev/char-fe.h" - #include "hw/acpi/aml-build.h" -+#include "hw/boards.h" - #include "hw/irq.h" - #include "hw/isa/isa.h" - #include "hw/qdev-properties.h" -@@ -533,6 +534,14 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp) - int base; - uint8_t dummy; - -+ /* Restricted for Red Hat Enterprise Linux */ -+ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); -+ if (strstr(mc->name, "rhel")) { -+ error_setg(errp, "Device %s is not supported with machine type %s", -+ object_get_typename(OBJECT(dev)), mc->name); -+ return; -+ } -+ - if (!qemu_chr_fe_backend_connected(&s->chr)) { - error_setg(errp, "Can't create parallel device, empty char device"); - return; -diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c -index 1b1cc18ae0..6e1f1ba082 100644 ---- a/hw/i386/pc_piix.c -+++ b/hw/i386/pc_piix.c -@@ -1018,7 +1018,7 @@ static void pc_machine_rhel7_options(MachineClass *m) - { - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); - m->family = "pc_piix_Y"; -- m->default_machine_opts = "firmware=bios-256k.bin"; -+ m->default_machine_opts = "firmware=bios-256k.bin,hpet=off"; - pcmc->default_nic_model = "e1000"; - m->default_display = "std"; - m->no_parallel = 1; -diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c -index 72854192a9..a8c0496c9f 100644 ---- a/hw/i386/pc_q35.c -+++ b/hw/i386/pc_q35.c -@@ -580,7 +580,7 @@ static void pc_q35_machine_rhel_options(MachineClass *m) - pcmc->default_nic_model = "e1000e"; - m->family = "pc_q35_Z"; - m->units_per_default_bus = 1; -- m->default_machine_opts = "firmware=bios-256k.bin"; -+ m->default_machine_opts = "firmware=bios-256k.bin,hpet=off"; - m->default_display = "std"; - m->no_floppy = 1; - m->no_parallel = 1; -diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c -index 9520471be2..202e032524 100644 ---- a/hw/timer/hpet.c -+++ b/hw/timer/hpet.c -@@ -733,6 +733,14 @@ static void hpet_realize(DeviceState *dev, Error **errp) - int i; - HPETTimer *timer; - -+ /* Restricted for Red Hat Enterprise Linux */ -+ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); -+ if (strstr(mc->name, "rhel")) { -+ error_setg(errp, "Device %s is not supported with machine type %s", -+ object_get_typename(OBJECT(dev)), mc->name); -+ return; -+ } -+ - if (!s->intcap) { - warn_report("Hpet's intcap not initialized"); - } --- -2.27.0 - diff --git a/kvm-scsi-disk-do-not-complete-requests-early-for-rerror-.patch b/kvm-scsi-disk-do-not-complete-requests-early-for-rerror-.patch deleted file mode 100644 index 1e18da6..0000000 --- a/kvm-scsi-disk-do-not-complete-requests-early-for-rerror-.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 570d5034b8c6124df1830857144dc1ac08c13d06 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 8 Mar 2021 10:48:59 -0500 -Subject: [PATCH 02/15] scsi-disk: do not complete requests early for - rerror/werror=ignore -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Paolo Bonzini -Message-id: <20210308104902.149906-3-pbonzini@redhat.com> -Patchwork-id: 101309 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 2/5] scsi-disk: do not complete requests early for rerror/werror=ignore -Bugzilla: 1927530 -RH-Acked-by: Marc-André Lureau -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Philippe Mathieu-Daudé - -When requested to ignore errors, just do nothing and let the -request complete normally. This means that the request will -be accounted correctly. - -This is what commit 40dce4ee61 ("scsi-disk: fix rerror/werror=ignore", -2018-10-19) was supposed to do: - -Fixes: 40dce4ee61 ("scsi-disk: fix rerror/werror=ignore", 2018-10-19) -Signed-off-by: Paolo Bonzini -(cherry picked from commit 424740def9a42da88550410de9a41ef07cc4a010) -Signed-off-by: Danilo C. L. de Paula ---- - hw/scsi/scsi-disk.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index cecdea2640..e8de15f549 100644 ---- a/hw/scsi/scsi-disk.c -+++ b/hw/scsi/scsi-disk.c -@@ -252,8 +252,7 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) - - blk_error_action(s->qdev.conf.blk, action, is_read, error); - if (action == BLOCK_ERROR_ACTION_IGNORE) { -- scsi_req_complete(&r->req, 0); -- return true; -+ return false; - } - - if (action == BLOCK_ERROR_ACTION_STOP) { --- -2.27.0 - diff --git a/kvm-scsi-disk-move-scsi_handle_rw_error-earlier.patch b/kvm-scsi-disk-move-scsi_handle_rw_error-earlier.patch deleted file mode 100644 index 766321a..0000000 --- a/kvm-scsi-disk-move-scsi_handle_rw_error-earlier.patch +++ /dev/null @@ -1,222 +0,0 @@ -From c029d041853805ba612d27886f769c0e004c35e6 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 8 Mar 2021 10:48:58 -0500 -Subject: [PATCH 01/15] scsi-disk: move scsi_handle_rw_error earlier -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Paolo Bonzini -Message-id: <20210308104902.149906-2-pbonzini@redhat.com> -Patchwork-id: 101307 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/5] scsi-disk: move scsi_handle_rw_error earlier -Bugzilla: 1927530 -RH-Acked-by: Marc-André Lureau -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Philippe Mathieu-Daudé - -Remove the forward declaration. - -Signed-off-by: Paolo Bonzini -(cherry picked from commit f95f61c2c9618fae7d8ea4c1d63e7416884bad52) -Signed-off-by: Danilo C. L. de Paula ---- - hw/scsi/scsi-disk.c | 168 ++++++++++++++++++++++---------------------- - 1 file changed, 83 insertions(+), 85 deletions(-) - -diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index 90841ad791..cecdea2640 100644 ---- a/hw/scsi/scsi-disk.c -+++ b/hw/scsi/scsi-disk.c -@@ -110,8 +110,6 @@ struct SCSIDiskState { - uint16_t rotation_rate; - }; - --static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed); -- - static void scsi_free_request(SCSIRequest *req) - { - SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); -@@ -181,6 +179,89 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req) - qemu_iovec_init_external(&r->qiov, &r->iov, 1); - } - -+/* -+ * scsi_handle_rw_error has two return values. False means that the error -+ * must be ignored, true means that the error has been processed and the -+ * caller should not do anything else for this request. Note that -+ * scsi_handle_rw_error always manages its reference counts, independent -+ * of the return value. -+ */ -+static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) -+{ -+ bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV); -+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); -+ SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); -+ BlockErrorAction action = blk_get_error_action(s->qdev.conf.blk, -+ is_read, error); -+ -+ if (action == BLOCK_ERROR_ACTION_REPORT) { -+ if (acct_failed) { -+ block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); -+ } -+ switch (error) { -+ case 0: -+ /* A passthrough command has run and has produced sense data; check -+ * whether the error has to be handled by the guest or should rather -+ * pause the host. -+ */ -+ assert(r->status && *r->status); -+ if (scsi_sense_buf_is_guest_recoverable(r->req.sense, sizeof(r->req.sense))) { -+ /* These errors are handled by guest. */ -+ sdc->update_sense(&r->req); -+ scsi_req_complete(&r->req, *r->status); -+ return true; -+ } -+ error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense)); -+ break; -+#ifdef CONFIG_LINUX -+ /* These errno mapping are specific to Linux. For more information: -+ * - scsi_decide_disposition in drivers/scsi/scsi_error.c -+ * - scsi_result_to_blk_status in drivers/scsi/scsi_lib.c -+ * - blk_errors[] in block/blk-core.c -+ */ -+ case EBADE: -+ /* DID_NEXUS_FAILURE -> BLK_STS_NEXUS. */ -+ scsi_req_complete(&r->req, RESERVATION_CONFLICT); -+ break; -+ case ENODATA: -+ /* DID_MEDIUM_ERROR -> BLK_STS_MEDIUM. */ -+ scsi_check_condition(r, SENSE_CODE(READ_ERROR)); -+ break; -+ case EREMOTEIO: -+ /* DID_TARGET_FAILURE -> BLK_STS_TARGET. */ -+ scsi_req_complete(&r->req, HARDWARE_ERROR); -+ break; -+#endif -+ case ENOMEDIUM: -+ scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); -+ break; -+ case ENOMEM: -+ scsi_check_condition(r, SENSE_CODE(TARGET_FAILURE)); -+ break; -+ case EINVAL: -+ scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); -+ break; -+ case ENOSPC: -+ scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED)); -+ break; -+ default: -+ scsi_check_condition(r, SENSE_CODE(IO_ERROR)); -+ break; -+ } -+ } -+ -+ blk_error_action(s->qdev.conf.blk, action, is_read, error); -+ if (action == BLOCK_ERROR_ACTION_IGNORE) { -+ scsi_req_complete(&r->req, 0); -+ return true; -+ } -+ -+ if (action == BLOCK_ERROR_ACTION_STOP) { -+ scsi_req_retry(&r->req); -+ } -+ return true; -+} -+ - static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) - { - if (r->req.io_canceled) { -@@ -427,89 +508,6 @@ static void scsi_read_data(SCSIRequest *req) - } - } - --/* -- * scsi_handle_rw_error has two return values. False means that the error -- * must be ignored, true means that the error has been processed and the -- * caller should not do anything else for this request. Note that -- * scsi_handle_rw_error always manages its reference counts, independent -- * of the return value. -- */ --static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) --{ -- bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV); -- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); -- SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); -- BlockErrorAction action = blk_get_error_action(s->qdev.conf.blk, -- is_read, error); -- -- if (action == BLOCK_ERROR_ACTION_REPORT) { -- if (acct_failed) { -- block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); -- } -- switch (error) { -- case 0: -- /* A passthrough command has run and has produced sense data; check -- * whether the error has to be handled by the guest or should rather -- * pause the host. -- */ -- assert(r->status && *r->status); -- if (scsi_sense_buf_is_guest_recoverable(r->req.sense, sizeof(r->req.sense))) { -- /* These errors are handled by guest. */ -- sdc->update_sense(&r->req); -- scsi_req_complete(&r->req, *r->status); -- return true; -- } -- error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense)); -- break; --#ifdef CONFIG_LINUX -- /* These errno mapping are specific to Linux. For more information: -- * - scsi_decide_disposition in drivers/scsi/scsi_error.c -- * - scsi_result_to_blk_status in drivers/scsi/scsi_lib.c -- * - blk_errors[] in block/blk-core.c -- */ -- case EBADE: -- /* DID_NEXUS_FAILURE -> BLK_STS_NEXUS. */ -- scsi_req_complete(&r->req, RESERVATION_CONFLICT); -- break; -- case ENODATA: -- /* DID_MEDIUM_ERROR -> BLK_STS_MEDIUM. */ -- scsi_check_condition(r, SENSE_CODE(READ_ERROR)); -- break; -- case EREMOTEIO: -- /* DID_TARGET_FAILURE -> BLK_STS_TARGET. */ -- scsi_req_complete(&r->req, HARDWARE_ERROR); -- break; --#endif -- case ENOMEDIUM: -- scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); -- break; -- case ENOMEM: -- scsi_check_condition(r, SENSE_CODE(TARGET_FAILURE)); -- break; -- case EINVAL: -- scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); -- break; -- case ENOSPC: -- scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED)); -- break; -- default: -- scsi_check_condition(r, SENSE_CODE(IO_ERROR)); -- break; -- } -- } -- -- blk_error_action(s->qdev.conf.blk, action, is_read, error); -- if (action == BLOCK_ERROR_ACTION_IGNORE) { -- scsi_req_complete(&r->req, 0); -- return true; -- } -- -- if (action == BLOCK_ERROR_ACTION_STOP) { -- scsi_req_retry(&r->req); -- } -- return true; --} -- - static void scsi_write_complete_noio(SCSIDiskReq *r, int ret) - { - uint32_t n; --- -2.27.0 - diff --git a/kvm-scsi-disk-pass-SCSI-status-to-scsi_handle_rw_error.patch b/kvm-scsi-disk-pass-SCSI-status-to-scsi_handle_rw_error.patch deleted file mode 100644 index eb49e97..0000000 --- a/kvm-scsi-disk-pass-SCSI-status-to-scsi_handle_rw_error.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 620d646367a38ff9908de811e1f0a24a3f105529 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 8 Mar 2021 10:49:01 -0500 -Subject: [PATCH 04/15] scsi-disk: pass SCSI status to scsi_handle_rw_error -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Paolo Bonzini -Message-id: <20210308104902.149906-5-pbonzini@redhat.com> -Patchwork-id: 101310 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 4/5] scsi-disk: pass SCSI status to scsi_handle_rw_error -Bugzilla: 1927530 -RH-Acked-by: Marc-André Lureau -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Philippe Mathieu-Daudé - -Instead of fishing it from *r->status, just pass the SCSI status -as a positive value of the second parameter and an errno as a -negative value. - -Signed-off-by: Paolo Bonzini -(cherry picked from commit f63c68bc0f514694a958b2e84a204b7792d28b17) -Signed-off-by: Danilo C. L. de Paula ---- - hw/scsi/scsi-disk.c | 38 +++++++++++++++++++++++++++----------- - 1 file changed, 27 insertions(+), 11 deletions(-) - -diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index 7393f33ee2..c545f0b674 100644 ---- a/hw/scsi/scsi-disk.c -+++ b/hw/scsi/scsi-disk.c -@@ -186,34 +186,48 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req) - * scsi_handle_rw_error always manages its reference counts, independent - * of the return value. - */ --static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) -+static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed) - { - bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV); - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); -- BlockErrorAction action = blk_get_error_action(s->qdev.conf.blk, -- is_read, error); -- SCSISense sense; -+ SCSISense sense = SENSE_CODE(NO_SENSE); -+ int error = 0; -+ bool req_has_sense = false; -+ BlockErrorAction action; -+ int status; - -+ if (ret < 0) { -+ status = scsi_sense_from_errno(-ret, &sense); -+ error = -ret; -+ } else { -+ /* A passthrough command has completed with nonzero status. */ -+ status = ret; -+ if (status == CHECK_CONDITION) { -+ req_has_sense = true; -+ error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense)); -+ } else { -+ error = EINVAL; -+ } -+ } -+ -+ action = blk_get_error_action(s->qdev.conf.blk, is_read, error); - if (action == BLOCK_ERROR_ACTION_REPORT) { - if (acct_failed) { - block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); - } -- if (error == 0) { -+ if (req_has_sense) { - /* A passthrough command has run and has produced sense data; check - * whether the error has to be handled by the guest or should rather - * pause the host. - */ -- assert(r->status && *r->status); - if (scsi_sense_buf_is_guest_recoverable(r->req.sense, sizeof(r->req.sense))) { - /* These errors are handled by guest. */ - sdc->update_sense(&r->req); -- scsi_req_complete(&r->req, *r->status); -+ scsi_req_complete(&r->req, status); - return true; - } -- error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense)); - } else { -- int status = scsi_sense_from_errno(error, &sense); - if (status == CHECK_CONDITION) { - scsi_req_build_sense(&r->req, sense); - } -@@ -239,8 +253,10 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) - return true; - } - -- if (ret < 0 || (r->status && *r->status)) { -- return scsi_handle_rw_error(r, -ret, acct_failed); -+ if (ret < 0) { -+ return scsi_handle_rw_error(r, ret, acct_failed); -+ } else if (r->status && *r->status) { -+ return scsi_handle_rw_error(r, *r->status, acct_failed); - } - - return false; --- -2.27.0 - diff --git a/kvm-scsi-disk-pass-guest-recoverable-errors-through-even.patch b/kvm-scsi-disk-pass-guest-recoverable-errors-through-even.patch deleted file mode 100644 index 58fac83..0000000 --- a/kvm-scsi-disk-pass-guest-recoverable-errors-through-even.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 9cf10f41fc8a89cd80f27e3b2674dec7eead60d4 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 8 Mar 2021 10:49:02 -0500 -Subject: [PATCH 05/15] scsi-disk: pass guest recoverable errors through even - for rerror=stop -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Paolo Bonzini -Message-id: <20210308104902.149906-6-pbonzini@redhat.com> -Patchwork-id: 101311 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 5/5] scsi-disk: pass guest recoverable errors through even for rerror=stop -Bugzilla: 1927530 -RH-Acked-by: Marc-André Lureau -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Philippe Mathieu-Daudé - -Right now, recoverable sense values are only passed directly to the -guest only for rerror=report. However, when rerror/werror are 'stop' -we still don't want the host to be involved on every UNIT ATTENTION -(especially considered that the QMP event will not have enough information -to act on the report). - -Signed-off-by: Paolo Bonzini -(cherry picked from commit 782a78c9e994c2be23467262f50e885a0eb0d9fc) -Signed-off-by: Danilo C. L. de Paula ---- - hw/scsi/scsi-disk.c | 51 +++++++++++++++++++++++++-------------------- - 1 file changed, 28 insertions(+), 23 deletions(-) - -diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index c545f0b674..f2abbf0d87 100644 ---- a/hw/scsi/scsi-disk.c -+++ b/hw/scsi/scsi-disk.c -@@ -211,39 +211,44 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed) - } - } - -- action = blk_get_error_action(s->qdev.conf.blk, is_read, error); -- if (action == BLOCK_ERROR_ACTION_REPORT) { -+ /* -+ * Check whether the error has to be handled by the guest or should -+ * rather follow the rerror=/werror= settings. Guest-handled errors -+ * are usually retried immediately, so do not post them to QMP and -+ * do not account them as failed I/O. -+ */ -+ if (req_has_sense && -+ scsi_sense_buf_is_guest_recoverable(r->req.sense, sizeof(r->req.sense))) { -+ action = BLOCK_ERROR_ACTION_REPORT; -+ acct_failed = false; -+ } else { -+ action = blk_get_error_action(s->qdev.conf.blk, is_read, error); -+ blk_error_action(s->qdev.conf.blk, action, is_read, error); -+ } -+ -+ switch (action) { -+ case BLOCK_ERROR_ACTION_REPORT: - if (acct_failed) { - block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); - } - if (req_has_sense) { -- /* A passthrough command has run and has produced sense data; check -- * whether the error has to be handled by the guest or should rather -- * pause the host. -- */ -- if (scsi_sense_buf_is_guest_recoverable(r->req.sense, sizeof(r->req.sense))) { -- /* These errors are handled by guest. */ -- sdc->update_sense(&r->req); -- scsi_req_complete(&r->req, status); -- return true; -- } -- } else { -- if (status == CHECK_CONDITION) { -- scsi_req_build_sense(&r->req, sense); -- } -- scsi_req_complete(&r->req, status); -+ sdc->update_sense(&r->req); -+ } else if (status == CHECK_CONDITION) { -+ scsi_req_build_sense(&r->req, sense); - } -- } -+ scsi_req_complete(&r->req, status); -+ return true; - -- blk_error_action(s->qdev.conf.blk, action, is_read, error); -- if (action == BLOCK_ERROR_ACTION_IGNORE) { -+ case BLOCK_ERROR_ACTION_IGNORE: - return false; -- } - -- if (action == BLOCK_ERROR_ACTION_STOP) { -+ case BLOCK_ERROR_ACTION_STOP: - scsi_req_retry(&r->req); -+ return true; -+ -+ default: -+ g_assert_not_reached(); - } -- return true; - } - - static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) --- -2.27.0 - diff --git a/kvm-scsi-fix-device-removal-race-vs-IO-restart-callback-.patch b/kvm-scsi-fix-device-removal-race-vs-IO-restart-callback-.patch deleted file mode 100644 index 75baf13..0000000 --- a/kvm-scsi-fix-device-removal-race-vs-IO-restart-callback-.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 3b537ab3eb342af4222a8cf825062d17893cd18f Mon Sep 17 00:00:00 2001 -From: Maxim Levitsky -Date: Wed, 27 Jan 2021 11:47:54 -0500 -Subject: [PATCH 1/7] scsi: fix device removal race vs IO restart callback on - resume - -RH-Author: Maxim Levitsky -Message-id: <20210127114754.477582-2-mlevitsk@redhat.com> -Patchwork-id: 100795 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/1] scsi: fix device removal race vs IO restart callback on resume -Bugzilla: 1854811 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: John Snow - -There is (mostly theoretical) race between removal of a scsi device and -scsi_dma_restart_bh. - -It used to be easier to hit this race prior to my / Paulo's patch series -that added rcu to scsi bus device handling code, but IMHO this race -should still be possible to hit, at least in theory. - -Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1854811 - -Fix it anyway with a patch that was proposed by Paulo in the above bugzilla. - -Suggested-by: Paolo Bonzini -Signed-off-by: Maxim Levitsky -Message-Id: <20201210125929.1136390-2-mlevitsk@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit cfd4e36352d4426221aa94da44a172da1aaa741b) -Signed-off-by: Maxim Levitsky -Signed-off-by: Eduardo Lima (Etrunko) ---- - hw/scsi/scsi-bus.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c -index b901e701f0..edb5c3492a 100644 ---- a/hw/scsi/scsi-bus.c -+++ b/hw/scsi/scsi-bus.c -@@ -170,6 +170,8 @@ static void scsi_dma_restart_bh(void *opaque) - scsi_req_unref(req); - } - aio_context_release(blk_get_aio_context(s->conf.blk)); -+ /* Drop the reference that was acquired in scsi_dma_restart_cb */ -+ object_unref(OBJECT(s)); - } - - void scsi_req_retry(SCSIRequest *req) -@@ -188,6 +190,8 @@ static void scsi_dma_restart_cb(void *opaque, int running, RunState state) - } - if (!s->bh) { - AioContext *ctx = blk_get_aio_context(s->conf.blk); -+ /* The reference is dropped in scsi_dma_restart_bh.*/ -+ object_ref(OBJECT(s)); - s->bh = aio_bh_new(ctx, scsi_dma_restart_bh, s); - qemu_bh_schedule(s->bh); - } --- -2.18.4 - diff --git a/kvm-scsi-introduce-scsi_sense_from_errno.patch b/kvm-scsi-introduce-scsi_sense_from_errno.patch deleted file mode 100644 index 4a13519..0000000 --- a/kvm-scsi-introduce-scsi_sense_from_errno.patch +++ /dev/null @@ -1,181 +0,0 @@ -From 38a29a168f4b377eb6381469af16887e12ebfa3d Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 8 Mar 2021 10:49:00 -0500 -Subject: [PATCH 03/15] scsi: introduce scsi_sense_from_errno() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Paolo Bonzini -Message-id: <20210308104902.149906-4-pbonzini@redhat.com> -Patchwork-id: 101308 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 3/5] scsi: introduce scsi_sense_from_errno() -Bugzilla: 1927530 -RH-Acked-by: Marc-André Lureau -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Philippe Mathieu-Daudé - -The new function is an extension of the switch statement in scsi-disk.c -which also includes the errno cases only found in sg_io_sense_from_errno. -This allows us to consolidate the errno handling. - -Extracted from a patch by Hannes Reinecke . - -Signed-off-by: Paolo Bonzini -(cherry picked from commit d7a84021db8eeddcd5d24ab591a1434763caff6c) -Signed-off-by: Danilo C. L. de Paula ---- - hw/scsi/scsi-disk.c | 45 +++++++------------------------------- - include/scsi/utils.h | 2 ++ - scsi/utils.c | 51 +++++++++++++++++++++++++++++++++++--------- - 3 files changed, 51 insertions(+), 47 deletions(-) - -diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index e8de15f549..7393f33ee2 100644 ---- a/hw/scsi/scsi-disk.c -+++ b/hw/scsi/scsi-disk.c -@@ -193,13 +193,13 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) - SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); - BlockErrorAction action = blk_get_error_action(s->qdev.conf.blk, - is_read, error); -+ SCSISense sense; - - if (action == BLOCK_ERROR_ACTION_REPORT) { - if (acct_failed) { - block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); - } -- switch (error) { -- case 0: -+ if (error == 0) { - /* A passthrough command has run and has produced sense data; check - * whether the error has to be handled by the guest or should rather - * pause the host. -@@ -212,41 +212,12 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) - return true; - } - error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense)); -- break; --#ifdef CONFIG_LINUX -- /* These errno mapping are specific to Linux. For more information: -- * - scsi_decide_disposition in drivers/scsi/scsi_error.c -- * - scsi_result_to_blk_status in drivers/scsi/scsi_lib.c -- * - blk_errors[] in block/blk-core.c -- */ -- case EBADE: -- /* DID_NEXUS_FAILURE -> BLK_STS_NEXUS. */ -- scsi_req_complete(&r->req, RESERVATION_CONFLICT); -- break; -- case ENODATA: -- /* DID_MEDIUM_ERROR -> BLK_STS_MEDIUM. */ -- scsi_check_condition(r, SENSE_CODE(READ_ERROR)); -- break; -- case EREMOTEIO: -- /* DID_TARGET_FAILURE -> BLK_STS_TARGET. */ -- scsi_req_complete(&r->req, HARDWARE_ERROR); -- break; --#endif -- case ENOMEDIUM: -- scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); -- break; -- case ENOMEM: -- scsi_check_condition(r, SENSE_CODE(TARGET_FAILURE)); -- break; -- case EINVAL: -- scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); -- break; -- case ENOSPC: -- scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED)); -- break; -- default: -- scsi_check_condition(r, SENSE_CODE(IO_ERROR)); -- break; -+ } else { -+ int status = scsi_sense_from_errno(error, &sense); -+ if (status == CHECK_CONDITION) { -+ scsi_req_build_sense(&r->req, sense); -+ } -+ scsi_req_complete(&r->req, status); - } - } - -diff --git a/include/scsi/utils.h b/include/scsi/utils.h -index fbc5588279..878434a8f5 100644 ---- a/include/scsi/utils.h -+++ b/include/scsi/utils.h -@@ -133,4 +133,6 @@ int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, - SCSISense *sense); - #endif - -+int scsi_sense_from_errno(int errno_value, SCSISense *sense); -+ - #endif -diff --git a/scsi/utils.c b/scsi/utils.c -index b37c283014..c93458b80e 100644 ---- a/scsi/utils.c -+++ b/scsi/utils.c -@@ -560,21 +560,52 @@ const char *scsi_command_name(uint8_t cmd) - return names[cmd]; - } - -+int scsi_sense_from_errno(int errno_value, SCSISense *sense) -+{ -+ switch (errno_value) { -+ case 0: -+ return GOOD; -+ case EDOM: -+ return TASK_SET_FULL; -+#ifdef CONFIG_LINUX -+ /* These errno mapping are specific to Linux. For more information: -+ * - scsi_decide_disposition in drivers/scsi/scsi_error.c -+ * - scsi_result_to_blk_status in drivers/scsi/scsi_lib.c -+ * - blk_errors[] in block/blk-core.c -+ */ -+ case EBADE: -+ return RESERVATION_CONFLICT; -+ case ENODATA: -+ *sense = SENSE_CODE(READ_ERROR); -+ return CHECK_CONDITION; -+ case EREMOTEIO: -+ *sense = SENSE_CODE(LUN_COMM_FAILURE); -+ return CHECK_CONDITION; -+#endif -+ case ENOMEDIUM: -+ *sense = SENSE_CODE(NO_MEDIUM); -+ return CHECK_CONDITION; -+ case ENOMEM: -+ *sense = SENSE_CODE(TARGET_FAILURE); -+ return CHECK_CONDITION; -+ case EINVAL: -+ *sense = SENSE_CODE(INVALID_FIELD); -+ return CHECK_CONDITION; -+ case ENOSPC: -+ *sense = SENSE_CODE(SPACE_ALLOC_FAILED); -+ return CHECK_CONDITION; -+ default: -+ *sense = SENSE_CODE(IO_ERROR); -+ return CHECK_CONDITION; -+ } -+} -+ - #ifdef CONFIG_LINUX - int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, - SCSISense *sense) - { - if (errno_value != 0) { -- switch (errno_value) { -- case EDOM: -- return TASK_SET_FULL; -- case ENOMEM: -- *sense = SENSE_CODE(TARGET_FAILURE); -- return CHECK_CONDITION; -- default: -- *sense = SENSE_CODE(IO_ERROR); -- return CHECK_CONDITION; -- } -+ return scsi_sense_from_errno(errno_value, sense); - } else { - if (io_hdr->host_status == SG_ERR_DID_NO_CONNECT || - io_hdr->host_status == SG_ERR_DID_BUS_BUSY || --- -2.27.0 - diff --git a/kvm-spapr-Adjust-firmware-path-of-PCI-devices.patch b/kvm-spapr-Adjust-firmware-path-of-PCI-devices.patch deleted file mode 100644 index e5a4937..0000000 --- a/kvm-spapr-Adjust-firmware-path-of-PCI-devices.patch +++ /dev/null @@ -1,205 +0,0 @@ -From 2cb473c2e1cd671da4458b58a0f760f4f1c36cbc Mon Sep 17 00:00:00 2001 -From: Greg Kurz -Date: Wed, 10 Feb 2021 16:54:03 -0300 -Subject: [PATCH 08/54] spapr: Adjust firmware path of PCI devices -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Greg Kurz -Message-id: <20210210165403.469213-2-gkurz@redhat.com> -Patchwork-id: 101036 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/1] spapr: Adjust firmware path of PCI devices -Bugzilla: 1920941 -RH-Acked-by: Philippe Mathieu-Daudé -RH-Acked-by: David Gibson -RH-Acked-by: Laszlo Ersek - -From: Greg Kurz - -It is currently not possible to perform a strict boot from USB storage: - -$ qemu-system-ppc64 -accel kvm -nodefaults -nographic -serial stdio \ - -boot strict=on \ - -device qemu-xhci \ - -device usb-storage,drive=disk,bootindex=0 \ - -blockdev driver=file,node-name=disk,filename=fedora-ppc64le.qcow2 - -SLOF ********************************************************************** -QEMU Starting - Build Date = Jul 17 2020 11:15:24 - FW Version = git-e18ddad8516ff2cf - Press "s" to enter Open Firmware. - -Populating /vdevice methods -Populating /vdevice/vty@71000000 -Populating /vdevice/nvram@71000001 -Populating /pci@800000020000000 - 00 0000 (D) : 1b36 000d serial bus [ usb-xhci ] -No NVRAM common partition, re-initializing... -Scanning USB - XHCI: Initializing - USB Storage - SCSI: Looking for devices - 101000000000000 DISK : "QEMU QEMU HARDDISK 2.5+" -Using default console: /vdevice/vty@71000000 - - Welcome to Open Firmware - - Copyright (c) 2004, 2017 IBM Corporation All rights reserved. - This program and the accompanying materials are made available - under the terms of the BSD License available at - http://www.opensource.org/licenses/bsd-license.php - -Trying to load: from: /pci@800000020000000/usb@0/storage@1/disk@101000000000000 ... -E3405: No such device - -E3407: Load failed - - Type 'boot' and press return to continue booting the system. - Type 'reset-all' and press return to reboot the system. - -Ready! -0 > - -The device tree handed over by QEMU to SLOF indeed contains: - -qemu,boot-list = - "/pci@800000020000000/usb@0/storage@1/disk@101000000000000 HALT"; - -but the device node is named usb-xhci@0, not usb@0. - -This happens because the firmware names of PCI devices returned -by get_boot_devices_list() come from pcibus_get_fw_dev_path(), -while the sPAPR PHB code uses a different naming scheme for -device nodes. This inconsistency has always been there but it was -hidden for a long time because SLOF used to rename USB device -nodes, until this commit, merged in QEMU 4.2.0 : - -commit 85164ad4ed9960cac842fa4cc067c6b6699b0994 -Author: Alexey Kardashevskiy -Date: Wed Sep 11 16:24:32 2019 +1000 - - pseries: Update SLOF firmware image - - This fixes USB host bus adapter name in the device tree to match QEMU's - one. - - Signed-off-by: Alexey Kardashevskiy - Signed-off-by: David Gibson - -Fortunately, sPAPR implements the firmware path provider interface. -This provides a way to override the default firmware paths. - -Just factor out the sPAPR PHB naming logic from spapr_dt_pci_device() -to a helper, and use it in the sPAPR firmware path provider hook. - -Fixes: 85164ad4ed99 ("pseries: Update SLOF firmware image") -Signed-off-by: Greg Kurz -Message-Id: <20210122170157.246374-1-groug@kaod.org> -Reviewed-by: Daniel Henrique Barboza -Signed-off-by: David Gibson -(cherry picked from commit 040bdafce12f750816d879442014df2999a995c4) -Signed-off-by: Greg Kurz -Signed-off-by: Eduardo Lima (Etrunko) ---- - hw/ppc/spapr.c | 5 +++++ - hw/ppc/spapr_pci.c | 33 ++++++++++++++++++--------------- - include/hw/pci-host/spapr.h | 2 ++ - 3 files changed, 25 insertions(+), 15 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index a67df8cb26..c6a97e7964 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -3057,6 +3057,7 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus, - SCSIDevice *d = CAST(SCSIDevice, dev, TYPE_SCSI_DEVICE); - SpaprPhbState *phb = CAST(SpaprPhbState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE); - VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON); -+ PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE); - - if (d) { - void *spapr = CAST(void, bus->parent, "spapr-vscsi"); -@@ -3130,6 +3131,10 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus, - return g_strdup_printf("pci@%x", PCI_SLOT(pcidev->devfn)); - } - -+ if (pcidev) { -+ return spapr_pci_fw_dev_name(pcidev); -+ } -+ - return NULL; - } - -diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c -index 88ce87f130..e78e917af1 100644 ---- a/hw/ppc/spapr_pci.c -+++ b/hw/ppc/spapr_pci.c -@@ -1334,15 +1334,29 @@ static int spapr_dt_pci_bus(SpaprPhbState *sphb, PCIBus *bus, - return offset; - } - -+char *spapr_pci_fw_dev_name(PCIDevice *dev) -+{ -+ const gchar *basename; -+ int slot = PCI_SLOT(dev->devfn); -+ int func = PCI_FUNC(dev->devfn); -+ uint32_t ccode = pci_default_read_config(dev, PCI_CLASS_PROG, 3); -+ -+ basename = dt_name_from_class((ccode >> 16) & 0xff, (ccode >> 8) & 0xff, -+ ccode & 0xff); -+ -+ if (func != 0) { -+ return g_strdup_printf("%s@%x,%x", basename, slot, func); -+ } else { -+ return g_strdup_printf("%s@%x", basename, slot); -+ } -+} -+ - /* create OF node for pci device and required OF DT properties */ - static int spapr_dt_pci_device(SpaprPhbState *sphb, PCIDevice *dev, - void *fdt, int parent_offset) - { - int offset; -- const gchar *basename; -- gchar *nodename; -- int slot = PCI_SLOT(dev->devfn); -- int func = PCI_FUNC(dev->devfn); -+ g_autofree gchar *nodename = spapr_pci_fw_dev_name(dev); - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); - ResourceProps rp; - SpaprDrc *drc = drc_from_dev(sphb, dev); -@@ -1359,19 +1373,8 @@ static int spapr_dt_pci_device(SpaprPhbState *sphb, PCIDevice *dev, - uint32_t pci_status = pci_default_read_config(dev, PCI_STATUS, 2); - gchar *loc_code; - -- basename = dt_name_from_class((ccode >> 16) & 0xff, (ccode >> 8) & 0xff, -- ccode & 0xff); -- -- if (func != 0) { -- nodename = g_strdup_printf("%s@%x,%x", basename, slot, func); -- } else { -- nodename = g_strdup_printf("%s@%x", basename, slot); -- } -- - _FDT(offset = fdt_add_subnode(fdt, parent_offset, nodename)); - -- g_free(nodename); -- - /* in accordance with PAPR+ v2.7 13.6.3, Table 181 */ - _FDT(fdt_setprop_cell(fdt, offset, "vendor-id", vendor_id)); - _FDT(fdt_setprop_cell(fdt, offset, "device-id", device_id)); -diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h -index bd014823a9..5b03a7b0eb 100644 ---- a/include/hw/pci-host/spapr.h -+++ b/include/hw/pci-host/spapr.h -@@ -210,4 +210,6 @@ static inline unsigned spapr_phb_windows_supported(SpaprPhbState *sphb) - return sphb->ddw_enabled ? SPAPR_PCI_DMA_MAX_WINDOWS : 1; - } - -+char *spapr_pci_fw_dev_name(PCIDevice *dev); -+ - #endif /* PCI_HOST_SPAPR_H */ --- -2.27.0 - diff --git a/kvm-spapr-Allow-memory-unplug-to-always-succeed.patch b/kvm-spapr-Allow-memory-unplug-to-always-succeed.patch deleted file mode 100644 index f7a6b9a..0000000 --- a/kvm-spapr-Allow-memory-unplug-to-always-succeed.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 1365bf10ad49fd7c0a3b4e2eabeaacd1abf60d18 Mon Sep 17 00:00:00 2001 -From: Greg Kurz -Date: Tue, 19 Jan 2021 15:20:43 -0500 -Subject: [PATCH 1/5] spapr: Allow memory unplug to always succeed - -RH-Author: Greg Kurz -Message-id: <20210119152044.1019191-2-gkurz@redhat.com> -Patchwork-id: 100690 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/2] spapr: Allow memory unplug to always succeed -Bugzilla: 1914069 -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Laurent Vivier -RH-Acked-by: David Gibson - -From: Greg Kurz - -It is currently impossible to hot-unplug a memory device between -machine reset and CAS. - -(qemu) device_del dimm1 -Error: Memory hot unplug not supported for this guest - -This limitation was introduced in order to provide an explicit -error path for older guests that didn't support hot-plug event -sources (and thus memory hot-unplug). - -The linux kernel has been supporting these since 4.11. All recent -enough guests are thus capable of handling the removal of a memory -device at all time, including during early boot. - -Lift the limitation for the latest machine type. This means that -trying to unplug memory from a guest that doesn't support it will -likely just do nothing and the memory will only get removed at -next reboot. Such older guests can still get the existing behavior -by using an older machine type. - -Signed-off-by: Greg Kurz -Message-Id: <160794035064.23292.17560963281911312439.stgit@bahia.lan> -Signed-off-by: David Gibson -(cherry picked from commit 1e8b5b1aa16b7d73ba8ba52c95d0b52329d5c9d0) -Signed-off-by: Greg Kurz - -Conflicts: - hw/ppc/spapr.c - -Conflict because RHEL-AV doesn't have upstream 576a00bdeb5b ("hw: add -compat machines for 6.0"). Just ignore the change that sets -pre_6_0_memory_unplug for older machine types since the next patch -removes the flag. - -Signed-off-by: Eduardo Lima (Etrunko) ---- - hw/ppc/spapr.c | 3 ++- - hw/ppc/spapr_events.c | 3 ++- - include/hw/ppc/spapr.h | 1 + - 3 files changed, 5 insertions(+), 2 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 4f61b64a21..65a647134a 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -4064,7 +4064,8 @@ static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev, - SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc); - - if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -- if (spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) { -+ if (!smc->pre_6_0_memory_unplug || -+ spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) { - spapr_memory_unplug_request(hotplug_dev, dev, errp); - } else { - /* NOTE: this means there is a window after guest reset, prior to -diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c -index 1add53547e..c30123177b 100644 ---- a/hw/ppc/spapr_events.c -+++ b/hw/ppc/spapr_events.c -@@ -659,7 +659,8 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action, - /* we should not be using count_indexed value unless the guest - * supports dedicated hotplug event source - */ -- g_assert(spapr_ovec_test(spapr->ov5_cas, OV5_HP_EVT)); -+ g_assert(!SPAPR_MACHINE_GET_CLASS(spapr)->pre_6_0_memory_unplug || -+ spapr_ovec_test(spapr->ov5_cas, OV5_HP_EVT)); - hp->drc_id.count_indexed.count = - cpu_to_be32(drc_id->count_indexed.count); - hp->drc_id.count_indexed.index = -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index 28bbf07f8f..4941fe9b4f 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -142,6 +142,7 @@ struct SpaprMachineClass { - hwaddr rma_limit; /* clamp the RMA to this size */ - bool pre_5_1_assoc_refpoints; - bool pre_5_2_numa_associativity; -+ bool pre_6_0_memory_unplug; - - bool has_power9_support; - void (*phb_placement)(SpaprMachineState *spapr, uint32_t index, --- -2.18.4 - diff --git a/kvm-spapr-Improve-handling-of-memory-unplug-with-old-gue.patch b/kvm-spapr-Improve-handling-of-memory-unplug-with-old-gue.patch deleted file mode 100644 index 94bad1d..0000000 --- a/kvm-spapr-Improve-handling-of-memory-unplug-with-old-gue.patch +++ /dev/null @@ -1,168 +0,0 @@ -From cd719765bd751142c4040ee7daf615b859fb3e9d Mon Sep 17 00:00:00 2001 -From: Greg Kurz -Date: Tue, 19 Jan 2021 15:20:44 -0500 -Subject: [PATCH 2/5] spapr: Improve handling of memory unplug with old guests - -RH-Author: Greg Kurz -Message-id: <20210119152044.1019191-3-gkurz@redhat.com> -Patchwork-id: 100691 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 2/2] spapr: Improve handling of memory unplug with old guests -Bugzilla: 1914069 -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Laurent Vivier -RH-Acked-by: David Gibson - -From: Greg Kurz - -Since commit 1e8b5b1aa16b ("spapr: Allow memory unplug to always succeed") -trying to unplug memory from a guest that doesn't support it (eg. rhel6) -no longer generates an error like it used to. Instead, it leaves the -memory around : only a subsequent reboot or manual use of drmgr within -the guest can complete the hot-unplug sequence. A flag was added to -SpaprMachineClass so that this new behavior only applies to the default -machine type. - -We can do better. CAS processes all pending hot-unplug requests. This -means that we don't really care about what the guest supports if -the hot-unplug request happens before CAS. - -All guests that we care for, even old ones, set enough bits in OV5 -that lead to a non-empty bitmap in spapr->ov5_cas. Use that as a -heuristic to decide if CAS has already occured or not. - -Always accept unplug requests that happen before CAS since CAS will -process them. Restore the previous behavior of rejecting them after -CAS when we know that the guest doesn't support memory hot-unplug. - -This behavior is suitable for all machine types : this allows to -drop the pre_6_0_memory_unplug flag. - -Fixes: 1e8b5b1aa16b ("spapr: Allow memory unplug to always succeed") -Signed-off-by: Greg Kurz -Message-Id: <161012708715.801107.11418801796987916516.stgit@bahia.lan> -Reviewed-by: Daniel Henrique Barboza -Signed-off-by: David Gibson -(cherry picked from commit 73598c75df0585e039825e642adede21912dabc7) -Signed-off-by: Greg Kurz - -Conflicts: - hw/ppc/spapr.c - -Conflict around the removal of pre_6_0_memory_unplug, which was only -partially backported from upstream 1e8b5b1aa16b. - -Signed-off-by: Eduardo Lima (Etrunko) ---- - hw/ppc/spapr.c | 21 +++++++++++++-------- - hw/ppc/spapr_events.c | 3 +-- - hw/ppc/spapr_ovec.c | 7 +++++++ - include/hw/ppc/spapr.h | 2 +- - include/hw/ppc/spapr_ovec.h | 1 + - 5 files changed, 23 insertions(+), 11 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 65a647134a..a67df8cb26 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -4056,6 +4056,18 @@ static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev, - } - } - -+bool spapr_memory_hot_unplug_supported(SpaprMachineState *spapr) -+{ -+ return spapr_ovec_test(spapr->ov5_cas, OV5_HP_EVT) || -+ /* -+ * CAS will process all pending unplug requests. -+ * -+ * HACK: a guest could theoretically have cleared all bits in OV5, -+ * but none of the guests we care for do. -+ */ -+ spapr_ovec_empty(spapr->ov5_cas); -+} -+ - static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) - { -@@ -4064,16 +4076,9 @@ static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev, - SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc); - - if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { -- if (!smc->pre_6_0_memory_unplug || -- spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) { -+ if (spapr_memory_hot_unplug_supported(sms)) { - spapr_memory_unplug_request(hotplug_dev, dev, errp); - } else { -- /* NOTE: this means there is a window after guest reset, prior to -- * CAS negotiation, where unplug requests will fail due to the -- * capability not being detected yet. This is a bit different than -- * the case with PCI unplug, where the events will be queued and -- * eventually handled by the guest after boot -- */ - error_setg(errp, "Memory hot unplug not supported for this guest"); - } - } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { -diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c -index c30123177b..80b918ff5f 100644 ---- a/hw/ppc/spapr_events.c -+++ b/hw/ppc/spapr_events.c -@@ -659,8 +659,7 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action, - /* we should not be using count_indexed value unless the guest - * supports dedicated hotplug event source - */ -- g_assert(!SPAPR_MACHINE_GET_CLASS(spapr)->pre_6_0_memory_unplug || -- spapr_ovec_test(spapr->ov5_cas, OV5_HP_EVT)); -+ g_assert(spapr_memory_hot_unplug_supported(spapr)); - hp->drc_id.count_indexed.count = - cpu_to_be32(drc_id->count_indexed.count); - hp->drc_id.count_indexed.index = -diff --git a/hw/ppc/spapr_ovec.c b/hw/ppc/spapr_ovec.c -index dd003f1763..b2567caa5c 100644 ---- a/hw/ppc/spapr_ovec.c -+++ b/hw/ppc/spapr_ovec.c -@@ -125,6 +125,13 @@ bool spapr_ovec_test(SpaprOptionVector *ov, long bitnr) - return test_bit(bitnr, ov->bitmap) ? true : false; - } - -+bool spapr_ovec_empty(SpaprOptionVector *ov) -+{ -+ g_assert(ov); -+ -+ return bitmap_empty(ov->bitmap, OV_MAXBITS); -+} -+ - static void guest_byte_to_bitmap(uint8_t entry, unsigned long *bitmap, - long bitmap_offset) - { -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index 4941fe9b4f..5952942362 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -142,7 +142,6 @@ struct SpaprMachineClass { - hwaddr rma_limit; /* clamp the RMA to this size */ - bool pre_5_1_assoc_refpoints; - bool pre_5_2_numa_associativity; -- bool pre_6_0_memory_unplug; - - bool has_power9_support; - void (*phb_placement)(SpaprMachineState *spapr, uint32_t index, -@@ -954,4 +953,5 @@ bool spapr_check_pagesize(SpaprMachineState *spapr, hwaddr pagesize, - - void spapr_set_all_lpcrs(target_ulong value, target_ulong mask); - hwaddr spapr_get_rtas_addr(void); -+bool spapr_memory_hot_unplug_supported(SpaprMachineState *spapr); - #endif /* HW_SPAPR_H */ -diff --git a/include/hw/ppc/spapr_ovec.h b/include/hw/ppc/spapr_ovec.h -index d4dee9e06a..48b716a060 100644 ---- a/include/hw/ppc/spapr_ovec.h -+++ b/include/hw/ppc/spapr_ovec.h -@@ -71,6 +71,7 @@ void spapr_ovec_cleanup(SpaprOptionVector *ov); - void spapr_ovec_set(SpaprOptionVector *ov, long bitnr); - void spapr_ovec_clear(SpaprOptionVector *ov, long bitnr); - bool spapr_ovec_test(SpaprOptionVector *ov, long bitnr); -+bool spapr_ovec_empty(SpaprOptionVector *ov); - SpaprOptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector); - int spapr_dt_ovec(void *fdt, int fdt_offset, - SpaprOptionVector *ov, const char *name); --- -2.18.4 - diff --git a/kvm-storage-daemon-Call-bdrv_close_all-on-exit.patch b/kvm-storage-daemon-Call-bdrv_close_all-on-exit.patch deleted file mode 100644 index 7b0472c..0000000 --- a/kvm-storage-daemon-Call-bdrv_close_all-on-exit.patch +++ /dev/null @@ -1,48 +0,0 @@ -From b1883ddf10c2ec31ac72866494687d8897535a82 Mon Sep 17 00:00:00 2001 -From: Sergio Lopez Pascual -Date: Thu, 11 Feb 2021 14:42:07 -0300 -Subject: [PATCH 5/6] storage-daemon: Call bdrv_close_all() on exit - -RH-Author: Sergio Lopez Pascual -Message-id: <20210211144208.58930-5-slp@redhat.com> -Patchwork-id: 101048 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 4/5] storage-daemon: Call bdrv_close_all() on exit -Bugzilla: 1918966 1918968 -RH-Acked-by: Max Reitz -RH-Acked-by: Kevin Wolf -RH-Acked-by: Eric Blake - -From: Max Reitz - -Otherwise, exports and block devices are not properly shut down and -closed, unless the users explicitly issues blockdev-del and -block-export-del commands for each of them. - -Signed-off-by: Max Reitz -Reviewed-by: Kevin Wolf -Message-Id: <20201027190600.192171-17-mreitz@redhat.com> -Signed-off-by: Kevin Wolf -(cherry picked from commit b55a3c8860b763b62b2cc2f4a6f55379977bbde5) -Signed-off-by: Sergio Lopez -Signed-off-by: Eduardo Lima (Etrunko) ---- - storage-daemon/qemu-storage-daemon.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c -index 7c914b0dc1..e0c87edbdd 100644 ---- a/storage-daemon/qemu-storage-daemon.c -+++ b/storage-daemon/qemu-storage-daemon.c -@@ -314,6 +314,9 @@ int main(int argc, char *argv[]) - main_loop_wait(false); - } - -+ bdrv_drain_all_begin(); -+ bdrv_close_all(); -+ - monitor_cleanup(); - qemu_chr_cleanup(); - user_creatable_cleanup(); --- -2.27.0 - diff --git a/kvm-tracetool-also-strip-l-and-ll-from-systemtap-format-.patch b/kvm-tracetool-also-strip-l-and-ll-from-systemtap-format-.patch deleted file mode 100644 index 7d519a1..0000000 --- a/kvm-tracetool-also-strip-l-and-ll-from-systemtap-format-.patch +++ /dev/null @@ -1,69 +0,0 @@ -From b51851d9684443028c2568e70bb203481ecd533a Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Tue, 2 Feb 2021 14:03:34 -0500 -Subject: [PATCH 2/7] tracetool: also strip %l and %ll from systemtap format - strings -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Laurent Vivier -Message-id: <20210202140334.1798082-2-lvivier@redhat.com> -Patchwork-id: 100948 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/1] tracetool: also strip %l and %ll from systemtap format strings -Bugzilla: 1907264 -RH-Acked-by: Jon Maloy -RH-Acked-by: Philippe Mathieu-Daudé -RH-Acked-by: Daniel P. Berrange - -From: Daniel P. Berrangé - -All variables are 64-bit and so %l / %ll are not required, and the -latter is actually invalid: - - $ sudo stap -e 'probe begin{printf ("BEGIN")}' -I . - parse error: invalid or missing conversion specifier - saw: operator ',' at ./qemu-system-x86_64-log.stp:15118:101 - source: printf("%d@%d vhost_vdpa_set_log_base dev: %p base: 0x%x size: %llu -refcnt: %d fd: %d log: %p\n", pid(), gettimeofday_ns(), dev, base, size, refcnt, fd, log) - - ^ - -Signed-off-by: Daniel P. Berrangé -Reviewed-by: Laurent Vivier -Reviewed-by: Philippe Mathieu-Daudé -Tested-by: Laurent Vivier -Message-id: 20210106130239.1004729-1-berrange@redhat.com - -[Fixed "simiarly" typo found by Laurent Vivier ---Stefan] - -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 09612de7e9adbe9666a8fa4cc60bab0a29a68ed1) -Signed-off-by: Laurent Vivier -Signed-off-by: Eduardo Lima (Etrunko) ---- - scripts/tracetool/format/log_stap.py | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/scripts/tracetool/format/log_stap.py b/scripts/tracetool/format/log_stap.py -index b486beb672..2d910ced82 100644 ---- a/scripts/tracetool/format/log_stap.py -+++ b/scripts/tracetool/format/log_stap.py -@@ -77,7 +77,12 @@ def c_fmt_to_stap(fmt): - elif state == STATE_LITERAL: - bits.append(literal) - -- fmt = re.sub("%(\d*)z(x|u|d)", "%\\1\\2", "".join(bits)) -+ # All variables in systemtap are 64-bit in size -+ # The "%l" integer size qualifier is thus redundant -+ # and "%ll" is not valid at all. Similarly the size_t -+ # based "%z" size qualifier is not valid. We just -+ # strip all size qualifiers for sanity. -+ fmt = re.sub("%(\d*)(l+|z)(x|u|d)", "%\\1\\3", "".join(bits)) - return fmt - - def generate(events, backend, group): --- -2.18.4 - diff --git a/kvm-vhost-Check-for-valid-vdev-in-vhost_backend_handle_i.patch b/kvm-vhost-Check-for-valid-vdev-in-vhost_backend_handle_i.patch deleted file mode 100644 index ddd67b7..0000000 --- a/kvm-vhost-Check-for-valid-vdev-in-vhost_backend_handle_i.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 9142072649d593acbd118e71f5d257bd9996ab36 Mon Sep 17 00:00:00 2001 -From: eperezma -Date: Fri, 19 Feb 2021 08:49:50 -0300 -Subject: [PATCH 12/54] vhost: Check for valid vdev in - vhost_backend_handle_iotlb_msg -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: eperezma -Message-id: <20210219084950.2159701-1-eperezma@redhat.com> -Patchwork-id: 101110 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH] vhost: Check for valid vdev in vhost_backend_handle_iotlb_msg -Bugzilla: 1880299 -RH-Acked-by: Peter Xu -RH-Acked-by: Stefano Garzarella -RH-Acked-by: Xiao Wang - -BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1880299 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged -BREW: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=35031170 - -Not checking this can lead to invalid dev->vdev member access in -vhost_device_iotlb_miss if backend issue an iotlb message in a bad -timing, either maliciously or by a bug. - -Reproduced rebooting a guest with testpmd in txonly forward mode. - #0 0x0000559ffff94394 in vhost_device_iotlb_miss ( - dev=dev@entry=0x55a0012f6680, iova=10245279744, write=1) - at ../hw/virtio/vhost.c:1013 - #1 0x0000559ffff9ac31 in vhost_backend_handle_iotlb_msg ( - imsg=0x7ffddcfd32c0, dev=0x55a0012f6680) - at ../hw/virtio/vhost-backend.c:411 - #2 vhost_backend_handle_iotlb_msg (dev=dev@entry=0x55a0012f6680, - imsg=imsg@entry=0x7ffddcfd32c0) - at ../hw/virtio/vhost-backend.c:404 - #3 0x0000559fffeded7b in slave_read (opaque=0x55a0012f6680) - at ../hw/virtio/vhost-user.c:1464 - #4 0x000055a0000c541b in aio_dispatch_handler ( - ctx=ctx@entry=0x55a0010a2120, node=0x55a0012d9e00) - at ../util/aio-posix.c:329 - -Fixes: 020e571b8b ("vhost: rework IOTLB messaging") -Signed-off-by: Eugenio Pérez -Message-Id: <20210129090728.831208-1-eperezma@redhat.com> -Acked-by: Jason Wang -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 4d1ccc17f40f73313e13c84914f70ec3d40ac738) -Signed-off-by: Eugenio Pérez -Signed-off-by: Eduardo Lima (Etrunko) ---- - hw/virtio/vhost-backend.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c -index 222bbcc62d..31b33bde37 100644 ---- a/hw/virtio/vhost-backend.c -+++ b/hw/virtio/vhost-backend.c -@@ -406,6 +406,11 @@ int vhost_backend_handle_iotlb_msg(struct vhost_dev *dev, - { - int ret = 0; - -+ if (unlikely(!dev->vdev)) { -+ error_report("Unexpected IOTLB message when virtio device is stopped"); -+ return -EINVAL; -+ } -+ - switch (imsg->type) { - case VHOST_IOTLB_MISS: - ret = vhost_device_iotlb_miss(dev, imsg->iova, --- -2.27.0 - diff --git a/kvm-vhost-Unbreak-SMMU-and-virtio-iommu-on-dev-iotlb-sup.patch b/kvm-vhost-Unbreak-SMMU-and-virtio-iommu-on-dev-iotlb-sup.patch deleted file mode 100644 index 2926e5b..0000000 --- a/kvm-vhost-Unbreak-SMMU-and-virtio-iommu-on-dev-iotlb-sup.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 26c3b9b2a5e904f2799ac097c91588cb2248a6e0 Mon Sep 17 00:00:00 2001 -From: Auger Eric -Date: Fri, 5 Feb 2021 18:58:52 -0500 -Subject: [PATCH 6/7] vhost: Unbreak SMMU and virtio-iommu on dev-iotlb support - -RH-Author: Auger Eric -Message-id: <20210205185852.12830-1-eric.auger@redhat.com> -Patchwork-id: 100996 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH] vhost: Unbreak SMMU and virtio-iommu on dev-iotlb support -Bugzilla: 1925028 -RH-Acked-by: Gavin Shan -RH-Acked-by: Andrew Jones -RH-Acked-by: Peter Xu - -From: Peter Xu - -BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1925028 -BRANCH: rhel-av-8.4.0 -UPSTREAM: merged -BREW: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=34788078 - -Previous work on dev-iotlb message broke vhost on either SMMU or virtio-iommu -since dev-iotlb (or PCIe ATS) is not yet supported for those archs. - -An initial idea is that we can let IOMMU to export this information to vhost so -that vhost would know whether the vIOMMU would support dev-iotlb, then vhost -can conditionally register to dev-iotlb or the old iotlb way. We can work -based on some previous patch to introduce PCIIOMMUOps as Yi Liu proposed [1]. - -However it's not as easy as I thought since vhost_iommu_region_add() does not -have a PCIDevice context at all since it's completely a backend. It seems -non-trivial to pass over a PCI device to the backend during init. E.g. when -the IOMMU notifier registered hdev->vdev is still NULL. - -To make the fix smaller and easier, this patch goes the other way to leverage -the flag_changed() hook of vIOMMUs so that SMMU and virtio-iommu can trap the -dev-iotlb registration and fail it. Then vhost could try the fallback solution -as using UNMAP invalidation for it's translations. - -[1] https://lore.kernel.org/qemu-devel/1599735398-6829-4-git-send-email-yi.l.liu@intel.com/ - -Reported-by: Eric Auger -Fixes: b68ba1ca57677acf870d5ab10579e6105c1f5338 -Reviewed-by: Eric Auger -Tested-by: Eric Auger -Signed-off-by: Peter Xu -Message-Id: <20210204191228.187550-1-peterx@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 958ec334bca3fa9862289e4cfe31bf1019e55816) -Signed-off-by: Eric Auger -Signed-off-by: Eduardo Lima (Etrunko) ---- - hw/arm/smmuv3.c | 5 +++++ - hw/virtio/vhost.c | 13 +++++++++++-- - hw/virtio/virtio-iommu.c | 5 +++++ - 3 files changed, 21 insertions(+), 2 deletions(-) - -diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c -index 98b99d4fe8..bd1f97000d 100644 ---- a/hw/arm/smmuv3.c -+++ b/hw/arm/smmuv3.c -@@ -1497,6 +1497,11 @@ static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu, - SMMUv3State *s3 = sdev->smmu; - SMMUState *s = &(s3->smmu_state); - -+ if (new & IOMMU_NOTIFIER_DEVIOTLB_UNMAP) { -+ error_setg(errp, "SMMUv3 does not support dev-iotlb yet"); -+ return -EINVAL; -+ } -+ - if (new & IOMMU_NOTIFIER_MAP) { - error_setg(errp, - "device %02x.%02x.%x requires iommu MAP notifier which is " -diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c -index 28c7d78172..6e17d631f7 100644 ---- a/hw/virtio/vhost.c -+++ b/hw/virtio/vhost.c -@@ -704,6 +704,7 @@ static void vhost_iommu_region_add(MemoryListener *listener, - Int128 end; - int iommu_idx; - IOMMUMemoryRegion *iommu_mr; -+ int ret; - - if (!memory_region_is_iommu(section->mr)) { - return; -@@ -726,8 +727,16 @@ static void vhost_iommu_region_add(MemoryListener *listener, - iommu->iommu_offset = section->offset_within_address_space - - section->offset_within_region; - iommu->hdev = dev; -- memory_region_register_iommu_notifier(section->mr, &iommu->n, -- &error_fatal); -+ ret = memory_region_register_iommu_notifier(section->mr, &iommu->n, NULL); -+ if (ret) { -+ /* -+ * Some vIOMMUs do not support dev-iotlb yet. If so, try to use the -+ * UNMAP legacy message -+ */ -+ iommu->n.notifier_flags = IOMMU_NOTIFIER_UNMAP; -+ memory_region_register_iommu_notifier(section->mr, &iommu->n, -+ &error_fatal); -+ } - QLIST_INSERT_HEAD(&dev->iommu_list, iommu, iommu_next); - /* TODO: can replay help performance here? */ - } -diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c -index cea8811295..65184f6e43 100644 ---- a/hw/virtio/virtio-iommu.c -+++ b/hw/virtio/virtio-iommu.c -@@ -893,6 +893,11 @@ static int virtio_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu_mr, - IOMMUNotifierFlag new, - Error **errp) - { -+ if (new & IOMMU_NOTIFIER_DEVIOTLB_UNMAP) { -+ error_setg(errp, "Virtio-iommu does not support dev-iotlb yet"); -+ return -EINVAL; -+ } -+ - if (old == IOMMU_NOTIFIER_NONE) { - trace_virtio_iommu_notify_flag_add(iommu_mr->parent_obj.name); - } else if (new == IOMMU_NOTIFIER_NONE) { --- -2.18.4 - diff --git a/kvm-vhost-user-blk-fix-blkcfg-num_queues-endianness.patch b/kvm-vhost-user-blk-fix-blkcfg-num_queues-endianness.patch deleted file mode 100644 index efb0b34..0000000 --- a/kvm-vhost-user-blk-fix-blkcfg-num_queues-endianness.patch +++ /dev/null @@ -1,68 +0,0 @@ -From f6ad6b772dce72042afbe8779cd9c52d5e352418 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Mon, 15 Mar 2021 18:16:24 -0400 -Subject: [PATCH 08/15] vhost-user-blk: fix blkcfg->num_queues endianness -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Stefan Hajnoczi -Message-id: <20210315181629.212884-2-stefanha@redhat.com> -Patchwork-id: 101338 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/6] vhost-user-blk: fix blkcfg->num_queues endianness -Bugzilla: 1937004 -RH-Acked-by: Danilo de Paula -RH-Acked-by: Philippe Mathieu-Daudé -RH-Acked-by: Kevin Wolf -RH-Acked-by: Max Reitz - -Treat the num_queues field as virtio-endian. On big-endian hosts the -vhost-user-blk num_queues field was in the wrong endianness. - -Move the blkcfg.num_queues store operation from realize to -vhost_user_blk_update_config() so feature negotiation has finished and -we know the endianness of the device. VIRTIO 1.0 devices are -little-endian, but in case someone wants to use legacy VIRTIO we support -all endianness cases. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Raphael Norwitz -Reviewed-by: Michael S. Tsirkin -Message-Id: <20210223144653.811468-2-stefanha@redhat.com> -Signed-off-by: Kevin Wolf -(cherry picked from commit 535255b43898d2e96744057eb86f8497d4d7a461) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Danilo C. L. de Paula ---- - hw/block/vhost-user-blk.c | 7 +++---- - 1 file changed, 3 insertions(+), 4 deletions(-) - -diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c -index 2dd3d93ca0..d9d9dc8a89 100644 ---- a/hw/block/vhost-user-blk.c -+++ b/hw/block/vhost-user-blk.c -@@ -53,6 +53,9 @@ static void vhost_user_blk_update_config(VirtIODevice *vdev, uint8_t *config) - { - VHostUserBlk *s = VHOST_USER_BLK(vdev); - -+ /* Our num_queues overrides the device backend */ -+ virtio_stw_p(vdev, &s->blkcfg.num_queues, s->num_queues); -+ - memcpy(config, &s->blkcfg, sizeof(struct virtio_blk_config)); - } - -@@ -490,10 +493,6 @@ reconnect: - goto reconnect; - } - -- if (s->blkcfg.num_queues != s->num_queues) { -- s->blkcfg.num_queues = s->num_queues; -- } -- - return; - - virtio_err: --- -2.27.0 - diff --git a/kvm-virtio-Add-corresponding-memory_listener_unregister-.patch b/kvm-virtio-Add-corresponding-memory_listener_unregister-.patch deleted file mode 100644 index 46c96b0..0000000 --- a/kvm-virtio-Add-corresponding-memory_listener_unregister-.patch +++ /dev/null @@ -1,234 +0,0 @@ -From ac9e40a75eba0019fb9930835804e8daceead981 Mon Sep 17 00:00:00 2001 -From: eperezma -Date: Tue, 9 Feb 2021 10:38:16 -0300 -Subject: [PATCH 1/6] virtio: Add corresponding memory_listener_unregister to - unrealize -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: eperezma -Message-id: <20210209103816.1636200-2-eperezma@redhat.com> -Patchwork-id: 101009 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/1] virtio: Add corresponding memory_listener_unregister to unrealize -Bugzilla: 1903521 -RH-Acked-by: Peter Xu -RH-Acked-by: Philippe Mathieu-Daudé -RH-Acked-by: Stefano Garzarella - -Address space is destroyed without proper removal of its listeners with -current code. They are expected to be removed in -virtio_device_instance_finalize [1], but qemu calls it through -object_deinit, after address_space_destroy call through -device_set_realized [2]. - -Move it to virtio_device_unrealize, called before device_set_realized -[3] and making it symmetric with memory_listener_register in -virtio_device_realize. - -v2: Delete no-op call of virtio_device_instance_finalize. - Add backtraces. - -[1] - - #0 virtio_device_instance_finalize (obj=0x555557de5120) - at /home/qemu/include/hw/virtio/virtio.h:71 - #1 0x0000555555b703c9 in object_deinit (type=0x555556639860, - obj=) at ../qom/object.c:671 - #2 object_finalize (data=0x555557de5120) at ../qom/object.c:685 - #3 object_unref (objptr=0x555557de5120) at ../qom/object.c:1184 - #4 0x0000555555b4de9d in bus_free_bus_child (kid=0x555557df0660) - at ../hw/core/qdev.c:55 - #5 0x0000555555c65003 in call_rcu_thread (opaque=opaque@entry=0x0) - at ../util/rcu.c:281 - -Queued by: - - #0 bus_remove_child (bus=0x555557de5098, - child=child@entry=0x555557de5120) at ../hw/core/qdev.c:60 - #1 0x0000555555b4ee31 in device_unparent (obj=) - at ../hw/core/qdev.c:984 - #2 0x0000555555b70465 in object_finalize_child_property ( - obj=, name=, opaque=0x555557de5120) - at ../qom/object.c:1725 - #3 0x0000555555b6fa17 in object_property_del_child ( - child=0x555557de5120, obj=0x555557ddcf90) at ../qom/object.c:645 - #4 object_unparent (obj=0x555557de5120) at ../qom/object.c:664 - #5 0x0000555555b4c071 in bus_unparent (obj=) - at ../hw/core/bus.c:147 - #6 0x0000555555b70465 in object_finalize_child_property ( - obj=, name=, opaque=0x555557de5098) - at ../qom/object.c:1725 - #7 0x0000555555b6fa17 in object_property_del_child ( - child=0x555557de5098, obj=0x555557ddcf90) at ../qom/object.c:645 - #8 object_unparent (obj=0x555557de5098) at ../qom/object.c:664 - #9 0x0000555555b4ee19 in device_unparent (obj=) - at ../hw/core/qdev.c:981 - #10 0x0000555555b70465 in object_finalize_child_property ( - obj=, name=, opaque=0x555557ddcf90) - at ../qom/object.c:1725 - #11 0x0000555555b6fa17 in object_property_del_child ( - child=0x555557ddcf90, obj=0x55555685da10) at ../qom/object.c:645 - #12 object_unparent (obj=0x555557ddcf90) at ../qom/object.c:664 - #13 0x00005555558dc331 in pci_for_each_device_under_bus ( - opaque=, fn=, bus=) - at ../hw/pci/pci.c:1654 - -[2] - -Optimizer omits pci_qdev_unrealize, called by device_set_realized, and -do_pci_unregister_device, called by pci_qdev_unrealize and caller of -address_space_destroy. - - #0 address_space_destroy (as=0x555557ddd1b8) - at ../softmmu/memory.c:2840 - #1 0x0000555555b4fc53 in device_set_realized (obj=0x555557ddcf90, - value=, errp=0x7fffeea8f1e0) - at ../hw/core/qdev.c:850 - #2 0x0000555555b6eaa6 in property_set_bool (obj=0x555557ddcf90, - v=, name=, opaque=0x555556650ba0, - errp=0x7fffeea8f1e0) at ../qom/object.c:2255 - #3 0x0000555555b70e07 in object_property_set ( - obj=obj@entry=0x555557ddcf90, - name=name@entry=0x555555db99df "realized", - v=v@entry=0x7fffe46b7500, - errp=errp@entry=0x5555565bbf38 ) - at ../qom/object.c:1400 - #4 0x0000555555b73c5f in object_property_set_qobject ( - obj=obj@entry=0x555557ddcf90, - name=name@entry=0x555555db99df "realized", - value=value@entry=0x7fffe44f6180, - errp=errp@entry=0x5555565bbf38 ) - at ../qom/qom-qobject.c:28 - #5 0x0000555555b71044 in object_property_set_bool ( - obj=0x555557ddcf90, name=0x555555db99df "realized", - value=, errp=0x5555565bbf38 ) - at ../qom/object.c:1470 - #6 0x0000555555921cb7 in pcie_unplug_device (bus=, - dev=0x555557ddcf90, - opaque=) at /home/qemu/include/hw/qdev-core.h:17 - #7 0x00005555558dc331 in pci_for_each_device_under_bus ( - opaque=, fn=, - bus=) at ../hw/pci/pci.c:1654 - -[3] - - #0 virtio_device_unrealize (dev=0x555557de5120) - at ../hw/virtio/virtio.c:3680 - #1 0x0000555555b4fc63 in device_set_realized (obj=0x555557de5120, - value=, errp=0x7fffee28df90) - at ../hw/core/qdev.c:850 - #2 0x0000555555b6eab6 in property_set_bool (obj=0x555557de5120, - v=, name=, opaque=0x555556650ba0, - errp=0x7fffee28df90) at ../qom/object.c:2255 - #3 0x0000555555b70e17 in object_property_set ( - obj=obj@entry=0x555557de5120, - name=name@entry=0x555555db99ff "realized", - v=v@entry=0x7ffdd8035040, - errp=errp@entry=0x5555565bbf38 ) - at ../qom/object.c:1400 - #4 0x0000555555b73c6f in object_property_set_qobject ( - obj=obj@entry=0x555557de5120, - name=name@entry=0x555555db99ff "realized", - value=value@entry=0x7ffdd8035020, - errp=errp@entry=0x5555565bbf38 ) - at ../qom/qom-qobject.c:28 - #5 0x0000555555b71054 in object_property_set_bool ( - obj=0x555557de5120, name=name@entry=0x555555db99ff "realized", - value=value@entry=false, errp=0x5555565bbf38 ) - at ../qom/object.c:1470 - #6 0x0000555555b4edc5 in qdev_unrealize (dev=) - at ../hw/core/qdev.c:403 - #7 0x0000555555b4c2a9 in bus_set_realized (obj=, - value=, errp=) - at ../hw/core/bus.c:204 - #8 0x0000555555b6eab6 in property_set_bool (obj=0x555557de5098, - v=, name=, opaque=0x555557df04c0, - errp=0x7fffee28e0a0) at ../qom/object.c:2255 - #9 0x0000555555b70e17 in object_property_set ( - obj=obj@entry=0x555557de5098, - name=name@entry=0x555555db99ff "realized", - v=v@entry=0x7ffdd8034f50, - errp=errp@entry=0x5555565bbf38 ) - at ../qom/object.c:1400 - #10 0x0000555555b73c6f in object_property_set_qobject ( - obj=obj@entry=0x555557de5098, - name=name@entry=0x555555db99ff "realized", - value=value@entry=0x7ffdd8020630, - errp=errp@entry=0x5555565bbf38 ) - at ../qom/qom-qobject.c:28 - #11 0x0000555555b71054 in object_property_set_bool ( - obj=obj@entry=0x555557de5098, - name=name@entry=0x555555db99ff "realized", - value=value@entry=false, errp=0x5555565bbf38 ) - at ../qom/object.c:1470 - #12 0x0000555555b4c725 in qbus_unrealize ( - bus=bus@entry=0x555557de5098) at ../hw/core/bus.c:178 - #13 0x0000555555b4fc00 in device_set_realized (obj=0x555557ddcf90, - value=, errp=0x7fffee28e1e0) - at ../hw/core/qdev.c:844 - #14 0x0000555555b6eab6 in property_set_bool (obj=0x555557ddcf90, - v=, name=, opaque=0x555556650ba0, - errp=0x7fffee28e1e0) at ../qom/object.c:2255 - #15 0x0000555555b70e17 in object_property_set ( - obj=obj@entry=0x555557ddcf90, - name=name@entry=0x555555db99ff "realized", - v=v@entry=0x7ffdd8020560, - errp=errp@entry=0x5555565bbf38 ) - at ../qom/object.c:1400 - #16 0x0000555555b73c6f in object_property_set_qobject ( - obj=obj@entry=0x555557ddcf90, - name=name@entry=0x555555db99ff "realized", - value=value@entry=0x7ffdd8020540, - errp=errp@entry=0x5555565bbf38 ) - at ../qom/qom-qobject.c:28 - #17 0x0000555555b71054 in object_property_set_bool ( - obj=0x555557ddcf90, name=0x555555db99ff "realized", - value=, errp=0x5555565bbf38 ) - at ../qom/object.c:1470 - #18 0x0000555555921cb7 in pcie_unplug_device (bus=, - dev=0x555557ddcf90, opaque=) - at /home/qemu/include/hw/qdev-core.h:17 - #19 0x00005555558dc331 in pci_for_each_device_under_bus ( - opaque=, fn=, bus=) - at ../hw/pci/pci.c:1654 - -Fixes: c611c76417f ("virtio: add MemoryListener to cache ring translations") -Buglink: https://bugs.launchpad.net/qemu/+bug/1912846 -Signed-off-by: Eugenio Pérez -Message-Id: <20210125192505.390554-1-eperezma@redhat.com> -Reviewed-by: Peter Xu -Acked-by: Jason Wang -Reviewed-by: Stefano Garzarella -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit f6ab64c05f8a6229bf6569d3791c23abb9f6eee4) -Signed-off-by: Eugenio Pérez -Signed-off-by: Eduardo Lima (Etrunko) ---- - hw/virtio/virtio.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c -index ceb58fda6c..9312e7191b 100644 ---- a/hw/virtio/virtio.c -+++ b/hw/virtio/virtio.c -@@ -3677,6 +3677,7 @@ static void virtio_device_unrealize(DeviceState *dev) - VirtIODevice *vdev = VIRTIO_DEVICE(dev); - VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(dev); - -+ memory_listener_unregister(&vdev->listener); - virtio_bus_device_unplugged(vdev); - - if (vdc->unrealize != NULL) { -@@ -3707,7 +3708,6 @@ static void virtio_device_instance_finalize(Object *obj) - { - VirtIODevice *vdev = VIRTIO_DEVICE(obj); - -- memory_listener_unregister(&vdev->listener); - virtio_device_free_virtqueues(vdev); - - g_free(vdev->config); --- -2.27.0 - diff --git a/kvm-virtio-move-use-disabled-flag-property-to-hw_compat_.patch b/kvm-virtio-move-use-disabled-flag-property-to-hw_compat_.patch deleted file mode 100644 index 1869297..0000000 --- a/kvm-virtio-move-use-disabled-flag-property-to-hw_compat_.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 4a1b30af56f99b9fe7ecdd47aa9691fed5d3a0c3 Mon Sep 17 00:00:00 2001 -From: Stefano Garzarella -Date: Tue, 9 Feb 2021 17:15:33 -0300 -Subject: [PATCH 04/54] virtio: move 'use-disabled-flag' property to - hw_compat_4_2 - -RH-Author: Stefano Garzarella -Message-id: <20210209171533.133268-2-sgarzare@redhat.com> -Patchwork-id: 101012 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/1] virtio: move 'use-disabled-flag' property to hw_compat_4_2 -Bugzilla: 1907255 -RH-Acked-by: Sergio Lopez Pascual -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Dr. David Alan Gilbert - -Commit 9d7bd0826f introduced a new 'use-disabled-flag' property -set to true by default. -To allow the migration, we set this property to false in the hw_compat, -but in the wrong place (hw_compat_4_1). - -Since commit 9d7bd0826f was released with QEMU 5.0, we move -'use-disabled-flag' property to hw_compat_4_2, so 4.2 machine types -will have the pre-patch behavior and the migration can work. - -The issue was discovered with vhost-vsock device and 4.2 machine -type without running any kernel in the VM: - $ qemu-4.2 -M pc-q35-4.2,accel=kvm \ - -device vhost-vsock-pci,guest-cid=4 \ - -monitor stdio -incoming tcp:0:3333 - - $ qemu-5.2 -M pc-q35-4.2,accel=kvm \ - -device vhost-vsock-pci,guest-cid=3 \ - -monitor stdio - (qemu) migrate -d tcp:0:3333 - - # qemu-4.2 output - qemu-system-x86_64: Failed to load virtio-vhost_vsock:virtio - qemu-system-x86_64: error while loading state for instance 0x0 of device '0000:00:03.0/virtio-vhost_vsock' - qemu-system-x86_64: load of migration failed: No such file or directory - -Reported-by: Jing Zhao -Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1907255 -Fixes: 9d7bd0826f ("virtio-pci: disable vring processing when bus-mastering is disabled") -Cc: mdroth@linux.vnet.ibm.com -CC: qemu-stable@nongnu.org -Signed-off-by: Stefano Garzarella -Message-Id: <20210108171252.209502-1-sgarzare@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit c126b4c57e0164549de606ca35d1512762051083) -[sgarzare: add 'use-disabled-flag' property to hw_compat_rhel_8_2] -Signed-off-by: Stefano Garzarella -Signed-off-by: Eduardo Lima (Etrunko) ---- - hw/core/machine.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/hw/core/machine.c b/hw/core/machine.c -index 68495b9411..92398966a4 100644 ---- a/hw/core/machine.c -+++ b/hw/core/machine.c -@@ -77,6 +77,8 @@ GlobalProperty hw_compat_rhel_8_2[] = { - { "qxl-vga", "revision", "4" }, - /* hw_compat_rhel_8_2 from hw_compat_4_2 */ - { "fw_cfg", "acpi-mr-restore", "false" }, -+ /* hw_compat_rhel_8_2 from hw_compat_4_2 */ -+ { "virtio-device", "use-disabled-flag", "false" }, - /* hw_compat_rhel_8_2 from hw_compat_5_0 */ - { "pci-host-bridge", "x-config-reg-migration-enabled", "off" }, - /* hw_compat_rhel_8_2 from hw_compat_5_0 */ -@@ -298,12 +300,12 @@ GlobalProperty hw_compat_4_2[] = { - { "qxl", "revision", "4" }, - { "qxl-vga", "revision", "4" }, - { "fw_cfg", "acpi-mr-restore", "false" }, -+ { "virtio-device", "use-disabled-flag", "false" }, - }; - const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2); - - GlobalProperty hw_compat_4_1[] = { - { "virtio-pci", "x-pcie-flr-init", "off" }, -- { "virtio-device", "use-disabled-flag", "false" }, - }; - const size_t hw_compat_4_1_len = G_N_ELEMENTS(hw_compat_4_1); - --- -2.27.0 - diff --git a/kvm-virtio-net-add-missing-object_unref.patch b/kvm-virtio-net-add-missing-object_unref.patch deleted file mode 100644 index efa7b44..0000000 --- a/kvm-virtio-net-add-missing-object_unref.patch +++ /dev/null @@ -1,66 +0,0 @@ -From d66b778c2f888507dedc3e4111006215dd394b95 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 25 Feb 2021 23:14:47 -0500 -Subject: [PATCH 50/54] virtio-net: add missing object_unref() - -RH-Author: Laurent Vivier -Message-id: <20210225231447.2187738-28-lvivier@redhat.com> -Patchwork-id: 101266 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH v2 27/27] virtio-net: add missing object_unref() -Bugzilla: 1819991 -RH-Acked-by: Juan Quintela -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Jens Freimann -RH-Acked-by: Michael S. Tsirkin - -BZ: https://bugzilla.redhat.com/1819991 -BRANCH: rhel-av-8.4.0 -UPSTREAM: Merged - -failover_add_primary() calls qdev_device_add() and doesn't unref -the device. Because of that, when the device is unplugged a reference -is remaining and prevents the cleanup of the object. - -This prevents to be able to plugin back the failover primary device, -with errors like: - - (qemu) device_add vfio-pci,host=0000:41:00.0,id=hostdev0,bus=root.3,failover_pair_id=net0 - (qemu) device_del hostdev0 - -We can check with "info qtree" and "info pci" that the device has been removed, and then: - - (qemu) device_add vfio-pci,host=0000:41:00.0,id=hostdev1,bus=root.3,failover_pair_id=net0 - Error: vfio 0000:41:00.0: device is already attached - (qemu) device_add vfio-pci,host=0000:41:00.0,id=hostdev0,bus=root.3,failover_pair_id=net0 - qemu-kvm: Duplicate ID 'hostdev0' for device - -Fixes: 21e8709b29cd ("failover: Remove primary_dev member") -Cc: quintela@redhat.com -Signed-off-by: Laurent Vivier -Message-Id: <20210212135250.2738750-3-lvivier@redhat.com> -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -Reviewed-by: Jens Freimann -(cherry picked from commit 00e7b1299599384dfdda2a2a4570a0fb2d69eb6b) -Signed-off-by: Laurent Vivier -Signed-off-by: Danilo C. L. de Paula ---- - hw/net/virtio-net.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 044ac95f6f..7faaa829b6 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -869,6 +869,8 @@ static void failover_add_primary(VirtIONet *n, Error **errp) - dev = qdev_device_add(opts, &err); - if (err) { - qemu_opts_del(opts); -+ } else { -+ object_unref(OBJECT(dev)); - } - } else { - error_setg(errp, "Primary device not found"); --- -2.27.0 - diff --git a/kvm-virtiofs-drop-remapped-security.capability-xattr-as-.patch b/kvm-virtiofs-drop-remapped-security.capability-xattr-as-.patch deleted file mode 100644 index 72fe0a4..0000000 --- a/kvm-virtiofs-drop-remapped-security.capability-xattr-as-.patch +++ /dev/null @@ -1,224 +0,0 @@ -From 6a0564e81d5e329f955c4391809daf248f078481 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Thu, 4 Mar 2021 15:49:01 -0500 -Subject: [PATCH 4/4] virtiofs: drop remapped security.capability xattr as - needed - -RH-Author: Dr. David Alan Gilbert -Message-id: <20210304154901.47930-3-dgilbert@redhat.com> -Patchwork-id: 101305 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 2/2] virtiofs: drop remapped security.capability xattr as needed -Bugzilla: 1935071 -RH-Acked-by: Connor Kuehl -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Stefan Hajnoczi - -From: "Dr. David Alan Gilbert" - -On Linux, the 'security.capability' xattr holds a set of -capabilities that can change when an executable is run, giving -a limited form of privilege escalation to those programs that -the writer of the file deemed worthy. - -Any write causes the 'security.capability' xattr to be dropped, -stopping anyone from gaining privilege by modifying a blessed -file. - -Fuse relies on the daemon to do this dropping, and in turn the -daemon relies on the host kernel to drop the xattr for it. However, -with the addition of -o xattrmap, the xattr that the guest -stores its capabilities in is now not the same as the one that -the host kernel automatically clears. - -Where the mapping changes 'security.capability', explicitly clear -the remapped name to preserve the same behaviour. - -This bug is assigned CVE-2021-20263. - -Signed-off-by: Dr. David Alan Gilbert -Reviewed-by: Vivek Goyal -(cherry picked from commit e586edcb410543768ef009eaa22a2d9dd4a53846) -Signed-off-by: Dr. David Alan Gilbert - Downstream slight context difference due to missing d64907ac FUSE_HANDLE_KILLPRIV_V2 -Signed-off-by: Danilo C. L. de Paula ---- - docs/tools/virtiofsd.rst | 4 ++ - tools/virtiofsd/passthrough_ll.c | 77 +++++++++++++++++++++++++++++++- - 2 files changed, 80 insertions(+), 1 deletion(-) - -diff --git a/docs/tools/virtiofsd.rst b/docs/tools/virtiofsd.rst -index 5b3be8a6d6..6e0fc94005 100644 ---- a/docs/tools/virtiofsd.rst -+++ b/docs/tools/virtiofsd.rst -@@ -228,6 +228,10 @@ The 'map' type adds a number of separate rules to add **prepend** as a prefix - to the matched **key** (or all attributes if **key** is empty). - There may be at most one 'map' rule and it must be the last rule in the set. - -+Note: When the 'security.capability' xattr is remapped, the daemon has to do -+extra work to remove it during many operations, which the host kernel normally -+does itself. -+ - xattr-mapping Examples - ---------------------- - -diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c -index f06074d81f..9c33b0344b 100644 ---- a/tools/virtiofsd/passthrough_ll.c -+++ b/tools/virtiofsd/passthrough_ll.c -@@ -160,6 +160,7 @@ struct lo_data { - int posix_lock; - int xattr; - char *xattrmap; -+ char *xattr_security_capability; - char *source; - char *modcaps; - double timeout; -@@ -226,6 +227,8 @@ static __thread bool cap_loaded = 0; - - static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st, - uint64_t mnt_id); -+static int xattr_map_client(const struct lo_data *lo, const char *client_name, -+ char **out_name); - - static int is_dot_or_dotdot(const char *name) - { -@@ -365,6 +368,37 @@ out: - return ret; - } - -+/* -+ * The host kernel normally drops security.capability xattr's on -+ * any write, however if we're remapping xattr names we need to drop -+ * whatever the clients security.capability is actually stored as. -+ */ -+static int drop_security_capability(const struct lo_data *lo, int fd) -+{ -+ if (!lo->xattr_security_capability) { -+ /* We didn't remap the name, let the host kernel do it */ -+ return 0; -+ } -+ if (!fremovexattr(fd, lo->xattr_security_capability)) { -+ /* All good */ -+ return 0; -+ } -+ -+ switch (errno) { -+ case ENODATA: -+ /* Attribute didn't exist, that's fine */ -+ return 0; -+ -+ case ENOTSUP: -+ /* FS didn't support attribute anyway, also fine */ -+ return 0; -+ -+ default: -+ /* Hmm other error */ -+ return errno; -+ } -+} -+ - static void lo_map_init(struct lo_map *map) - { - map->elems = NULL; -@@ -718,6 +752,11 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, - uid_t uid = (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t)-1; - gid_t gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t)-1; - -+ saverr = drop_security_capability(lo, ifd); -+ if (saverr) { -+ goto out_err; -+ } -+ - res = fchownat(ifd, "", uid, gid, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); - if (res == -1) { - saverr = errno; -@@ -737,6 +776,14 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, - } - } - -+ saverr = drop_security_capability(lo, truncfd); -+ if (saverr) { -+ if (!fi) { -+ close(truncfd); -+ } -+ goto out_err; -+ } -+ - res = ftruncate(truncfd, attr->st_size); - saverr = res == -1 ? errno : 0; - if (!fi) { -@@ -1727,6 +1774,13 @@ static int lo_do_open(struct lo_data *lo, struct lo_inode *inode, - if (fd < 0) { - return -fd; - } -+ if (fi->flags & (O_TRUNC)) { -+ int err = drop_security_capability(lo, fd); -+ if (err) { -+ close(fd); -+ return err; -+ } -+ } - } - - pthread_mutex_lock(&lo->mutex); -@@ -2115,6 +2169,12 @@ static void lo_write_buf(fuse_req_t req, fuse_ino_t ino, - "lo_write_buf(ino=%" PRIu64 ", size=%zd, off=%lu)\n", ino, - out_buf.buf[0].size, (unsigned long)off); - -+ res = drop_security_capability(lo_data(req), out_buf.buf[0].fd); -+ if (res) { -+ fuse_reply_err(req, res); -+ return; -+ } -+ - /* - * If kill_priv is set, drop CAP_FSETID which should lead to kernel - * clearing setuid/setgid on file. -@@ -2354,6 +2414,7 @@ static void parse_xattrmap(struct lo_data *lo) - { - const char *map = lo->xattrmap; - const char *tmp; -+ int ret; - - lo->xattr_map_nentries = 0; - while (*map) { -@@ -2384,7 +2445,7 @@ static void parse_xattrmap(struct lo_data *lo) - * the last entry. - */ - parse_xattrmap_map(lo, map, sep); -- return; -+ break; - } else { - fuse_log(FUSE_LOG_ERR, - "%s: Unexpected type;" -@@ -2453,6 +2514,19 @@ static void parse_xattrmap(struct lo_data *lo) - fuse_log(FUSE_LOG_ERR, "Empty xattr map\n"); - exit(1); - } -+ -+ ret = xattr_map_client(lo, "security.capability", -+ &lo->xattr_security_capability); -+ if (ret) { -+ fuse_log(FUSE_LOG_ERR, "Failed to map security.capability: %s\n", -+ strerror(ret)); -+ exit(1); -+ } -+ if (!strcmp(lo->xattr_security_capability, "security.capability")) { -+ /* 1-1 mapping, don't need to do anything */ -+ free(lo->xattr_security_capability); -+ lo->xattr_security_capability = NULL; -+ } - } - - /* -@@ -3481,6 +3555,7 @@ static void fuse_lo_data_cleanup(struct lo_data *lo) - - free(lo->xattrmap); - free_xattrmap(lo); -+ free(lo->xattr_security_capability); - free(lo->source); - } - --- -2.27.0 - diff --git a/kvm-virtiofsd-Save-error-code-early-at-the-failure-calls.patch b/kvm-virtiofsd-Save-error-code-early-at-the-failure-calls.patch deleted file mode 100644 index 72e42ac..0000000 --- a/kvm-virtiofsd-Save-error-code-early-at-the-failure-calls.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 22fe525a532619088a135c0f5f80bde12da68109 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Thu, 4 Mar 2021 15:49:00 -0500 -Subject: [PATCH 3/4] virtiofsd: Save error code early at the failure callsite - -RH-Author: Dr. David Alan Gilbert -Message-id: <20210304154901.47930-2-dgilbert@redhat.com> -Patchwork-id: 101304 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/2] virtiofsd: Save error code early at the failure callsite -Bugzilla: 1935071 -RH-Acked-by: Connor Kuehl -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Stefan Hajnoczi - -From: Vivek Goyal - -Change error code handling slightly in lo_setattr(). Right now we seem -to jump to out_err and assume that "errno" is valid and use that to -send reply. - -But if caller has to do some other operations before jumping to out_err, -then it does the dance of first saving errno to saverr and the restore -errno before jumping to out_err. This makes it more confusing. - -I am about to make more changes where caller will have to do some -work after error before jumping to out_err. I found it easier to -change the convention a bit. That is caller saves error in "saverr" -before jumping to out_err. And out_err uses "saverr" to send error -back and does not rely on "errno" having actual error. - -v3: Resolved conflicts in lo_setattr() due to lo_inode_open() changes. - -Signed-off-by: Vivek Goyal -Reviewed-by: Dr. David Alan Gilbert -Message-Id: <20210208224024.43555-2-vgoyal@redhat.com> -(cherry picked from commit 1e08f164e9fdc9528ad6990012301b9a04b0bc90) -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Danilo C. L. de Paula ---- - tools/virtiofsd/passthrough_ll.c | 9 +++++---- - 1 file changed, 5 insertions(+), 4 deletions(-) - -diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c -index 03c5e0d13c..f06074d81f 100644 ---- a/tools/virtiofsd/passthrough_ll.c -+++ b/tools/virtiofsd/passthrough_ll.c -@@ -710,6 +710,7 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, - res = fchmodat(lo->proc_self_fd, procname, attr->st_mode, 0); - } - if (res == -1) { -+ saverr = errno; - goto out_err; - } - } -@@ -719,6 +720,7 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, - - res = fchownat(ifd, "", uid, gid, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); - if (res == -1) { -+ saverr = errno; - goto out_err; - } - } -@@ -730,16 +732,15 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, - } else { - truncfd = lo_inode_open(lo, inode, O_RDWR); - if (truncfd < 0) { -- errno = -truncfd; -+ saverr = -truncfd; - goto out_err; - } - } - - res = ftruncate(truncfd, attr->st_size); -+ saverr = res == -1 ? errno : 0; - if (!fi) { -- saverr = errno; - close(truncfd); -- errno = saverr; - } - if (res == -1) { - goto out_err; -@@ -772,6 +773,7 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, - res = utimensat(lo->proc_self_fd, procname, tv, 0); - } - if (res == -1) { -+ saverr = errno; - goto out_err; - } - } -@@ -780,7 +782,6 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, - return lo_getattr(req, ino, fi); - - out_err: -- saverr = errno; - lo_inode_put(lo, &inode); - fuse_reply_err(req, saverr); - } --- -2.27.0 - diff --git a/kvm-virtiofsd-extract-lo_do_open-from-lo_open.patch b/kvm-virtiofsd-extract-lo_do_open-from-lo_open.patch deleted file mode 100644 index eb73a1c..0000000 --- a/kvm-virtiofsd-extract-lo_do_open-from-lo_open.patch +++ /dev/null @@ -1,157 +0,0 @@ -From 745a04765f21dad1991be89e23dd97a0543d3fce Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Wed, 10 Feb 2021 11:15:16 -0300 -Subject: [PATCH 05/54] virtiofsd: extract lo_do_open() from lo_open() - -RH-Author: Stefan Hajnoczi -Message-id: <20210210111518.228148-2-stefanha@redhat.com> -Patchwork-id: 101032 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/3] virtiofsd: extract lo_do_open() from lo_open() -Bugzilla: 1920740 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Greg Kurz -RH-Acked-by: Dr. David Alan Gilbert - -Both lo_open() and lo_create() have similar code to open a file. Extract -a common lo_do_open() function from lo_open() that will be used by -lo_create() in a later commit. - -Since lo_do_open() does not otherwise need fuse_req_t req, convert -lo_add_fd_mapping() to use struct lo_data *lo instead. - -Signed-off-by: Stefan Hajnoczi -Message-Id: <20210204150208.367837-2-stefanha@redhat.com> -Reviewed-by: Greg Kurz -Signed-off-by: Dr. David Alan Gilbert -(cherry picked from commit 8afaaee976965b7fb90ec225a51d60f35c5f173c) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Eduardo Lima (Etrunko) ---- - tools/virtiofsd/passthrough_ll.c | 73 ++++++++++++++++++++------------ - 1 file changed, 46 insertions(+), 27 deletions(-) - -diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c -index 97485b22b4..218e20e9d7 100644 ---- a/tools/virtiofsd/passthrough_ll.c -+++ b/tools/virtiofsd/passthrough_ll.c -@@ -471,17 +471,17 @@ static void lo_map_remove(struct lo_map *map, size_t key) - } - - /* Assumes lo->mutex is held */ --static ssize_t lo_add_fd_mapping(fuse_req_t req, int fd) -+static ssize_t lo_add_fd_mapping(struct lo_data *lo, int fd) - { - struct lo_map_elem *elem; - -- elem = lo_map_alloc_elem(&lo_data(req)->fd_map); -+ elem = lo_map_alloc_elem(&lo->fd_map); - if (!elem) { - return -1; - } - - elem->fd = fd; -- return elem - lo_data(req)->fd_map.elems; -+ return elem - lo->fd_map.elems; - } - - /* Assumes lo->mutex is held */ -@@ -1661,6 +1661,38 @@ static void update_open_flags(int writeback, int allow_direct_io, - } - } - -+static int lo_do_open(struct lo_data *lo, struct lo_inode *inode, -+ struct fuse_file_info *fi) -+{ -+ char buf[64]; -+ ssize_t fh; -+ int fd; -+ -+ update_open_flags(lo->writeback, lo->allow_direct_io, fi); -+ -+ sprintf(buf, "%i", inode->fd); -+ fd = openat(lo->proc_self_fd, buf, fi->flags & ~O_NOFOLLOW); -+ if (fd == -1) { -+ return errno; -+ } -+ -+ pthread_mutex_lock(&lo->mutex); -+ fh = lo_add_fd_mapping(lo, fd); -+ pthread_mutex_unlock(&lo->mutex); -+ if (fh == -1) { -+ close(fd); -+ return ENOMEM; -+ } -+ -+ fi->fh = fh; -+ if (lo->cache == CACHE_NONE) { -+ fi->direct_io = 1; -+ } else if (lo->cache == CACHE_ALWAYS) { -+ fi->keep_cache = 1; -+ } -+ return 0; -+} -+ - static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, struct fuse_file_info *fi) - { -@@ -1701,7 +1733,7 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name, - ssize_t fh; - - pthread_mutex_lock(&lo->mutex); -- fh = lo_add_fd_mapping(req, fd); -+ fh = lo_add_fd_mapping(lo, fd); - pthread_mutex_unlock(&lo->mutex); - if (fh == -1) { - close(fd); -@@ -1892,38 +1924,25 @@ static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync, - - static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) - { -- int fd; -- ssize_t fh; -- char buf[64]; - struct lo_data *lo = lo_data(req); -+ struct lo_inode *inode = lo_inode(req, ino); -+ int err; - - fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n", ino, - fi->flags); - -- update_open_flags(lo->writeback, lo->allow_direct_io, fi); -- -- sprintf(buf, "%i", lo_fd(req, ino)); -- fd = openat(lo->proc_self_fd, buf, fi->flags & ~O_NOFOLLOW); -- if (fd == -1) { -- return (void)fuse_reply_err(req, errno); -- } -- -- pthread_mutex_lock(&lo->mutex); -- fh = lo_add_fd_mapping(req, fd); -- pthread_mutex_unlock(&lo->mutex); -- if (fh == -1) { -- close(fd); -- fuse_reply_err(req, ENOMEM); -+ if (!inode) { -+ fuse_reply_err(req, EBADF); - return; - } - -- fi->fh = fh; -- if (lo->cache == CACHE_NONE) { -- fi->direct_io = 1; -- } else if (lo->cache == CACHE_ALWAYS) { -- fi->keep_cache = 1; -+ err = lo_do_open(lo, inode, fi); -+ lo_inode_put(lo, &inode); -+ if (err) { -+ fuse_reply_err(req, err); -+ } else { -+ fuse_reply_open(req, fi); - } -- fuse_reply_open(req, fi); - } - - static void lo_release(fuse_req_t req, fuse_ino_t ino, --- -2.27.0 - diff --git a/kvm-virtiofsd-optionally-return-inode-pointer-from-lo_do.patch b/kvm-virtiofsd-optionally-return-inode-pointer-from-lo_do.patch deleted file mode 100644 index 95d8085..0000000 --- a/kvm-virtiofsd-optionally-return-inode-pointer-from-lo_do.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 24833a2db44e39ec7652779a0fa2e70983b9cb4e Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Wed, 10 Feb 2021 11:15:17 -0300 -Subject: [PATCH 06/54] virtiofsd: optionally return inode pointer from - lo_do_lookup() - -RH-Author: Stefan Hajnoczi -Message-id: <20210210111518.228148-3-stefanha@redhat.com> -Patchwork-id: 101033 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 2/3] virtiofsd: optionally return inode pointer from lo_do_lookup() -Bugzilla: 1920740 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Greg Kurz -RH-Acked-by: Dr. David Alan Gilbert - -lo_do_lookup() finds an existing inode or allocates a new one. It -increments nlookup so that the inode stays alive until the client -releases it. - -Existing callers don't need the struct lo_inode so the function doesn't -return it. Extend the function to optionally return the inode. The next -commit will need it. - -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Greg Kurz -Message-Id: <20210204150208.367837-3-stefanha@redhat.com> -Signed-off-by: Dr. David Alan Gilbert -(cherry picked from commit 22d2ece71e533310da31f2857ebc4a00d91968b3) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Eduardo Lima (Etrunko) ---- - tools/virtiofsd/passthrough_ll.c | 29 +++++++++++++++++++++-------- - 1 file changed, 21 insertions(+), 8 deletions(-) - -diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c -index 218e20e9d7..2bd050b620 100644 ---- a/tools/virtiofsd/passthrough_ll.c -+++ b/tools/virtiofsd/passthrough_ll.c -@@ -843,11 +843,13 @@ static int do_statx(struct lo_data *lo, int dirfd, const char *pathname, - } - - /* -- * Increments nlookup and caller must release refcount using -- * lo_inode_put(&parent). -+ * Increments nlookup on the inode on success. unref_inode_lolocked() must be -+ * called eventually to decrement nlookup again. If inodep is non-NULL, the -+ * inode pointer is stored and the caller must call lo_inode_put(). - */ - static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name, -- struct fuse_entry_param *e) -+ struct fuse_entry_param *e, -+ struct lo_inode **inodep) - { - int newfd; - int res; -@@ -857,6 +859,10 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name, - struct lo_inode *inode = NULL; - struct lo_inode *dir = lo_inode(req, parent); - -+ if (inodep) { -+ *inodep = NULL; -+ } -+ - /* - * name_to_handle_at() and open_by_handle_at() can reach here with fuse - * mount point in guest, but we don't have its inode info in the -@@ -924,7 +930,14 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name, - pthread_mutex_unlock(&lo->mutex); - } - e->ino = inode->fuse_ino; -- lo_inode_put(lo, &inode); -+ -+ /* Transfer ownership of inode pointer to caller or drop it */ -+ if (inodep) { -+ *inodep = inode; -+ } else { -+ lo_inode_put(lo, &inode); -+ } -+ - lo_inode_put(lo, &dir); - - fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n", (unsigned long long)parent, -@@ -959,7 +972,7 @@ static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) - return; - } - -- err = lo_do_lookup(req, parent, name, &e); -+ err = lo_do_lookup(req, parent, name, &e, NULL); - if (err) { - fuse_reply_err(req, err); - } else { -@@ -1067,7 +1080,7 @@ static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent, - goto out; - } - -- saverr = lo_do_lookup(req, parent, name, &e); -+ saverr = lo_do_lookup(req, parent, name, &e, NULL); - if (saverr) { - goto out; - } -@@ -1544,7 +1557,7 @@ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, - - if (plus) { - if (!is_dot_or_dotdot(name)) { -- err = lo_do_lookup(req, ino, name, &e); -+ err = lo_do_lookup(req, ino, name, &e, NULL); - if (err) { - goto error; - } -@@ -1742,7 +1755,7 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name, - } - - fi->fh = fh; -- err = lo_do_lookup(req, parent, name, &e); -+ err = lo_do_lookup(req, parent, name, &e, NULL); - } - if (lo->cache == CACHE_NONE) { - fi->direct_io = 1; --- -2.27.0 - diff --git a/kvm-virtiofsd-prevent-opening-of-special-files-CVE-2020-.patch b/kvm-virtiofsd-prevent-opening-of-special-files-CVE-2020-.patch deleted file mode 100644 index a4ded98..0000000 --- a/kvm-virtiofsd-prevent-opening-of-special-files-CVE-2020-.patch +++ /dev/null @@ -1,311 +0,0 @@ -From 8cc13bdaa45cca3ef907cad9697683390aff2545 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Wed, 10 Feb 2021 11:15:18 -0300 -Subject: [PATCH 07/54] virtiofsd: prevent opening of special files - (CVE-2020-35517) - -RH-Author: Stefan Hajnoczi -Message-id: <20210210111518.228148-4-stefanha@redhat.com> -Patchwork-id: 101034 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 3/3] virtiofsd: prevent opening of special files (CVE-2020-35517) -Bugzilla: 1920740 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Greg Kurz -RH-Acked-by: Dr. David Alan Gilbert - -A well-behaved FUSE client does not attempt to open special files with -FUSE_OPEN because they are handled on the client side (e.g. device nodes -are handled by client-side device drivers). - -The check to prevent virtiofsd from opening special files is missing in -a few cases, most notably FUSE_OPEN. A malicious client can cause -virtiofsd to open a device node, potentially allowing the guest to -escape. This can be exploited by a modified guest device driver. It is -not exploitable from guest userspace since the guest kernel will handle -special files inside the guest instead of sending FUSE requests. - -This patch fixes this issue by introducing the lo_inode_open() function -to check the file type before opening it. This is a short-term solution -because it does not prevent a compromised virtiofsd process from opening -device nodes on the host. - -Restructure lo_create() to try O_CREAT | O_EXCL first. Note that O_CREAT -| O_EXCL does not follow symlinks, so O_NOFOLLOW masking is not -necessary here. If the file exists and the user did not specify O_EXCL, -open it via lo_do_open(). - -Reported-by: Alex Xu -Fixes: CVE-2020-35517 -Reviewed-by: Dr. David Alan Gilbert -Reviewed-by: Vivek Goyal -Reviewed-by: Greg Kurz -Signed-off-by: Stefan Hajnoczi -Message-Id: <20210204150208.367837-4-stefanha@redhat.com> -Signed-off-by: Dr. David Alan Gilbert -(cherry picked from commit a3fdbbc7f271bff7d53d0501b29d910ece0b3789) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Eduardo Lima (Etrunko) ---- - tools/virtiofsd/passthrough_ll.c | 144 ++++++++++++++++++++----------- - 1 file changed, 92 insertions(+), 52 deletions(-) - -diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c -index 2bd050b620..03c5e0d13c 100644 ---- a/tools/virtiofsd/passthrough_ll.c -+++ b/tools/virtiofsd/passthrough_ll.c -@@ -567,6 +567,38 @@ static int lo_fd(fuse_req_t req, fuse_ino_t ino) - return fd; - } - -+/* -+ * Open a file descriptor for an inode. Returns -EBADF if the inode is not a -+ * regular file or a directory. -+ * -+ * Use this helper function instead of raw openat(2) to prevent security issues -+ * when a malicious client opens special files such as block device nodes. -+ * Symlink inodes are also rejected since symlinks must already have been -+ * traversed on the client side. -+ */ -+static int lo_inode_open(struct lo_data *lo, struct lo_inode *inode, -+ int open_flags) -+{ -+ g_autofree char *fd_str = g_strdup_printf("%d", inode->fd); -+ int fd; -+ -+ if (!S_ISREG(inode->filetype) && !S_ISDIR(inode->filetype)) { -+ return -EBADF; -+ } -+ -+ /* -+ * The file is a symlink so O_NOFOLLOW must be ignored. We checked earlier -+ * that the inode is not a special file but if an external process races -+ * with us then symlinks are traversed here. It is not possible to escape -+ * the shared directory since it is mounted as "/" though. -+ */ -+ fd = openat(lo->proc_self_fd, fd_str, open_flags & ~O_NOFOLLOW); -+ if (fd < 0) { -+ return -errno; -+ } -+ return fd; -+} -+ - static void lo_init(void *userdata, struct fuse_conn_info *conn) - { - struct lo_data *lo = (struct lo_data *)userdata; -@@ -696,9 +728,9 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, - if (fi) { - truncfd = fd; - } else { -- sprintf(procname, "%i", ifd); -- truncfd = openat(lo->proc_self_fd, procname, O_RDWR); -+ truncfd = lo_inode_open(lo, inode, O_RDWR); - if (truncfd < 0) { -+ errno = -truncfd; - goto out_err; - } - } -@@ -860,7 +892,7 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name, - struct lo_inode *dir = lo_inode(req, parent); - - if (inodep) { -- *inodep = NULL; -+ *inodep = NULL; /* in case there is an error */ - } - - /* -@@ -1674,19 +1706,26 @@ static void update_open_flags(int writeback, int allow_direct_io, - } - } - -+/* -+ * Open a regular file, set up an fd mapping, and fill out the struct -+ * fuse_file_info for it. If existing_fd is not negative, use that fd instead -+ * opening a new one. Takes ownership of existing_fd. -+ * -+ * Returns 0 on success or a positive errno. -+ */ - static int lo_do_open(struct lo_data *lo, struct lo_inode *inode, -- struct fuse_file_info *fi) -+ int existing_fd, struct fuse_file_info *fi) - { -- char buf[64]; - ssize_t fh; -- int fd; -+ int fd = existing_fd; - - update_open_flags(lo->writeback, lo->allow_direct_io, fi); - -- sprintf(buf, "%i", inode->fd); -- fd = openat(lo->proc_self_fd, buf, fi->flags & ~O_NOFOLLOW); -- if (fd == -1) { -- return errno; -+ if (fd < 0) { -+ fd = lo_inode_open(lo, inode, fi->flags); -+ if (fd < 0) { -+ return -fd; -+ } - } - - pthread_mutex_lock(&lo->mutex); -@@ -1709,9 +1748,10 @@ static int lo_do_open(struct lo_data *lo, struct lo_inode *inode, - static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, struct fuse_file_info *fi) - { -- int fd; -+ int fd = -1; - struct lo_data *lo = lo_data(req); - struct lo_inode *parent_inode; -+ struct lo_inode *inode = NULL; - struct fuse_entry_param e; - int err; - struct lo_cred old = {}; -@@ -1737,36 +1777,38 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name, - - update_open_flags(lo->writeback, lo->allow_direct_io, fi); - -- fd = openat(parent_inode->fd, name, (fi->flags | O_CREAT) & ~O_NOFOLLOW, -- mode); -+ /* Try to create a new file but don't open existing files */ -+ fd = openat(parent_inode->fd, name, fi->flags | O_CREAT | O_EXCL, mode); - err = fd == -1 ? errno : 0; -- lo_restore_cred(&old); - -- if (!err) { -- ssize_t fh; -+ lo_restore_cred(&old); - -- pthread_mutex_lock(&lo->mutex); -- fh = lo_add_fd_mapping(lo, fd); -- pthread_mutex_unlock(&lo->mutex); -- if (fh == -1) { -- close(fd); -- err = ENOMEM; -- goto out; -- } -+ /* Ignore the error if file exists and O_EXCL was not given */ -+ if (err && (err != EEXIST || (fi->flags & O_EXCL))) { -+ goto out; -+ } - -- fi->fh = fh; -- err = lo_do_lookup(req, parent, name, &e, NULL); -+ err = lo_do_lookup(req, parent, name, &e, &inode); -+ if (err) { -+ goto out; - } -- if (lo->cache == CACHE_NONE) { -- fi->direct_io = 1; -- } else if (lo->cache == CACHE_ALWAYS) { -- fi->keep_cache = 1; -+ -+ err = lo_do_open(lo, inode, fd, fi); -+ fd = -1; /* lo_do_open() takes ownership of fd */ -+ if (err) { -+ /* Undo lo_do_lookup() nlookup ref */ -+ unref_inode_lolocked(lo, inode, 1); - } - - out: -+ lo_inode_put(lo, &inode); - lo_inode_put(lo, &parent_inode); - - if (err) { -+ if (fd >= 0) { -+ close(fd); -+ } -+ - fuse_reply_err(req, err); - } else { - fuse_reply_create(req, &e, fi); -@@ -1780,7 +1822,6 @@ static struct lo_inode_plock *lookup_create_plock_ctx(struct lo_data *lo, - pid_t pid, int *err) - { - struct lo_inode_plock *plock; -- char procname[64]; - int fd; - - plock = -@@ -1797,12 +1838,10 @@ static struct lo_inode_plock *lookup_create_plock_ctx(struct lo_data *lo, - } - - /* Open another instance of file which can be used for ofd locks. */ -- sprintf(procname, "%i", inode->fd); -- - /* TODO: What if file is not writable? */ -- fd = openat(lo->proc_self_fd, procname, O_RDWR); -- if (fd == -1) { -- *err = errno; -+ fd = lo_inode_open(lo, inode, O_RDWR); -+ if (fd < 0) { -+ *err = -fd; - free(plock); - return NULL; - } -@@ -1949,7 +1988,7 @@ static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) - return; - } - -- err = lo_do_open(lo, inode, fi); -+ err = lo_do_open(lo, inode, -1, fi); - lo_inode_put(lo, &inode); - if (err) { - fuse_reply_err(req, err); -@@ -2005,39 +2044,40 @@ static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) - static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi) - { -+ struct lo_inode *inode = lo_inode(req, ino); -+ struct lo_data *lo = lo_data(req); - int res; - int fd; -- char *buf; - - fuse_log(FUSE_LOG_DEBUG, "lo_fsync(ino=%" PRIu64 ", fi=0x%p)\n", ino, - (void *)fi); - -- if (!fi) { -- struct lo_data *lo = lo_data(req); -- -- res = asprintf(&buf, "%i", lo_fd(req, ino)); -- if (res == -1) { -- return (void)fuse_reply_err(req, errno); -- } -+ if (!inode) { -+ fuse_reply_err(req, EBADF); -+ return; -+ } - -- fd = openat(lo->proc_self_fd, buf, O_RDWR); -- free(buf); -- if (fd == -1) { -- return (void)fuse_reply_err(req, errno); -+ if (!fi) { -+ fd = lo_inode_open(lo, inode, O_RDWR); -+ if (fd < 0) { -+ res = -fd; -+ goto out; - } - } else { - fd = lo_fi_fd(req, fi); - } - - if (datasync) { -- res = fdatasync(fd); -+ res = fdatasync(fd) == -1 ? errno : 0; - } else { -- res = fsync(fd); -+ res = fsync(fd) == -1 ? errno : 0; - } - if (!fi) { - close(fd); - } -- fuse_reply_err(req, res == -1 ? errno : 0); -+out: -+ lo_inode_put(lo, &inode); -+ fuse_reply_err(req, res); - } - - static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, --- -2.27.0 - diff --git a/kvm-x86-cpu-Add-AVX512_FP16-cpu-feature.patch b/kvm-x86-cpu-Add-AVX512_FP16-cpu-feature.patch deleted file mode 100644 index f04d944..0000000 --- a/kvm-x86-cpu-Add-AVX512_FP16-cpu-feature.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 5840880e2ed3747464242e0559a6cf7ec4e55a11 Mon Sep 17 00:00:00 2001 -From: "plai@redhat.com" -Date: Thu, 21 Jan 2021 17:43:53 -0500 -Subject: [PATCH 3/5] x86/cpu: Add AVX512_FP16 cpu feature - -RH-Author: plai@redhat.com -Message-id: <20210121174353.16032-1-plai@redhat.com> -Patchwork-id: 100758 -O-Subject: [RHEL8.4 AV qemu-kvm PATCH] x86/cpu: Add AVX512_FP16 cpu feature -Bugzilla: 1838738 -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Bandan Das - -From: Cathy Zhang - -BZ https://bugzilla.redhat.com/show_bug.cgi?id=1838738 -Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=34299228 - x86 https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=34299267 -Branch rhel-av-8.4.0 - -Tested on intel-eaglestream-spr-01.khw1.lab.eng.bos.redhat.com. -All flags found as expected - avx512_vp2intersect, serialize, and avx512_fp16 -except: - tsxldtrk - -Cpuid reports CPUID.(7.0).EDX[16] isn't enabled on this CPU. -Leaf Subleaf EAX EBX ECX EDX -00000007 00000000: 00000001 .... f3bfbfef .... fa417f5e ^.A. ff8c4532 2E.. - -Already in rhel-av-8.4.0 (rebased to v5.2.0 ): - 353f98c9a x86/cpu: Enable AVX512_VP2INTERSECT cpu feature - 5dd13f2a5 target/i386: Add SERIALIZE cpu feature - b3c7344e3 target/i386: Enable TSX Suspend Load Address Tracking feature - -Signed-off-by: Eduardo Lima (Etrunko) ---- - target/i386/cpu.c | 2 +- - target/i386/cpu.h | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index dc592e990e..f944b41573 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -977,7 +977,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - "avx512-vp2intersect", NULL, "md-clear", NULL, - NULL, NULL, "serialize", NULL, - "tsx-ldtrk", NULL, NULL /* pconfig */, NULL, -- NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, "avx512-fp16", - NULL, NULL, "spec-ctrl", "stibp", - NULL, "arch-capabilities", "core-capability", "ssbd", - }, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 88e8586f8f..a3db7e3c6c 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -783,6 +783,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS]; - #define CPUID_7_0_EDX_SERIALIZE (1U << 14) - /* TSX Suspend Load Address Tracking instruction */ - #define CPUID_7_0_EDX_TSX_LDTRK (1U << 16) -+/* AVX512_FP16 instruction */ -+#define CPUID_7_0_EDX_AVX512_FP16 (1U << 23) - /* Speculation Control */ - #define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) - /* Single Thread Indirect Branch Predictors */ --- -2.18.4 - diff --git a/kvm-x86-cpu-Populate-SVM-CPUID-feature-bits.patch b/kvm-x86-cpu-Populate-SVM-CPUID-feature-bits.patch deleted file mode 100644 index 68d2cd8..0000000 --- a/kvm-x86-cpu-Populate-SVM-CPUID-feature-bits.patch +++ /dev/null @@ -1,91 +0,0 @@ -From ed5fe7ae48c263ff69602b55361806f896ed12fb Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Tue, 23 Feb 2021 15:18:10 -0500 -Subject: [PATCH 51/54] x86/cpu: Populate SVM CPUID feature bits - -RH-Author: Dr. David Alan Gilbert -Message-id: <20210223151811.27968-2-dgilbert@redhat.com> -Patchwork-id: 101197 -O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 1/2] x86/cpu: Populate SVM CPUID feature bits -Bugzilla: 1926785 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Sergio Lopez Pascual -RH-Acked-by: Peter Xu - -From: Wei Huang - -Newer AMD CPUs will add CPUID_0x8000000A_EDX[28] bit, which indicates -that SVM instructions (VMRUN/VMSAVE/VMLOAD) will trigger #VMEXIT before -CPU checking their EAX against reserved memory regions. This change will -allow the hypervisor to avoid intercepting #GP and emulating SVM -instructions. KVM turns on this CPUID bit for nested VMs. In order to -support it, let us populate this bit, along with other SVM feature bits, -in FEAT_SVM. - -Signed-off-by: Wei Huang -Message-Id: <20210126202456.589932-1-wei.huang2@amd.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 5447089c2b3b084b51670af36fc86ee3979e04be) -Signed-off-by: Danilo C. L. de Paula ---- - target/i386/cpu.c | 6 +++--- - target/i386/cpu.h | 24 ++++++++++++++---------- - 2 files changed, 17 insertions(+), 13 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index f944b41573..372cba2942 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -922,11 +922,11 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - "npt", "lbrv", "svm-lock", "nrip-save", - "tsc-scale", "vmcb-clean", "flushbyasid", "decodeassists", - NULL, NULL, "pause-filter", NULL, -- "pfthreshold", NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -+ "pfthreshold", "avic", NULL, "v-vmsave-vmload", -+ "vgif", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -+ "svme-addr-chk", NULL, NULL, NULL, - }, - .cpuid = { .eax = 0x8000000A, .reg = R_EDX, }, - .tcg_features = TCG_SVM_FEATURES, -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index a3db7e3c6c..4fdb552f93 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -672,16 +672,20 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS]; - #define CPUID_EXT3_PERFCORE (1U << 23) - #define CPUID_EXT3_PERFNB (1U << 24) - --#define CPUID_SVM_NPT (1U << 0) --#define CPUID_SVM_LBRV (1U << 1) --#define CPUID_SVM_SVMLOCK (1U << 2) --#define CPUID_SVM_NRIPSAVE (1U << 3) --#define CPUID_SVM_TSCSCALE (1U << 4) --#define CPUID_SVM_VMCBCLEAN (1U << 5) --#define CPUID_SVM_FLUSHASID (1U << 6) --#define CPUID_SVM_DECODEASSIST (1U << 7) --#define CPUID_SVM_PAUSEFILTER (1U << 10) --#define CPUID_SVM_PFTHRESHOLD (1U << 12) -+#define CPUID_SVM_NPT (1U << 0) -+#define CPUID_SVM_LBRV (1U << 1) -+#define CPUID_SVM_SVMLOCK (1U << 2) -+#define CPUID_SVM_NRIPSAVE (1U << 3) -+#define CPUID_SVM_TSCSCALE (1U << 4) -+#define CPUID_SVM_VMCBCLEAN (1U << 5) -+#define CPUID_SVM_FLUSHASID (1U << 6) -+#define CPUID_SVM_DECODEASSIST (1U << 7) -+#define CPUID_SVM_PAUSEFILTER (1U << 10) -+#define CPUID_SVM_PFTHRESHOLD (1U << 12) -+#define CPUID_SVM_AVIC (1U << 13) -+#define CPUID_SVM_V_VMSAVE_VMLOAD (1U << 15) -+#define CPUID_SVM_VGIF (1U << 16) -+#define CPUID_SVM_SVME_ADDR_CHK (1U << 28) - - /* Support RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE */ - #define CPUID_7_0_EBX_FSGSBASE (1U << 0) --- -2.27.0 - diff --git a/qemu-kvm.spec b/qemu-kvm.spec index 91601d0..fa7f3bb 100644 --- a/qemu-kvm.spec +++ b/qemu-kvm.spec @@ -69,8 +69,8 @@ Requires: %{name}-block-ssh = %{epoch}:%{version}-%{release} Summary: QEMU is a machine emulator and virtualizer Name: qemu-kvm -Version: 5.2.0 -Release: 16%{?dist} +Version: 6.0.0 +Release: 1%{?rcversion}%{?dist} # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 15 License: GPLv2 and GPLv2+ and CC-BY @@ -79,7 +79,7 @@ URL: http://www.qemu.org/ ExclusiveArch: x86_64 %{power64} aarch64 s390x -Source0: http://wiki.qemu.org/download/qemu-5.2.0.tar.xz +Source0: http://wiki.qemu.org/download/qemu-6.0.0.tar.xz # KSM control scripts Source4: ksm.service @@ -107,223 +107,21 @@ Source35: udev-kvm-check.c Source36: README.tests -Patch0001: 0001-redhat-Adding-slirp-to-the-exploded-tree.patch -Patch0005: 0005-Initial-redhat-build.patch -Patch0006: 0006-Enable-disable-devices-for-RHEL.patch -Patch0007: 0007-Machine-type-related-general-changes.patch -Patch0008: 0008-Add-aarch64-machine-types.patch -Patch0009: 0009-Add-ppc64-machine-types.patch -Patch0010: 0010-Add-s390x-machine-types.patch -Patch0011: 0011-Add-x86_64-machine-types.patch -Patch0012: 0012-Enable-make-check.patch -Patch0013: 0013-vfio-cap-number-of-devices-that-can-be-assigned.patch -Patch0014: 0014-Add-support-statement-to-help-output.patch -Patch0015: 0015-globally-limit-the-maximum-number-of-CPUs.patch -Patch0016: 0016-Use-qemu-kvm-in-documentation-instead-of-qemu-system.patch -Patch0017: 0017-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch -Patch0018: 0018-BZ1653590-Require-at-least-64kiB-pages-for-downstrea.patch -Patch0019: 0019-block-Versioned-x-blockdev-reopen-API-with-feature-f.patch -Patch0021: 0021-redhat-Define-hw_compat_8_3.patch -Patch0022: 0022-redhat-Add-spapr_machine_rhel_default_class_options.patch -Patch0023: 0023-redhat-Define-pseries-rhel8.4.0-machine-type.patch -Patch0024: 0024-redhat-s390x-add-rhel-8.4.0-compat-machine.patch -Patch0027: 0027-block-vpc-Make-vpc_open-read-the-full-dynamic-header.patch -Patch0028: 0028-GCC-11-warnings-hacks.patch -Patch0029: 0029-Disable-problematic-tests-for-initial-build.patch -Patch0030: 0030-Revert-GCC-11-warnings-hacks.patch -Patch0031: 0031-s390x-Use-strpadcpy-for-copying-vm-name.patch -Patch0032: 0032-tcg-Restrict-tcg_out_op-to-arrays-of-TCG_MAX_OP_ARGS.patch -Patch0033: 0033-net-eth-Simplify-_eth_get_rss_ex_dst_addr.patch -Patch0034: 0034-net-eth-Fix-stack-buffer-overflow-in.patch -Patch0035: 0035-block-nvme-Implement-fake-truncate-coroutine.patch -Patch0037: 0037-build-system-use-b_staticpic-false.patch -Patch0038: 0038-spapr-Fix-buffer-overflow-in-spapr_numa_associativit.patch -Patch0039: 0039-usb-hcd-xhci-pci-Fixup-capabilities-ordering-again.patch -Patch0040: 0040-qga-commands-posix-Send-CCW-address-on-s390x-with-th.patch -Patch0041: 0041-AArch64-machine-types-cleanup.patch -Patch0042: 0042-hw-arm-virt-Add-8.4-Machine-type.patch -Patch0044: 0044-memory-Rename-memory_region_notify_one-to-memory_reg.patch -Patch0045: 0045-memory-Add-IOMMUTLBEvent.patch -Patch0046: 0046-memory-Add-IOMMU_NOTIFIER_DEVIOTLB_UNMAP-IOMMUTLBNot.patch -Patch0047: 0047-intel_iommu-Skip-page-walking-on-device-iotlb-invali.patch -Patch0048: 0048-memory-Skip-bad-range-assertion-if-notifier-is-DEVIO.patch -Patch0049: 0049-RHEL-Switch-pvpanic-test-to-q35.patch -Patch0050: 0050-8.4-x86-machine-type.patch -Patch0051: 0051-memory-clamp-cached-translation-in-case-it-points-to.patch -Patch0054: 0054-Drop-bogus-IPv6-messages.patch -# For bz#1914069 - [ppc64le] have this fix for rhel8.4 av (spapr: Allow memory unplug to always succeed) -Patch55: kvm-spapr-Allow-memory-unplug-to-always-succeed.patch -# For bz#1914069 - [ppc64le] have this fix for rhel8.4 av (spapr: Allow memory unplug to always succeed) -Patch56: kvm-spapr-Improve-handling-of-memory-unplug-with-old-gue.patch -# For bz#1838738 - [Intel 8.4 FEAT] qemu-kvm Sapphire Rapids (SPR) New Instructions (NIs) - Fast Train -Patch57: kvm-x86-cpu-Add-AVX512_FP16-cpu-feature.patch -# For bz#1904268 - [RFE] [HPEMC] qemu-kvm: support up to 710 VCPUs -Patch58: kvm-q35-Increase-max_cpus-to-710-on-pc-q35-rhel8-machine.patch -# For bz#1922170 - Enable vfio-ccw in AV -Patch59: kvm-config-enable-VFIO_CCW.patch -# For bz#1854811 - scsi-bus.c: use-after-free due to race between device unplug and I/O operation causes guest crash -Patch60: kvm-scsi-fix-device-removal-race-vs-IO-restart-callback-.patch -# For bz#1907264 - systemtap: invalid or missing conversion specifier at the trace event vhost_vdpa_set_log_base -Patch61: kvm-tracetool-also-strip-l-and-ll-from-systemtap-format-.patch -# For bz#1834152 - [aarch64] QEMU SMMUv3 device: Support range invalidation -Patch63: kvm-hw-arm-smmuv3-Fix-addr_mask-for-range-based-invalida.patch -# For bz#1925028 - vsmmuv3/vhost and virtio-iommu/vhost regression -Patch65: kvm-vhost-Unbreak-SMMU-and-virtio-iommu-on-dev-iotlb-sup.patch -# For bz#1902537 - The default fsfreeze-hook path from man page and qemu-ga --help command are different -Patch66: kvm-docs-set-CONFDIR-when-running-sphinx.patch -# For bz#1903521 - hot unplug vhost-user cause qemu crash: qemu-kvm: ../softmmu/memory.c:2818: do_address_space_destroy: Assertion `QTAILQ_EMPTY(&as->listeners)' failed. -Patch67: kvm-virtio-Add-corresponding-memory_listener_unregister-.patch -# For bz#1918966 - [incremental_backup] qemu aborts if guest reboot during backup when using virtio-blk: "aio_co_schedule: Co-routine was already scheduled in 'aio_co_schedule'" -# For bz#1918968 - [incremental_backup] qemu deadlock after poweroff in guest during backup in nbd_export_close_all() -Patch68: kvm-block-Honor-blk_set_aio_context-context-requirements.patch -# For bz#1918966 - [incremental_backup] qemu aborts if guest reboot during backup when using virtio-blk: "aio_co_schedule: Co-routine was already scheduled in 'aio_co_schedule'" -# For bz#1918968 - [incremental_backup] qemu deadlock after poweroff in guest during backup in nbd_export_close_all() -Patch69: kvm-nbd-server-Quiesce-coroutines-on-context-switch.patch -# For bz#1918966 - [incremental_backup] qemu aborts if guest reboot during backup when using virtio-blk: "aio_co_schedule: Co-routine was already scheduled in 'aio_co_schedule'" -# For bz#1918968 - [incremental_backup] qemu deadlock after poweroff in guest during backup in nbd_export_close_all() -Patch70: kvm-block-Avoid-processing-BDS-twice-in-bdrv_set_aio_con.patch -# For bz#1918966 - [incremental_backup] qemu aborts if guest reboot during backup when using virtio-blk: "aio_co_schedule: Co-routine was already scheduled in 'aio_co_schedule'" -# For bz#1918968 - [incremental_backup] qemu deadlock after poweroff in guest during backup in nbd_export_close_all() -Patch71: kvm-storage-daemon-Call-bdrv_close_all-on-exit.patch -# For bz#1918966 - [incremental_backup] qemu aborts if guest reboot during backup when using virtio-blk: "aio_co_schedule: Co-routine was already scheduled in 'aio_co_schedule'" -# For bz#1918968 - [incremental_backup] qemu deadlock after poweroff in guest during backup in nbd_export_close_all() -Patch72: kvm-block-move-blk_exp_close_all-to-qemu_cleanup.patch -# For bz#1887883 - qemu blocks client progress with various NBD actions -Patch73: kvm-block-nbd-only-detach-existing-iochannel-from-aio_co.patch -# For bz#1887883 - qemu blocks client progress with various NBD actions -Patch74: kvm-block-nbd-only-enter-connection-coroutine-if-it-s-pr.patch -# For bz#1887883 - qemu blocks client progress with various NBD actions -Patch75: kvm-nbd-make-nbd_read-return-EIO-on-error.patch -# For bz#1907255 - Migrate failed with vhost-vsock-pci from RHEL-AV 8.3.1 to RHEL-AV 8.2.1 -Patch76: kvm-virtio-move-use-disabled-flag-property-to-hw_compat_.patch -# For bz#1920740 - CVE-2020-35517 virt:8.4/qemu-kvm: QEMU: virtiofsd: potential privileged host device access from guest [rhel-av-8.4.0] -Patch77: kvm-virtiofsd-extract-lo_do_open-from-lo_open.patch -# For bz#1920740 - CVE-2020-35517 virt:8.4/qemu-kvm: QEMU: virtiofsd: potential privileged host device access from guest [rhel-av-8.4.0] -Patch78: kvm-virtiofsd-optionally-return-inode-pointer-from-lo_do.patch -# For bz#1920740 - CVE-2020-35517 virt:8.4/qemu-kvm: QEMU: virtiofsd: potential privileged host device access from guest [rhel-av-8.4.0] -Patch79: kvm-virtiofsd-prevent-opening-of-special-files-CVE-2020-.patch -# For bz#1920941 - [ppc64le] [AV]--disk cdimage.iso,bus=usb fails to boot -Patch80: kvm-spapr-Adjust-firmware-path-of-PCI-devices.patch -# For bz#1917830 - Add romsize property to qemu-kvm -Patch81: kvm-pci-reject-too-large-ROMs.patch -# For bz#1917830 - Add romsize property to qemu-kvm -Patch82: kvm-pci-add-romsize-property.patch -# For bz#1917826 - Add extra device support to qemu-kvm, but not to rhel machine types -Patch83: kvm-redhat-Add-some-devices-for-exporting-upstream-machi.patch -# For bz#1880299 - vhost-user mq connection fails to restart after kill host testpmd which acts as vhost-user client -Patch84: kvm-vhost-Check-for-valid-vdev-in-vhost_backend_handle_i.patch -# For bz#1901323 - QSD (QEMU Storage Daemon): basic support - TechPreview -Patch85: kvm-docs-generate-qemu-storage-daemon-qmp-ref-7-man-page.patch -# For bz#1901323 - QSD (QEMU Storage Daemon): basic support - TechPreview -Patch86: kvm-docs-add-qemu-storage-daemon-1-man-page.patch -# For bz#1901323 - QSD (QEMU Storage Daemon): basic support - TechPreview -Patch87: kvm-docs-Add-qemu-storage-daemon-1-manpage-to-meson.buil.patch -# For bz#1901323 - QSD (QEMU Storage Daemon): basic support - TechPreview -Patch88: kvm-qemu-storage-daemon-Enable-object-add.patch -# For bz#1930033 - enable vhost-user-blk device [TechPreview] -Patch90: kvm-default-configs-Enable-vhost-user-blk.patch -# For bz#1925345 - qemu-nbd needs larger backlog for Unix socket listen() -Patch91: kvm-qemu-nbd-Use-SOMAXCONN-for-socket-listen-backlog.patch -# For bz#1917654 - [failover vf migration][RHEL84 vm] After start a vm with a failover vf + a failover virtio net device, the failvoer vf do not exist in the vm -Patch92: kvm-pcie-don-t-set-link-state-active-if-the-slot-is-empt.patch -# For bz#1930757 - Allow control of block-dirty-bitmap persistence via 'block-bitmap-mapping' -Patch93: kvm-migration-dirty-bitmap-Use-struct-for-alias-map-inne.patch -# For bz#1930757 - Allow control of block-dirty-bitmap persistence via 'block-bitmap-mapping' -Patch94: kvm-migration-dirty-bitmap-Allow-control-of-bitmap-persi.patch -# For bz#1930757 - Allow control of block-dirty-bitmap persistence via 'block-bitmap-mapping' -Patch95: kvm-qemu-iotests-300-Add-test-case-for-modifying-persist.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch96: kvm-failover-fix-indentantion.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch97: kvm-failover-Use-always-atomics-for-primary_should_be_hi.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch98: kvm-failover-primary-bus-is-only-used-once-and-where-it-.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch99: kvm-failover-Remove-unused-parameter.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch100: kvm-failover-Remove-external-partially_hotplugged-proper.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch101: kvm-failover-qdev_device_add-returns-err-or-dev-set.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch102: kvm-failover-Rename-bool-to-failover_primary_hidden.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch103: kvm-failover-g_strcmp0-knows-how-to-handle-NULL.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch104: kvm-failover-Remove-primary_device_opts.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch105: kvm-failover-remove-standby_id-variable.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch106: kvm-failover-Remove-primary_device_dict.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch107: kvm-failover-Remove-memory-leak.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch108: kvm-failover-simplify-virtio_net_find_primary.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch109: kvm-failover-should_be_hidden-should-take-a-bool.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch110: kvm-failover-Rename-function-to-hide_device.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch111: kvm-failover-virtio_net_connect_failover_devices-does-no.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch112: kvm-failover-Rename-to-failover_find_primary_device.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch113: kvm-failover-simplify-qdev_device_add-failover-case.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch114: kvm-failover-simplify-qdev_device_add.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch115: kvm-failover-make-sure-that-id-always-exist.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch116: kvm-failover-remove-failover_find_primary_device-error-p.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch117: kvm-failover-split-failover_find_primary_device_id.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch118: kvm-failover-We-don-t-need-to-cache-primary_device_id-an.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch119: kvm-failover-Caller-of-this-two-functions-already-have-p.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch120: kvm-failover-simplify-failover_unplug_primary.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch121: kvm-failover-Remove-primary_dev-member.patch -# For bz#1819991 - Hostdev type interface with net failover enabled exists in domain xml and doesn't reattach to host after hot-unplug -Patch122: kvm-virtio-net-add-missing-object_unref.patch -# For bz#1926785 - [RFE] AMD Milan - Add KVM/support for EPYC-Milan CPU Model - Fast Train -Patch123: kvm-x86-cpu-Populate-SVM-CPUID-feature-bits.patch -# For bz#1926785 - [RFE] AMD Milan - Add KVM/support for EPYC-Milan CPU Model - Fast Train -Patch124: kvm-i386-Add-the-support-for-AMD-EPYC-3rd-generation-pro.patch -# For bz#1932190 - Timeout when dump the screen from 2nd VGA -Patch125: kvm-qxl-set-qxl.ssd.dcl.con-on-secondary-devices.patch -# For bz#1932190 - Timeout when dump the screen from 2nd VGA -Patch126: kvm-qxl-also-notify-the-rendering-is-done-when-skipping-.patch -# For bz#1935071 - CVE-2021-20263 virt:8.4/qemu-kvm: QEMU: virtiofsd: 'security.capabilities' is not dropped with xattrmap option [rhel-av-8] -Patch127: kvm-virtiofsd-Save-error-code-early-at-the-failure-calls.patch -# For bz#1935071 - CVE-2021-20263 virt:8.4/qemu-kvm: QEMU: virtiofsd: 'security.capabilities' is not dropped with xattrmap option [rhel-av-8] -Patch128: kvm-virtiofs-drop-remapped-security.capability-xattr-as-.patch -# For bz#1927530 - RHEL8 Hypervisor - OVIRT - Issues seen on a virtualization guest with direct passthrough LUNS pausing when a host gets a Thin threshold warning -Patch129: kvm-scsi-disk-move-scsi_handle_rw_error-earlier.patch -# For bz#1927530 - RHEL8 Hypervisor - OVIRT - Issues seen on a virtualization guest with direct passthrough LUNS pausing when a host gets a Thin threshold warning -Patch130: kvm-scsi-disk-do-not-complete-requests-early-for-rerror-.patch -# For bz#1927530 - RHEL8 Hypervisor - OVIRT - Issues seen on a virtualization guest with direct passthrough LUNS pausing when a host gets a Thin threshold warning -Patch131: kvm-scsi-introduce-scsi_sense_from_errno.patch -# For bz#1927530 - RHEL8 Hypervisor - OVIRT - Issues seen on a virtualization guest with direct passthrough LUNS pausing when a host gets a Thin threshold warning -Patch132: kvm-scsi-disk-pass-SCSI-status-to-scsi_handle_rw_error.patch -# For bz#1927530 - RHEL8 Hypervisor - OVIRT - Issues seen on a virtualization guest with direct passthrough LUNS pausing when a host gets a Thin threshold warning -Patch133: kvm-scsi-disk-pass-guest-recoverable-errors-through-even.patch -# For bz#1936948 - CVE-2021-20221 virt:av/qemu-kvm: qemu: out-of-bound heap buffer access via an interrupt ID field [rhel-av-8.4.0] -Patch134: kvm-hw-intc-arm_gic-Fix-interrupt-ID-in-GICD_SGIR-regist.patch -# For bz#1934158 - Windows guest looses network connectivity when NIC was configured with static IP -Patch135: kvm-i386-acpi-restore-device-paths-for-pre-5.1-vms.patch -# For bz#1937004 - vhost-user-blk server endianness and input validation fixes -Patch136: kvm-vhost-user-blk-fix-blkcfg-num_queues-endianness.patch -# For bz#1937004 - vhost-user-blk server endianness and input validation fixes -Patch137: kvm-block-export-fix-blk_size-double-byteswap.patch -# For bz#1937004 - vhost-user-blk server endianness and input validation fixes -Patch138: kvm-block-export-use-VIRTIO_BLK_SECTOR_BITS.patch -# For bz#1937004 - vhost-user-blk server endianness and input validation fixes -Patch139: kvm-block-export-fix-vhost-user-blk-export-sector-number.patch -# For bz#1937004 - vhost-user-blk server endianness and input validation fixes -Patch140: kvm-block-export-port-virtio-blk-discard-write-zeroes-in.patch -# For bz#1937004 - vhost-user-blk server endianness and input validation fixes -Patch141: kvm-block-export-port-virtio-blk-read-write-range-check.patch +Patch0004: 0004-Initial-redhat-build.patch +Patch0005: 0005-Enable-disable-devices-for-RHEL.patch +Patch0006: 0006-Machine-type-related-general-changes.patch +Patch0007: 0007-Add-aarch64-machine-types.patch +Patch0008: 0008-Add-ppc64-machine-types.patch +Patch0009: 0009-Add-s390x-machine-types.patch +Patch0010: 0010-Add-x86_64-machine-types.patch +Patch0011: 0011-Enable-make-check.patch +Patch0012: 0012-vfio-cap-number-of-devices-that-can-be-assigned.patch +Patch0013: 0013-Add-support-statement-to-help-output.patch +Patch0014: 0014-globally-limit-the-maximum-number-of-CPUs.patch +Patch0015: 0015-Use-qemu-kvm-in-documentation-instead-of-qemu-system.patch +Patch0016: 0016-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch +Patch0017: 0017-BZ1653590-Require-at-least-64kiB-pages-for-downstrea.patch +Patch0018: 0018-block-Versioned-x-blockdev-reopen-API-with-feature-f.patch BuildRequires: wget BuildRequires: rpm-build @@ -432,6 +230,7 @@ BuildRequires: pkgconfig(gbm) %endif BuildRequires: perl-Test-Harness +BuildRequires: libslirp-devel Requires: qemu-kvm-core = %{epoch}:%{version}-%{release} @@ -479,15 +278,6 @@ emulation for the KVM hypervisor. qemu-kvm acts as a virtual machine monitor together with the KVM kernel modules, and emulates the hardware for a full system such as a PC and its associated peripherals. -%package -n qemu-kiwi -Summary: qemu-kiwi components -Requires: qemu-kvm-common = %{epoch}:%{version}-%{release} - -%description -n qemu-kiwi -qemu-kiwi is a version of qemu-kvm with a restricted set of features -intended for use by specific applications. -It's experimental and unsupported. - %package -n qemu-kvm-docs Summary: qemu-kvm documentation @@ -635,29 +425,17 @@ This package provides opengl support. %prep -%setup -n qemu-%{version}%{?rcversion} -# Remove slirp content in scratchbuilds because it's being applyed as a patch -rm -fr slirp -mkdir slirp +%if 0%{?rcversion} +%setup -n qemu-%{version}-%{?rcversion} +%else +%setup -n qemu-%{version} +%endif %autopatch -p1 %global qemu_kvm_build qemu_kvm_build -%global qemu_kiwi_build qemu_kiwi_src/build - -%ifnarch %{power64} -# XXX: ugly hack to copy source tree into a new folder. -# it allows to build qemu-kiwi without touching the original source tree. -# This is required as the build isolation is not 100% as we also have to -# change the source tree when building qemu-kiwi. And, when we do that, -# calling "make check" on qemu-kvm see that change and behaves baddly. -# Newer version of qemu allow us to create a better sollution, and this -# hack can be dropped. -cp -fpr . ../qemu_kiwi_src -mv ../qemu_kiwi_src ./qemu_kiwi_src -mkdir -p %{qemu_kiwi_build} -%endif mkdir -p %{qemu_kvm_build} + %build %global buildarch %{kvm_target}-softmmu @@ -682,6 +460,8 @@ buildldflags="VL_LDFLAGS=-Wl,--build-id" --disable-bzip2 \\\ --disable-cap-ng \\\ --disable-capstone \\\ + --disable-cfi \\\ + --disable-cfi-debug \\\ --disable-cloop \\\ --disable-cocoa \\\ --disable-coroutine-pool \\\ @@ -694,8 +474,10 @@ buildldflags="VL_LDFLAGS=-Wl,--build-id" --disable-dmg \\\ --disable-docs \\\ --disable-fdt \\\ + --disable-fuse \\\ + --disable-fuse-lseek \\\ --disable-gcrypt \\\ - --disable-git-update \\\ + --disable-gio \\\ --disable-glusterfs \\\ --disable-gnutls \\\ --disable-gtk \\\ @@ -718,6 +500,7 @@ buildldflags="VL_LDFLAGS=-Wl,--build-id" --disable-linux-io-uring \\\ --disable-linux-user \\\ --disable-live-block-migration \\\ + --disable-lto \\\ --disable-lzfse \\\ --disable-lzo \\\ --disable-malloc-trim \\\ @@ -725,6 +508,7 @@ buildldflags="VL_LDFLAGS=-Wl,--build-id" --disable-modules \\\ --disable-module-upgrades \\\ --disable-mpath \\\ + --disable-multiprocess \\\ --disable-netmap \\\ --disable-nettle \\\ --disable-numa \\\ @@ -745,6 +529,7 @@ buildldflags="VL_LDFLAGS=-Wl,--build-id" --disable-sdl-image \\\ --disable-seccomp \\\ --disable-sheepdog \\\ + --disable-slirp \\\ --disable-smartcard \\\ --disable-snappy \\\ --disable-sparse \\\ @@ -783,7 +568,8 @@ buildldflags="VL_LDFLAGS=-Wl,--build-id" --disable-xen-pci-passthrough \\\ --disable-xfsctl \\\ --disable-xkbcommon \\\ - --disable-zstd + --disable-zstd \\\ + --with-git-submodules=ignore pushd %{qemu_kvm_build} ../configure \ @@ -854,6 +640,7 @@ pushd %{qemu_kvm_build} --enable-rdma \ %endif --enable-seccomp \ + --enable-slirp=system \ --enable-snappy \ %if 0%{have_spice} --enable-smartcard \ @@ -907,117 +694,25 @@ make V=1 %{?_smp_mflags} $buildldflags # Setup back compat qemu-kvm binary %{__python3} scripts/tracetool.py --backend dtrace --format stap \ --group=all --binary %{_libexecdir}/qemu-kvm --probe-prefix qemu.kvm \ - trace/trace-events-all > qemu-kvm.stp + trace/trace-events-all qemu-kvm.stp %{__python3} scripts/tracetool.py --backends=dtrace --format=log-stap \ --group=all --binary %{_libexecdir}/qemu-kvm --probe-prefix qemu.kvm \ - trace/trace-events-all > qemu-kvm-log.stp + trace/trace-events-all qemu-kvm-log.stp %{__python3} scripts/tracetool.py --backend dtrace --format simpletrace-stap \ --group=all --binary %{_libexecdir}/qemu-kvm --probe-prefix qemu.kvm \ - trace/trace-events-all > qemu-kvm-simpletrace.stp + trace/trace-events-all qemu-kvm-simpletrace.stp cp -a %{kvm_target}-softmmu/qemu-system-%{kvm_target} qemu-kvm gcc %{SOURCE6} $RPM_OPT_FLAGS $RPM_LD_FLAGS -o ksmctl gcc %{SOURCE35} $RPM_OPT_FLAGS $RPM_LD_FLAGS -o udev-kvm-check - -popd -echo "Starting qemu-kiwi build" - -pushd %{qemu_kiwi_build} -# XXX: removing QXL and CONFIG_TPM.* mak configuration, -# which causes problem with the config options used by qemu-kiwi. -# Ideally we should be able to do this at configure time. -find ../default-configs -name "*-rh-devices.mak" \ - -exec sed -i '/CONFIG_QXL=/d' {} \; -find ../default-configs -name "*-rh-devices.mak" \ - -exec sed -i '/CONFIG_TPM.*=/d' {} \; - -../configure \ - --prefix="%{_prefix}" \ - --libdir="%{_libdir}" \ - --sysconfdir="%{_sysconfdir}" \ - --interp-prefix=%{_prefix}/qemu-%M \ - --localstatedir="%{_localstatedir}" \ - --libexecdir="%{_libexecdir}" \ - --extra-ldflags="-Wl,--build-id -Wl,-z,relro -Wl,-z,now" \ - --extra-cflags="%{optflags}" \ - --with-pkgversion="%{name}-%{version}-%{release}" \ - --with-suffix="%{name}" \ - --firmwarepath=%{_prefix}/share/qemu-firmware \ - --meson="%{__meson}" \ - --target-list="%{buildarch}" \ - --block-drv-rw-whitelist=%{block_drivers_list} \ - --audio-drv-list= \ - --block-drv-ro-whitelist=vmdk,vhdx,vpc,https,ssh \ - --with-coroutine=ucontext \ - --with-git=git \ - --tls-priority=@QEMU,SYSTEM \ - %{disable_everything} \ - --enable-attr \ -%ifarch %{ix86} x86_64 - --enable-avx2 \ -%endif - --enable-cap-ng \ - --enable-coroutine-pool \ - --enable-debug-info \ -%if 0%{have_fdt} - --enable-fdt \ -%endif - --enable-kvm \ -%ifarch x86_64 - --enable-libpmem \ -%endif - --enable-linux-aio \ - --enable-libudev \ - --enable-malloc-trim \ - --enable-mpath \ -%ifnarch s390x - --enable-numa \ -%endif - --enable-pie \ - --enable-seccomp \ - --enable-system \ - --enable-tcg \ - --enable-trace-backend=dtrace \ - --enable-vhost-kernel \ - --enable-vhost-net \ - --enable-vhost-user \ - --enable-vhost-user-blk-server \ - --enable-vhost-vdpa \ - --enable-vhost-vsock \ - --enable-werror \ - --enable-xkbcommon \ - --without-default-devices - - -echo "qemu-kiki config-host.mak contents:" -echo "===" -cat config-host.mak -echo "===" - -make V=1 %{?_smp_mflags} $buildldflags - -%{__python3} scripts/tracetool.py --backend dtrace --format stap \ - --group=all --binary %{_libexecdir}/qemu-kiwi --probe-prefix qemu.kvm \ - trace/trace-events-all > qemu-kiwi.stp - -%{__python3} scripts/tracetool.py --backends=dtrace --format=log-stap \ - --group=all --binary %{_libexecdir}/qemu-kiwi --probe-prefix qemu.kvm \ - trace/trace-events-all > qemu-kiwi-log.stp - -%{__python3} scripts/tracetool.py --backend dtrace --format simpletrace-stap \ - --group=all --binary %{_libexecdir}/qemu-kiwi --probe-prefix qemu.kvm \ - trace/trace-events-all > qemu-kiwi-simpletrace.stp - -cp -a %{kvm_target}-softmmu/qemu-system-%{kvm_target} qemu-kiwi %endif popd %install pushd %{qemu_kvm_build} - %define _udevdir %(pkg-config --variable=udevdir udev) %define _udevrulesdir %{_udevdir}/rules.d @@ -1218,11 +913,16 @@ rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/npcm7xx_bootrom.bin rm -rf ${RPM_BUILD_ROOT}%{_libdir}/qemu-kvm/ui-spice-app.so +# Remove virtfs-proxy-helper files +rm -rf ${RPM_BUILD_ROOT}%{_libexecdir}/virtfs-proxy-helper +rm -rf ${RPM_BUILD_ROOT}%{_mandir}/man1/virtfs-proxy-helper* + %ifarch s390x # Use the s390-ccw.img that we've just built, not the pre-built one install -m 0644 pc-bios/s390-ccw/s390-ccw.img $RPM_BUILD_ROOT%{_datadir}/%{name}/ %else rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}/s390-netboot.img + rm -rf ${RPM_BUILD_ROOT}%{_libdir}/qemu-kvm/hw-s390x-virtio-gpu-ccw.so %endif %ifnarch x86_64 @@ -1316,17 +1016,11 @@ rm -rf $RPM_BUILD_ROOT%{qemudocdir}/interop/.buildinfo rm -rf $RPM_BUILD_ROOT%{qemudocdir}/system/.buildinfo rm -rf $RPM_BUILD_ROOT%{qemudocdir}/tools/.buildinfo rm -rf $RPM_BUILD_ROOT%{qemudocdir}/user/.buildinfo +rm -rf $RPM_BUILD_ROOT%{qemudocdir}/devel/.buildinfo +rm -rf $RPM_BUILD_ROOT%{qemudocdir}/.buildinfo # Remove spec rm -rf $RPM_BUILD_ROOT%{qemudocdir}/specs - -popd - -pushd %{qemu_kiwi_build} -install -m 0755 %{kvm_target}-softmmu/qemu-system-%{kvm_target} $RPM_BUILD_ROOT%{_libexecdir}/qemu-kiwi -install -m 0644 qemu-kiwi.stp $RPM_BUILD_ROOT%{_datadir}/systemtap/tapset/ -install -m 0644 qemu-kiwi-log.stp $RPM_BUILD_ROOT%{_datadir}/systemtap/tapset/ -install -m 0644 qemu-kiwi-simpletrace.stp $RPM_BUILD_ROOT%{_datadir}/systemtap/tapset/ popd %check @@ -1335,11 +1029,6 @@ echo "Testing qemu-kvm-build" export DIFF=diff; make check V=1 popd -echo "Testing qemu-kiwi" -pushd %{qemu_kiwi_build} -export DIFF=diff; make check V=1 -popd - %post -n qemu-kvm-common %systemd_post ksm.service %systemd_post ksmtuned.service @@ -1389,6 +1078,10 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %files -n qemu-kvm-docs %defattr(-,root,root) %dir %{qemudocdir} +%doc %{qemudocdir}/genindex.html +%doc %{qemudocdir}/search.html +%doc %{qemudocdir}/objects.inv +%doc %{qemudocdir}/searchindex.js %doc %{qemudocdir}/README.rst %doc %{qemudocdir}/COPYING %doc %{qemudocdir}/COPYING.LIB @@ -1400,6 +1093,8 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %doc %{qemudocdir}/system/* %doc %{qemudocdir}/tools/* %doc %{qemudocdir}/user/* +%doc %{qemudocdir}/devel/* +%doc %{qemudocdir}/_static/* %files -n qemu-kvm-common %defattr(-,root,root) @@ -1498,16 +1193,11 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %{_libdir}/qemu-kvm/hw-usb-redirect.so %endif %{_libdir}/qemu-kvm/hw-display-virtio-gpu.so -%ifnarch s390x +%ifarch s390x + %{_libdir}/qemu-kvm/hw-s390x-virtio-gpu-ccw.so +%else %{_libdir}/qemu-kvm/hw-display-virtio-gpu-pci.so %endif - -%files -n qemu-kiwi -%defattr(-,root,root) -%{_libexecdir}/qemu-kiwi -%{_datadir}/systemtap/tapset/qemu-kiwi.stp -%{_datadir}/systemtap/tapset/qemu-kiwi-log.stp -%{_datadir}/systemtap/tapset/qemu-kiwi-simpletrace.stp %endif %files -n qemu-img @@ -1574,6 +1264,10 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %endif %changelog +* Fri Apr 30 2021 Miroslav Rezanina - 6.0.0-1 +- Rebase to QEMU 6.0 +- Resolves: bz#1872569 + * Mon Apr 26 2021 Miroslav Rezanina - 5.2.0-16 - kvm-Limit-build-on-Power-to-qemu-img-and-qemu-ga-only.patch [bz#1944056] - Resolves: bz#1944056 @@ -1723,8 +1417,7 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : - Resolves: bz#1918968 ([incremental_backup] qemu deadlock after poweroff in guest during backup in nbd_export_close_all()) - -* Fri Feb 12 2021 Miroslav Rezanina - 5.2.0-6.el8 +* Tue Feb 09 2021 Eduardo Lima (Etrunko) - 5.2.0-6.el8 - kvm-scsi-fix-device-removal-race-vs-IO-restart-callback-.patch [bz#1854811] - kvm-tracetool-also-strip-l-and-ll-from-systemtap-format-.patch [bz#1907264] - kvm-redhat-moving-all-documentation-files-to-qemu-kvm-do.patch [bz#1881170 bz#1924766] diff --git a/rpminspect.yaml b/rpminspect.yaml new file mode 100644 index 0000000..3b74418 --- /dev/null +++ b/rpminspect.yaml @@ -0,0 +1,5 @@ +--- +elf: + exclude_path:(^/usr/share/qemu-kvm/s390-ccw.img$)|(^/usr/share/qemu-kvm/s390-netboot.img$) +inspections: + badfuncs: off diff --git a/sources b/sources index 6a86af7..c713614 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (qemu-5.2.0.tar.xz) = bddd633ce111471ebc651e03080251515178808556b49a308a724909e55dac0be0cc0c79c536ac12d239678ae94c60100dc124be9b9d9538340c03a2f27177f3 +SHA512 (qemu-6.0.0.tar.xz) = ee3ff00aebec4d8891d2ff6dabe4e667e510b2a4fe3f6190aa34673a91ea32dcd2db2e9bf94c2f1bf05aa79788f17cfbbedc6027c0988ea08a92587b79ee05e4