diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 40277dc18..cfc308429 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,28 +40,33 @@ jobs: - scelbi 3b2 i701 i704 i7010 i7070 i7080 i7090 sigma uc15 i650 sel32 intel-mds ibm1130 steps: - uses: actions/checkout@v4 - ## Workaround for remnant symlinks in /usr/local pointing back to - ## macOS frameworks. - ## - ## Future: Will have to keep an eye on SDL_ttf's Python dependency - ## so that the correct/appropriate Python version is removed. - - name: Remnant symlink cleanup (macOS) + + ## Nuke homebrew and start with a clean instance: + - name: Reinstall HomeBrew (macOS) if: ${{runner.os == 'macOS'}} run: | - brew unlink python@3 || true - brew uninstall --ignore-dependencies python@3 || true - brew unlink python@3.12 || true - brew uninstall --ignore-dependencies python@3.12 || true - for f in $(find /usr/local/bin -type l -print); do \ - (readlink $f | grep -q -s "/Library") && echo Removing "$f" && rm -f "$f"; \ - done || exit 0 + /usr/bin/sudo /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall.sh)" + [ -d /opt/homebrew ] && ( sudo rm -rf /opt/homebrew/* || true ) + [ -d /usr/local ] && ( sudo rm -rf /usr/local/* || true ) + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" + ## Install our regular dependencies. - name: Install dependencies (macOS) if: ${{runner.os == 'macOS'}} - run: sh -ex .travis/deps.sh osx + run: | + sh -ex .travis/deps.sh osx + - name: Install dependencies (Linux) if: ${{runner.os == 'Linux'}} run: sh -ex .travis/deps.sh linux + + - name: libslirp module + run: | + git submodule sync + git submodule set-url -- libslirp https://gitlab.freedesktop.org/bscottmichel/libslirp-minimal.git + git submodule set-branch --branch incr-minimal libslirp + git submodule update --init --recursive --remote + - name: makefile build env: SIM: ${{matrix.simulators}} diff --git a/.github/workflows/cmake-builds.yml b/.github/workflows/cmake-builds.yml index d489f5987..8a715eafb 100644 --- a/.github/workflows/cmake-builds.yml +++ b/.github/workflows/cmake-builds.yml @@ -24,6 +24,14 @@ jobs: run: | sh -ex .travis/deps.sh linux sudo apt install -ym ninja-build + + - name: libslirp module + run: | + git submodule sync + git submodule set-url -- libslirp https://gitlab.freedesktop.org/bscottmichel/libslirp-minimal.git + git submodule set-branch --branch incr-minimal libslirp + git submodule update --init --recursive --remote + - name: cmake-builder.sh run: | cmake/cmake-builder.sh --config Release --flavor ninja --lto --notest --parallel --verbose --cpack_suffix x86_64-${{matrix.os}} @@ -47,7 +55,7 @@ jobs: cmake-macOS: - name: macOS 12+ + name: macOS runs-on: ${{ matrix.os }} strategy: #- @@ -57,8 +65,10 @@ jobs: # that the build produces. # # (*) "artefact" for the rest of the Anglosphere - + # + # As of 18 NOV 2024, Github deprecated macos-12. matrix: - os: [macos-12, macos-13, macos-14] + os: [macos-13, macos-14] env: CPACK_SUFFIX: ${{matrix.os != 'macos-14' && 'x86_64' || 'm1'}}.${{matrix.os}} @@ -66,23 +76,24 @@ jobs: steps: - uses: actions/checkout@v4 - ## Workaround for remnant symlinks in /usr/local pointing back to - ## macOS frameworks. - ## - ## Future: Will have to keep an eye on SDL_ttf's Python dependency - ## so that the correct/appropriate Python version is removed. - - name: Remnant symlink cleanup - run: | - brew unlink python@3 || true - brew uninstall --ignore-dependencies python@3 || true - brew unlink python@3.12 || true - brew uninstall --ignore-dependencies python@3.12 || true - for f in $(find /usr/local/bin -type l -print); do \ - (readlink $f | grep -q -s "/Library") && echo Removing "$f" && rm -f "$f"; \ - done || exit 0 + ## Nuke homebrew and start with a clean instance. + - name: Reinstall HomeBrew (macOS) + run: | + /usr/bin/sudo /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall.sh)" + [ -d /opt/homebrew ] && ( sudo rm -rf /opt/homebrew/* || true ) + [ -d /usr/local ] && ( sudo rm -rf /usr/local/* || true ) + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" - name: Install dependencies - run: sh -ex .travis/deps.sh osx + run: | + sh -ex .travis/deps.sh osx + + - name: libslirp module + run: | + git submodule sync + git submodule set-url -- libslirp https://gitlab.freedesktop.org/bscottmichel/libslirp-minimal.git + git submodule set-branch --branch incr-minimal libslirp + git submodule update --init --recursive --remote - name: cmake-builder.sh run: | @@ -123,6 +134,12 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@v4 + - name: libslirp module + run: | + git submodule sync + git submodule set-url -- libslirp https://gitlab.freedesktop.org/bscottmichel/libslirp-minimal.git + git submodule set-branch --branch incr-minimal libslirp + git submodule update --init --recursive --remote - name: Install v141_xp (XP toolkit) and build SIMH shell: pwsh run: | @@ -189,8 +206,25 @@ jobs: cmake-vs2022: name: VS 2022 Win10 native VCPKG runs-on: windows-latest + strategy: + #- + # The CMake builds produce artifacts (*) and the runner image's name is + # used in the artifact's name, simh-4.1.0-x86_64-ubuntu-20.04.deb. + # Consequently, each runner image is enumerated for each artifact (*) + # that the build produces. + # + # (*) "artefact" for the rest of the Anglosphere + #- + matrix: + build: [vs2022, vs2022-x64] steps: - uses: actions/checkout@v4 + - name: libslirp module + run: | + git submodule sync + git submodule set-url -- libslirp https://gitlab.freedesktop.org/bscottmichel/libslirp-minimal.git + git submodule set-branch --branch incr-minimal libslirp + git submodule update --init --recursive --remote - name: vs2022 build shell: pwsh run: | @@ -206,34 +240,36 @@ jobs: Push-Location $env:VCPKG_ROOT git pull Pop-Location - ./cmake/cmake-builder.ps1 -flavor vs2022 -config Release -clean -lto -verbose -notest -cpack_suffix win32-native + ./cmake/cmake-builder.ps1 -flavor ${{matrix.build}} -config Release -clean -lto -verbose ` + -notest ` + -cpack_suffix ${{matrix.build}} - name: SIMH simulator suite test shell: pwsh run: | - ./cmake/cmake-builder.ps1 -flavor vs2022 -config Release -testOnly + ./cmake/cmake-builder.ps1 -flavor ${{matrix.build}} -config Release -testOnly ## Install isn't strictly necessary, but it's a good way to see what dependencies ## (IMPORTED_RUNTIME_ARTIFACTS) get installed. - name: Install shell: pwsh run: | - cmake/cmake-builder.ps1 -config Release -flavor vs2022 -installOnly + cmake/cmake-builder.ps1 -config Release -flavor ${{matrix.build}} -installOnly - name: SIMH packaging shell: pwsh run: | - cd cmake\build-vs2022 + cd cmake\build-${{matrix.build}} cpack -G "NSIS;WIX;ZIP" -C Release - name: Upload ZIP uses: actions/upload-artifact@v4 with: - name: simh-4.1.0-win32-vs2022.zip - path: cmake/build-vs2022/simh-4.1.0-win32-native.zip + name: simh-4.1.0-${{matrix.build}}.zip + path: cmake/build-${{matrix.build}}/simh-4.1.0-${{matrix.build}}.zip - name: Upload EXE installer uses: actions/upload-artifact@v4 with: - name: simh-4.1.0-win32-vs2022.exe - path: cmake/build-vs2022/simh-4.1.0-win32-native.exe + name: simh-4.1.0-${{matrix.build}}.exe + path: cmake/build-${{matrix.build}}/simh-4.1.0-${{matrix.build}}.exe - name: Upload MSI installer uses: actions/upload-artifact@v4 with: - name: simh-4.1.0-win32-vs2022.msi - path: cmake/build-vs2022/simh-4.1.0-win32-native.msi + name: simh-4.1.0-${{matrix.build}}.msi + path: cmake/build-${{matrix.build}}/simh-4.1.0-${{matrix.build}}.msi diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..59262cc6c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "libslirp"] + path = libslirp + url = https://ourdoodlehouse.org/gitlab/scott/libslirp-minimal.git + branch = incr-minimal diff --git a/.travis/deps.sh b/.travis/deps.sh index dc08ec7fc..69449108b 100755 --- a/.travis/deps.sh +++ b/.travis/deps.sh @@ -30,6 +30,19 @@ install_linux() { sudo apt-get install -ym cmake cmake-data } +install_mingw32() { + ## Doesn't have libpcap or cmake's extra modules. Not that this + ## makes much of a difference. + pacman -S --needed mingw-w64-i686-ninja \ + mingw-w64-i686-cmake \ + mingw-w64-i686-gcc \ + mingw-w64-i686-make \ + mingw-w64-i686-pcre \ + mingw-w64-i686-freetype \ + mingw-w64-i686-SDL2 \ + mingw-w64-i686-SDL2_ttf +} + install_mingw64() { pacman -S --needed mingw-w64-x86_64-ninja \ mingw-w64-x86_64-cmake \ @@ -71,7 +84,7 @@ install_clang64() { case "$1" in - osx|macports|linux|mingw64|ucrt64|clang64) + osx|macports|linux|mingw32|mingw64|ucrt64|clang64) install_"$1" ;; arch-linux) diff --git a/0readme_ethernet.txt b/0readme_ethernet.txt index 62357a7ca..61abad7b7 100644 --- a/0readme_ethernet.txt +++ b/0readme_ethernet.txt @@ -50,6 +50,107 @@ bridge it with a physical network interface). The following steps were performed to get a working SIMH vax simulator sharing a physical NIC and allowing Host<->SIMH vax communications: +Linux (iproute2 utilities, /etc/network/interfaces): + + You have the iproute2 utility family installed if typing "ip addr show" + at the shell prompt shows you a list of network interfaces and their + associated IP addresses: + + $ ip addr show + 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + inet 127.0.0.1/8 scope host lo + valid_lft forever preferred_lft forever + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever + 2: eth0: mtu 1500 qdisc mq state UP group default qlen 1000 + ... + + The following example /etc/network/interfaces script creates a bridge + interface "br-main" and attaches the "eth0" and "tap0" interfaces to + the bridge. + + Linux networking reads the /etc/network/intefaces script to configure your + network at boot time, so this bridge is "one and done". The tap0 interface + will persist until such time as you decide it's no longer useful and remove + the bridge configuration from the /etc/network/interfaces script. + + ## /etc/network/interfaces bridge configuration example: + ## + ## THIS IS AN EXAMPLE CONFIGURATION. ADAPT IT TO FIT AND CONFORM + ## TO YOUR NETWORK CONFIGURATION. + + auto lo br-main # Configure lo0, br-main at boot time + + iface lo inet loopback + + iface br-main inet manual + ##------------------------------------------------------------- + ## If you don't use iptables to firewall your Linux, you can + ## comment out the next line. + ##------------------------------------------------------------- + pre-up modprobe br_netfilter + pre-up ip link add name br-main type bridge + up ip link set dev br-main up + ##------------------------------------------------------------- + ## Static IPv4 address configuration (you don't use DHCP): + ## + ## Replace HOSTIP4/NETBITS4 with your IPv4 address and bits in + ## your network mask, e.g., 192.168.1.20/24. + ## + ## Replace GATEWAY4 with your router's IPv4 address. + ## + ## If you use DHCP for IPv4 address configuration, comment out + ## the next two lines. + ##------------------------------------------------------------- + up ip address add HOSTIP4/NETBITS4 dev br-main + up ip route append default via GATEWAY4 dev br-main + ##------------------------------------------------------------- + ## IPv6: Replace HOSTIP6/NETBITS6 with your IPv6 address and + ## bits in your network mask, e.g., 2001:db8::/64. + ## + ## Replace GATEWAY6 with your router's IPv6 address. + ## + ## If your network sends Router Advertisements, comment out the + ## next two lines. + ##------------------------------------------------------------- + up ip address HOSTIP6/NETBITS6 dev br-main + up ip route append ::0 via GATEWAY6 + ##------------------------------------------------------------- + ## DHCP address configuration: + ## + ## If you prefer static IPv4 configuration, comment out the next + ## line and refer above. + ##------------------------------------------------------------- + up dhclient br-main + ##------------------------------------------------------------- + ## Attach eth0 and tap0: + ##------------------------------------------------------------- + up ifup eth0 + up ifup tap0 + ##------------------------------------------------------------- + ## If you don't use iptables to firewall your Linux, you can + ## comment out the next line. + ##------------------------------------------------------------- + post-up echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables + pre-down ifdown tap0 + pre-down ifdown eth0 + down ip link del dev br-main + + iface eth0 inet manual + up ip link set eth0 master br-main + down ip link set eth0 nomaster + + iface tap0 inet manual + pre-up ip tuntap add tap0 mode tap user USER + up ip link set tap0 master br-main + down ip link set dev tap0 nomaster + post-down ip link del dev tap0 + ## /etc/network/interfaces bridge configuration example ends... + + When you run the simulator: "attach xq tap:tap0" + + Linux (Ubuntu 10.04): apt-get install make apt-get install libpcap-dev @@ -181,37 +282,127 @@ OSX: install the net/vde2 package. ------------------------------------------------------------------------------- -Another alternative to direct pcap and tun/tap networking on all environments is -NAT (SLiRP) networking. NAT networking is limited to only IP network protocols -so DECnet, LAT and Clusting can't work on a NAT connected interface, but this may -be the easiest solution for many folks. +NAT (libslirp) networking is another network alternative to direct pcap and +tun/tap networking on all environments. NAT (libslirp) is always available as a +network option. + +NAT is limited to IP network protocols only, so DECnet, LAT and Clusting can't +work on a NAT-connected interface. + +Basic usage: sim> attach xq nat: -The simulator can use static IP addresses of 10.0.2.4 thru 10.0.2.14 with a -netmask of 255.255.255.0 and a gateway of 10.0.2.2 and a nameserver of 10.0.2.3. -If the simulated machine uses DHCP it will get the address 10.0.2.15. Various -NAT based parameters can be configured on the attach command. HELP XQ ATTACH -will provide useful information. Host to simulator connectivity can be -achieved for a simulator which gets its IP address via DHCP with the following -command: +This attaches NAT to the VAX xq Ethernet interface with the following default +IP parameters: + + - Simulator's IP: 10.0.2.4 - 10.0.2.14 are available as static IPv4 + addresses. DHCP is also available with IPv4 addresses starting at + 10.0.2.15. + - Gateway/Router IPv4 address: 10.0.2.2 (i.e., the simulator's O/S + should use this as the default route.) + - DNS resolver's IPv4 address: 10.0.2.3 + +Advanced usage: + + sim> attach xq nat:network=172.16.1.4/24,gateway=172.16.1.2,dns=172.16.1.3 + + This example overrides the NAT default and uses the following parameters, + where the NAT network uses the set of IPv4 addresses belonging to the + 172.16.1.0/24 network: + + - "network": Specifies the IPv4 aaddress nd network mask (CIDR format, in bits) + for the simulator interface. This basically tells libslirp which IPv4 address + the simulator uses (but you still have to configure the simulator's interface + with the required IPv4 configuration.) + - "gateway": Specifies the default router's IPv4 address. + - "dns": The DNS resolver's IPv4 address + +Mapping host ports to simulator ports has the general format: + + sim> attach intf nat:tcp=:: + +For example, to redirect the simulator's telnet port (port 23) to the host's +port 2323: + + sim> attach xq nat:tcp=2323:10.0.2.15:23,tcp=2121:10.0.2.15:21 + + Note 1: 10.0.2.15 is the first libslirp DHCP-assigned address, so this + example assumes that the VAX simulator uses DHCP to configure the + xq device's IPv4 configuration. + + Note 2: Unless the simulator runs with root or administrator privileges, + ports below 1024 are reserved. Mappings should use host port + numbers greater than 1024. - sim> attach xq nat:tcp=2323:10.0.2.15:23,tcp=2121:10.0.2.15:21 +Users can subsequently telnet to localhost:2323 to reach the simulator via +telnet. -The host computer can telnet to localhost:2323 to reach the simulator via -telnet, etc. +For the PDP10-KL simulator, the following IMP configuration is a useful Turism +starting point: -Additionally NAT based networking is useful to allow host systems with WiFi -networking to a) reach the simulated system and b) allow the simulated system -to reach out to the Internet. + set imp enabled + set imp mac=e2:6c:84:1d:34:a3 + set imp host=192.168.1.100 + set imp ip=192.168.2.4/24 + set imp gw=192.168.2.2 + at imp nat:dns=192.168.2.3,gateway=192.168.2.2,network=192.168.2.0/24,tcp=2023:192.168.2.4:23,tcp=2021:192.168.2.4:21,tcp=9595:192.168.2.4:95 + + Note: Ensure that ITS was built with a <255,255,0,0> network mask in the + PDP-10 KL configuration (See SYSTEM;CONFIG, search for "MCOND KL," and + change NM%IMP's definition following "MCOND KL,".) Then rebuild ITS. + + Rebuilding ITS: https://github.com/PDP-10/its/blob/master/doc/NITS.md + +Connect a SUPDUP client to port 9595 on localhost, such as Putty's SUPDUP +support or the user-maintained SUPDUP client (https://github.com/PDP-10/supdup) +to discover that Today Is A Good Day To Be A Turist. Users can also connect to +localhost:2023 for telnet Turism. (If ITS is unresponsive -- check the KL's +network mask and rebuild ITS if necessary!!!) Note: As mentioned above, NAT networking is specifically capable of providing TCP/IP connectivity. Only expect TCP and UDP traffic to pass through the interface. Do not expect ICMP traffic (ping mostly) to traverse - the NAT boundary. This restriction is a consequence of host platform + past the NAT boundary. This restriction is a consequence of host platform and network limitations regarding direct user mode code generating ICMP packets. +Debugging NAT: If you need to turn on NAT debugging, the following flags exist: + + POLL Outputs poll()/select() activities when libslirp polls the active + sockets for I/O activity. + + SOCKET Trace sockets as they are added and removed from libslirp. + +These debugging flags can only be set after "attach": + + sim> set debug -n "vax-xq.out" + sim> attach xq nat:tcp=2323:10.0.2.15:23,tcp=2121:10.0.2.15:21 + sim> set xq debug=socket;poll + +If you want REALLY verbose output and want to trace NAT's Ethernet traffic, you +have to set that debugging flag before "attach" (the "ether" debug flag is part +of the underlying sim_ether.c Ethernet support, not part of NAT): + + sim> set debug -n "vax-xq.out" + sim> set xq debug=ether + sim> attach xq nat:tcp=2323:10.0.2.15:23,tcp=2121:10.0.2.15:21 + sim> set xq debug=socket;poll + +Internal libslirp debugging is set by the "slirp=" argument to "attach": + + sim> attach xq nat:tcp=2323:10.0.2.15:23,tcp=2121:10.0.2.15:21,slirp=call;misc;error;verbose_call + +where: + + CALL Outputs arguments to libslirp's functions + MISC Outputs generally useful libslirp debugging info + ERROR Outputs error diagnostics when they occur + VERBOSE_CALL Like CALL, but selectively more verbose + ALL All of the above flags + +Once turned on, however, libslirp debugging cannot be turned off until the +simulator exits. ------------------------------------------------------------------------------- diff --git a/CMakeLists.txt b/CMakeLists.txt index 120da3960..1a893bec3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -261,7 +261,12 @@ endif() ## The default runtime output directory is the BIN subdirectory in the source tree's top set(SIMH_LEGACY_INSTALL "${CMAKE_SOURCE_DIR}/BIN") if (WIN32) - string(APPEND SIMH_LEGACY_INSTALL "/Win32") + # MinGW64 environment (MinGW64, Clang64, UCRT64, ...) + if (DEFINED ENV{MSYSTEM}) + string(APPEND SIMH_LEGACY_INSTALL "/$ENV{MSYSTEM}") + else () + string(APPEND SIMH_LEGACY_INSTALL "/Win32") + endif () endif() set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${SIMH_LEGACY_INSTALL}) @@ -365,6 +370,48 @@ if (ENABLE_CPPCHECK) set(CPPCHECK_STATUS "'cppcheck' not installed.") endif () endif () +unset(ROM_STATUS) + +if (NO_DEP_BUILD AND SIMH_BUILD_DEPS) + ## Don't build dependencies. Just wail about them. + message("") + message("Missing SIMH dependencies:") + foreach (dep ${SIMH_BUILD_DEPS}) + message(STATUS " ${dep}") + endforeach() + message("") + message("Please install the above dependencies via your platform package management or") + message("software installation system and reconfigure.") + message("") + message("Also see the .travis/deps.h file for Brew and apt packages installed during") + message("github.com workflow actions.") + message(FATAL_ERROR "Missing dependencies, cannot continue.") + + ## TODO: Assume that these dependencies are optional? +endif () + +if (NOT DEFINED DO_DEPENDENCY_BUILD OR SIMH_BUILD_DEPS) + if (DEFINED DO_DEPENDENCY_BUILD AND NOT DO_DEPENDENCY_BUILD AND SIMH_BUILD_DEPS) + message(FATAL_ERROR "Dependency libraries did not build successfully!!??") + endif() + + if (SIMH_BUILD_DEPS) + message(STATUS "Building dependency libraries as a superbuild") + set(DO_DEPENDENCY_BUILD ON CACHE BOOL "Superbuild flag" FORCE) + else () + set(DO_DEPENDENCY_BUILD OFF CACHE BOOL "Superbuild flag" FORCE) + endif () +else () + set(DO_DEPENDENCY_BUILD ${DO_DEPENDENCY_BUILD} CACHE BOOL "Superbuild flag" FORCE) +endif () + +if (NOT DO_DEPENDENCY_BUILD) + include (add_simulator) + if (WITH_NETWORK AND WITH_SLIRP) + ## Set the "Don't use GLIB" option here so that the libslirp subdirectory sees it. + set(NOGLIB TRUE CACHE BOOL "" FORCE) + add_subdirectory(libslirp) + endif () set(_feature_text "Libraries and features:\n") string(APPEND _feature_text "\n * Build with video/graphics support. ${BUILD_WITH_VIDEO}") @@ -411,47 +458,6 @@ string(APPEND _feature_text "\n") message(STATUS ${_feature_text}) unset(_feature_text) -unset(ROM_STATUS) - -if (NO_DEP_BUILD AND SIMH_BUILD_DEPS) - ## Don't build dependencies. Just wail about them. - message("") - message("Missing SIMH dependencies:") - foreach (dep ${SIMH_BUILD_DEPS}) - message(STATUS " ${dep}") - endforeach() - message("") - message("Please install the above dependencies via your platform package management or") - message("software installation system and reconfigure.") - message("") - message("Also see the .travis/deps.h file for Brew and apt packages installed during") - message("github.com workflow actions.") - message(FATAL_ERROR "Missing dependencies, cannot continue.") - - ## TODO: Assume that these dependencies are optional? -endif () - -if (NOT DEFINED DO_DEPENDENCY_BUILD OR SIMH_BUILD_DEPS) - if (DEFINED DO_DEPENDENCY_BUILD AND NOT DO_DEPENDENCY_BUILD AND SIMH_BUILD_DEPS) - message(FATAL_ERROR "Dependency libraries did not build successfully!!??") - endif() - - if (SIMH_BUILD_DEPS) - message(STATUS "Building dependency libraries as a superbuild") - set(DO_DEPENDENCY_BUILD ON CACHE BOOL "Superbuild flag" FORCE) - else () - set(DO_DEPENDENCY_BUILD OFF CACHE BOOL "Superbuild flag" FORCE) - endif () -else () - set(DO_DEPENDENCY_BUILD ${DO_DEPENDENCY_BUILD} CACHE BOOL "Superbuild flag" FORCE) -endif () - -if (NOT DO_DEPENDENCY_BUILD) - include (add_simulator) - if (WITH_SLIRP) - add_subdirectory(slirp) - endif (WITH_SLIRP) - ## Don't delete yet ## set(Python_ADDITIONAL_VERSIONS 3) ## Don't delete yet ## include(FindPythonInterp) ## Don't delete yet ## if (PYTHONINTERP_FOUND AND PYTHON_VERSION_MAJOR GREATER_EQUAL 3) @@ -508,6 +514,7 @@ else () -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + -DCOMPILE_DEFINITIONS=${COMPILE_DEFINITIONS} INSTALL_COMMAND "" BINARY_DIR ${CMAKE_BINARY_DIR} diff --git a/I650/CMakeLists.txt b/I650/CMakeLists.txt index 3ad491982..aac3c4c9a 100644 --- a/I650/CMakeLists.txt +++ b/I650/CMakeLists.txt @@ -32,6 +32,8 @@ add_simulator(i650 if (WIN32) if (MSVC) set(I650_STACK_FLAG "/STACK:8388608") + elseif (CMAKE_C_COMPILER_ID MATCHES ".*Clang") + set(I650_STACK_FLAG "-Xlinker" "/STACK:8388608") else () set(I650_STACK_FLAG "-Wl,--stack,8388608") endif () diff --git a/PDP10/CMakeLists.txt b/PDP10/CMakeLists.txt index 197c1a30d..4980df15a 100644 --- a/PDP10/CMakeLists.txt +++ b/PDP10/CMakeLists.txt @@ -42,6 +42,7 @@ add_simulator(pdp10 DEFINES VM_PDP10 FEATURE_INT64 + USES_AIO LABEL PDP10 NO_INSTALL TEST pdp10) diff --git a/README-CMake.md b/README-CMake.md index f5778fdd8..d0db86785 100644 --- a/README-CMake.md +++ b/README-CMake.md @@ -3,9 +3,13 @@ - [Build `simh` using CMake](#build-simh-using-cmake) - [Why CMake?](#why-cmake) + - [Quickstart for the Impatient](#quickstart-for-the-impatient) + - [Unix and macOS](#unix-and-macos) + - [Windows](#windows) + - [MinGW64](#mingw64) - [Before You Begin Building...](#before-you-begin-building) - [Toolchains and Tools](#toolchains-and-tools) - - [Ninja: "failed recompaction: Permission denied"](#ninja-file-recompaction-permission-denied) + - [Ninja: "failed recompaction: Permission denied"](#ninja-failed-recompaction-permission-denied) - [Windows XP-compatible/Server 2003 binaries](#windows-xp-compatibleserver-2003-binaries) - [Feature Libraries](#feature-libraries) - [Linux, macOS and MinGW-w64](#linux-macos-and-mingw-w64) @@ -47,12 +51,84 @@ framework. A sample of the supported build environments include: - MS Visual Studio solutions (2015, 2017, 2019, 2022) - IDE build wrappers ([Sublime Text][sublime] and [CodeBlocks][codeblocks]) -Making the Windows build process less complex by automatically downloading, -building and installing dependency feature libraries, and consistent cross -platform support were the initial motivations behind a [CMake][cmake]-based -build infrastructure. Since then, that motivation expanded to supporting a wider -variety of platforms and compiler combinations, streamlining the overall compile -process, enhanced IDE integration and SIMH packaging. +In addition to enabling choices across a diverse set of development +environments, [CMake][cmake] also handles packaging artifacts (artefacts) for +installers and archives. + +## Quickstart for the Impatient + +### Unix and macOS + +```shell +$ git clone https://github.com/open-simh/simh.git +$ cd simh +$ sh .travis/deps.sh linux +$ cmake/cmake-builder.sh --flavor ninja --config Release --target pdp10-kl +$ BIN/pdp10-kl +``` + +- Replace `linux` in `sh .travis/deps.sh linux` with `arch_linux` (Arch Linux), + `osx` (macOS Brew system), or `macports` (macOS MacPorts system). + +- Replace `pdp10-kl` with your preferred or desired simulator, e.g., `vax`, + `pdp11`, etc. + +- You can find the resulting simulator binaries in the BIN/ subdirectory. + +### Windows + +`cmd`-based console: + +```cmd +C:\...> git clone https://github.com/microsoft/vcpkg.git +C:\...> cd vcpkg +C:\...> .\bootstrap-vcpkg.bat +C:\...> set VCPKG_ROOT=%cd% +C:\...> cd .. +C:\...> git clone https://github.com/open-simh/simh.git +C:\...> cd simh +C:\...> cmake\cmake-builder.ps1 vs2022-x64 Release -target pdp10-kl +C:\...> BIN\Win32\Release\pdp10-kl +``` + +PowerShell-based console: + +```powershell +PS> git clone https://github.com/microsoft/vcpkg.git +PS> cd vcpkg; .\bootstrap-vcpkg.bat +PS> $env:VCPKG_ROOT=$(get-location) +PS> cd .. +PS> git clone https://github.com/open-simh/simh.git +PS> cd simh +PS> cmake\cmake-builder.ps1 vs2022-x64 Release -target pdp10-kl +PS> BIN\Win32\Release\pdp10-kl +``` + +Replace `pdp10-kl` with your preferred or desired simulator, e.g., `vax`, +`pdp11`, etc. + +You can find the resulting simulator binaries in the BIN/Win32/_config_ +subdirectory, where _config_ is "Release", "Debug" or "RelWithDebInfo". In the +above examples, _config_ is "Release", i.e., BIN/Win32/Release. + +### MinGW64 + +```shell +$ git clone https://github.com/open-simh/simh.git +$ cd simh +$ sh .travis/deps.sh mingw64 +$ cmake/cmake-builder.sh --flavor ninja --config Release --target pdp10-kl +$ BIN/Win32/pdp10-kl +``` + +- Replace `mingw64` in `sh .travis/deps.sh mingw64` with `clang64`, `ucrt64` or + `mingw32`, consistent with the MinGW64 environment in which you are compiling. + +- Replace `pdp10-kl` with your preferred or desired simulator, e.g., `vax`, + `pdp11`, etc. + +- You can find the resulting simulator binaries in the BIN/`$MSYSTEM` + subdirectory, where `$MSYSTEM` is one of MINGW64, MINGW32, CLANG64 or UCRT64. ## Before You Begin Building... @@ -67,8 +143,7 @@ Before you begin building the simulators, you need the following: builds on Windows. - _Microsoft Visual C/C++_: Visual Studio 2022, 2019, 2017 and 2015 are - supported. The [appveyor CI/CD][appveyor] pipeline builds using these four - Microsoft toolchains in _Release_ and _Debug_ configurations. + supported. - _VS 2022_: The Community Edition can be downloaded from the [Microsoft Visual Studio Community][vs_community] page. @@ -105,12 +180,12 @@ Before you begin building the simulators, you need the following: - _Visual Studio IDE, Developer command or PowerShell console windows_: No additional software installation needed. Microsoft provides `cmake` that can be invoked from the command prompt or from within the VS IDE. - Microsoft has bundled various version of `cmake` into Visual Studio since + Microsoft has bundled various versions of `cmake` into Visual Studio since VS 2015. - Otherwise, install `cmake` using your preferred Windows software package manager, such as [Chocolatey][chocolatey] or [Scoop][scoop]. You can also - [download and install the `cmake` binary distribution][cmake_downloads] + download and install [the `cmake` binary distribution][cmake_downloads] directly. - The [Git source control system][gitscm]. @@ -144,7 +219,7 @@ Before you begin building the simulators, you need the following: - Otherwise, install `git` using your preferred Windows software package manager, such as [Chocolatey][chocolatey] or [Scoop][scoop]. You can also - [download and install the `git` client][gitscm_downloads] directly. + download and install [the `git` client][gitscm_downloads] directly. - GNU Make: @@ -156,8 +231,8 @@ Before you begin building the simulators, you need the following: - Ninja: - [Ninja][ninja] is an optional, but useful/faster parallel build alternative to - Unix Makefiles and Visual Studio's `msbuild`. + [Ninja][ninja] is an optional parallel build alternative to Unix Makefiles and + Visual Studio's `msbuild`. #### Ninja: "failed recompaction: Permission denied" @@ -279,6 +354,12 @@ binaries. $ sudo sh .travis/deps.sh linux ``` + - Linux Arch: + + ```bash + $ sudo sh .travis/deps.sh arch-linux + ``` + - macOS Homebrew: ```bash @@ -299,7 +380,7 @@ binaries. $ .travis/deps.sh mingw64 ``` - - MinGW-w64 UCRT console: + - MinGW-w64 UCRT64 console: ```bash $ echo $MSYSTEM @@ -307,6 +388,14 @@ binaries. $ .travis/deps.sh ucrt64 ``` + - MinGW-w64 CLANG64 console: + + ```bash + $ echo $MSYSTEM + CLANG64 + $ .travis/deps.sh clang64 + ``` + #### Windows: "Legacy" superbuild or `vcpkg` The SIMH CMake infrastructure has two distinct feature library dependency @@ -376,10 +465,10 @@ Setup and Usage: PS C:\...> git clone https://github.com/Microsoft/vcpkg.git PS C:\...> cd vcpkg PS C:\...\vcpkg> .\vcpkg\bootstrap-vcpkg.bat + PS C:\...\vcpkg> $env:VCPKG_ROOT=$(get-location) PS C:\...\vcpkg> cd ..\open-simh PS C:\...\open-simh> ``` - Then set the `VCPKG_ROOT` environment variable to the `vcpkg` installation directory. [^1]: `vcpkg` does not support the `v141_xp` toolkit required to compile Windows XP binaries. Windows XP is a target platform that SIMH can hopefully deprecate diff --git a/build_mingw.bat b/build_mingw.bat deleted file mode 100644 index 7807128e1..000000000 --- a/build_mingw.bat +++ /dev/null @@ -1,19 +0,0 @@ -@echo off -rem Compile all of SIMH using MINGW make and gcc environment -rem -rem The makefile will determine if the needed WinPcap build -rem components are available and the resulting simulators will -rem run with networking support when the WinPcap environment -rem is installed on the running system. -rem -rem Individual simulator sources are in .\simulator_name -rem Individual simulator executables are to .\BIN -rem -rem If needed, define the path for the MINGW bin directory. -rem -gcc -v 1>NUL 2>NUL -if ERRORLEVEL 1 path C:\MinGW\bin;%path% -if not exist BIN mkdir BIN -gcc -v 1>NUL 2>NUL -if ERRORLEVEL 1 echo "MinGW Environment Unavailable" -mingw32-make -f makefile %* diff --git a/build_mingw_ether.bat b/build_mingw_ether.bat deleted file mode 100644 index 5a9771420..000000000 --- a/build_mingw_ether.bat +++ /dev/null @@ -1,6 +0,0 @@ -@echo off -rem Built in Ethernet support (requires WinPcap installed). -rem The normal Windows build always builds with Ethernet support -rem so, this procedure is un-necessary. Just call the normal build -rem -%~p0\build_mingw.bat %* diff --git a/build_mingw_noasync.bat b/build_mingw_noasync.bat deleted file mode 100644 index ca2eb9c79..000000000 --- a/build_mingw_noasync.bat +++ /dev/null @@ -1,14 +0,0 @@ -@echo off -rem Build without SIM_ASYNCH_IO defined (avoiding the use of pthreads) -rem Compile all of SIMH using MINGW make and gcc environment -rem Individual simulator sources are in .\simulator_name -rem Individual simulator executables are to .\BIN -rem -rem If needed, define the path for the MINGW bin directory. -rem -gcc -v 1>NUL 2>NUL -if ERRORLEVEL 1 path C:\MinGW\bin;%path% -if not exist BIN mkdir BIN -gcc -v 1>NUL 2>NUL -if ERRORLEVEL 1 echo "MinGW Environment Unavailable" -mingw32-make NOASYNCH=1 -f makefile %* diff --git a/cmake/add_simulator.cmake b/cmake/add_simulator.cmake index c4c702425..06e16639c 100644 --- a/cmake/add_simulator.cmake +++ b/cmake/add_simulator.cmake @@ -24,6 +24,7 @@ add_custom_target(update_sim_commit ALL ## Simulator sources and library: set(SIM_SOURCES ${CMAKE_SOURCE_DIR}/scp.c + ${CMAKE_SOURCE_DIR}/sim_debtab.c ${CMAKE_SOURCE_DIR}/sim_card.c ${CMAKE_SOURCE_DIR}/sim_console.c ${CMAKE_SOURCE_DIR}/sim_disk.c @@ -36,12 +37,20 @@ set(SIM_SOURCES ${CMAKE_SOURCE_DIR}/sim_tape.c ${CMAKE_SOURCE_DIR}/sim_timer.c ${CMAKE_SOURCE_DIR}/sim_tmxr.c - ${CMAKE_SOURCE_DIR}/sim_video.c) + ${CMAKE_SOURCE_DIR}/sim_video.c + ${CMAKE_SOURCE_DIR}/sim_debtab.c) set(SIM_VIDEO_SOURCES ${CMAKE_SOURCE_DIR}/display/display.c ${CMAKE_SOURCE_DIR}/display/sim_ws.c) +if (WITH_NETWORK AND WITH_SLIRP) + list(APPEND SIM_SOURCES + sim_slirp/sim_slirp.c + sim_slirp/slirp_poll.c + ) +endif () + ## Build a simulator core library, with and without AIO support. The AIO variant ## has "_aio" appended to its name, e.g., "simhz64_aio" or "simhz64_video_aio". function(build_simcore _targ) @@ -60,8 +69,38 @@ function(build_simcore _targ) C_STANDARD 99 EXCLUDE_FROM_ALL True ) + + if (TARGET_WINVER) + target_compile_definitions(${lib} PUBLIC WINVER=${TARGET_WINVER} _WIN32_WINNT=${TARGET_WINVER}) + endif () + target_compile_definitions(${lib} PRIVATE USE_SIM_CARD USE_SIM_IMD) target_compile_options(${lib} PRIVATE ${EXTRA_TARGET_CFLAGS}) + + if (WITH_NETWORK AND WITH_SLIRP) + target_compile_definitions( + ${lib} + PUBLIC + HAVE_SLIRP_NETWORK + LIBSLIRP_STATIC + ) + + if (HAVE_INET_PTON) + ## libslirp detects HAVE_INET_PTON for us. + target_compile_definitions(${lib} PUBLIC HAVE_INET_PTON) + endif() + + target_include_directories( + ${lib} + PUBLIC + ${CMAKE_SOURCE_DIR}/sim_slirp + PRIVATE + ${CMAKE_SOURCE_DIR}/libslirp/minimal + ${CMAKE_SOURCE_DIR}/libslirp/src + ${CMAKE_BINARY_DIR}/libslirp/build-include + ) + endif () + target_link_options(${lib} PRIVATE ${EXTRA_TARGET_LFLAGS}) # Make sure that the top-level directory is part of the libary's include path: diff --git a/cmake/cmake-builder.ps1 b/cmake/cmake-builder.ps1 index 2919e5079..5fa876348 100644 --- a/cmake/cmake-builder.ps1 +++ b/cmake/cmake-builder.ps1 @@ -85,7 +85,7 @@ param ( ## mingw-make MinGW GCC/mingw32-make ## mingw-ninja MinGW GCC/ninja [Parameter(Mandatory=$false)] - [string] $flavor = "vs2022", + [string] $flavor = "vs2022-x64", ## The target build configuration. Valid values: "Release" and "Debug" [Parameter(Mandatory=$false)] @@ -210,18 +210,21 @@ $multiConfig = $false $singleConfig = $true $cmakeGenMap = @{ - "vs2022" = [GeneratorInfo]::new("Visual Studio 17 2022", $multiConfig, $false, "", @("-A", "Win32")); - "vs2022-xp" = [GeneratorInfo]::new("Visual Studio 17 2022", $multiConfig, $false, "", @("-A", "Win32", "-T", "v141_xp")); - "vs2022-x64" = [GeneratorInfo]::new("Visual Studio 17 2022", $multiConfig, $false, "", @("-A", "x64", "-T", "host=x64")); - "vs2019" = [GeneratorInfo]::new("Visual Studio 16 2019", $multiConfig, $false, "", @("-A", "Win32")); - "vs2019-xp" = [GeneratorInfo]::new("Visual Studio 16 2019", $multiConfig, $false, "", @("-A", "Win32", "-T", "v141_xp")); - "vs2019-x64" = [GeneratorInfo]::new("Visual Studio 17 2022", $multiConfig, $false, "", @("-A", "x64", "-T", "host=x64")); - "vs2017" = [GeneratorInfo]::new("Visual Studio 15 2017", $multiConfig, $false, "", @("-A", "Win32")); - "vs2017-xp" = [GeneratorInfo]::new("Visual Studio 15 2017", $multiConfig, $false, "", @("-A", "Win32", "-T", "v141_xp")); - "vs2017-x64" = [GeneratorInfo]::new("Visual Studio 17 2022", $multiConfig, $false, "", @("-A", "x64", "-T", "host=x64")); - "vs2015" = [GeneratorInfo]::new("Visual Studio 14 2015", $multiConfig, $false, "", @()); - "mingw-make" = [GeneratorInfo]::new("MinGW Makefiles", $singleConfig, $false, "", @()); - "mingw-ninja" = [GeneratorInfo]::new("Ninja", $singleConfig, $false, "", @()) + "vs2022" = [GeneratorInfo]::new("Visual Studio 17 2022", $multiConfig, $false, "", @("-A", "Win32")); + "vs2022-x64" = [GeneratorInfo]::new("Visual Studio 17 2022", $multiConfig, $false, "", @("-A", "x64", "-T", "host=x64")); + "vs2022-xp" = [GeneratorInfo]::new("Visual Studio 17 2022", $multiConfig, $false, "", + @("-A", "Win32", "-T", "v141_xp", "-DTARGET_WINVER=0x0501")); + "vs2019" = [GeneratorInfo]::new("Visual Studio 16 2019", $multiConfig, $false, "", @("-A", "Win32")); + "vs2019-x64" = [GeneratorInfo]::new("Visual Studio 17 2019", $multiConfig, $false, "", @("-A", "x64", "-T", "host=x64")); + "vs2019-xp" = [GeneratorInfo]::new("Visual Studio 16 2019", $multiConfig, $false, "", + @("-A", "Win32", "-T", "v141_xp", "-DTARGET_WINVER=0x0501")); + "vs2017" = [GeneratorInfo]::new("Visual Studio 15 2017", $multiConfig, $false, "", @("-A", "Win32")); + "vs2017-x64" = [GeneratorInfo]::new("Visual Studio 17 2017", $multiConfig, $false, "", @("-A", "x64", "-T", "host=x64")); + "vs2017-xp" = [GeneratorInfo]::new("Visual Studio 15 2017", $multiConfig, $false, "", + @("-A", "Win32", "-T", "v141_xp", "-DTARGET_WINVER=0x0501")); + "vs2015" = [GeneratorInfo]::new("Visual Studio 14 2015", $multiConfig, $false, "", @()); + "mingw-make" = [GeneratorInfo]::new("MinGW Makefiles", $singleConfig, $false, "", @()); + "mingw-ninja" = [GeneratorInfo]::new("Ninja", $singleConfig, $false, "", @()) } @@ -301,7 +304,7 @@ if (!$testonly) } ## Validate the requested configuration. -if (!@("Release", "Debug").Contains($config)) +if (!@("Release", "Debug", "RelWithDebInfo").Contains($config)) { @" ${scriptName}: Invalid configuration: "${config}". diff --git a/cmake/cmake-builder.sh b/cmake/cmake-builder.sh index aee5dbca4..a52a1df85 100755 --- a/cmake/cmake-builder.sh +++ b/cmake/cmake-builder.sh @@ -27,7 +27,8 @@ Configure and build simh simulators on Linux and *nix-like platforms. msys2 mingw ucrt ---config (-c) Specifies the build configuration: 'Release' or 'Debug' +--config (-c) Specifies the build configuration: 'Release', 'Debug', or + 'RelWithDebInfo' --target Build a specific simulator or simulators. Separate multiple targets with a comma, e.g. "--target pdp8,pdp11,vax750,altairz80,3b2" @@ -219,7 +220,7 @@ while true; do ;; -c | --config) case "$2" in - Release|Debug) + Release|Debug|RelWithDebInfo) buildConfig=$2 shift 2 ;; diff --git a/cmake/dep-link.cmake b/cmake/dep-link.cmake index 90c7707e0..cfc342ba2 100644 --- a/cmake/dep-link.cmake +++ b/cmake/dep-link.cmake @@ -346,10 +346,10 @@ if (WITH_NETWORK) endif (HAVE_TAP_NETWORK) endif (WITH_TAP) - if (WITH_SLIRP) - target_link_libraries(simh_network INTERFACE slirp) + if (WITH_NETWORK AND WITH_SLIRP) + target_link_libraries(simh_network INTERFACE slirp_static) list(APPEND NETWORK_PKG_STATUS "NAT(SLiRP)") - endif (WITH_SLIRP) + endif () ## Finally, set the network runtime if (NOT network_runtime) diff --git a/cmake/os-features.cmake b/cmake/os-features.cmake index 6b982511e..44b05afa3 100644 --- a/cmake/os-features.cmake +++ b/cmake/os-features.cmake @@ -190,7 +190,6 @@ if (WIN32) target_compile_definitions(os_features INTERFACE HAVE_WINMM) if (NOT WINAPI_DEPRECATION) target_compile_definitions(os_features INTERFACE - _WINSOCK_DEPRECATED_NO_WARNINGS _CRT_NONSTDC_NO_WARNINGS _CRT_SECURE_NO_WARNINGS ) @@ -206,5 +205,41 @@ if (CYGWIN) endif () endif () +## inttypes.h for print formats: +check_include_file(inttypes.h have_inttypes_h) +if (have_inttypes_h) + target_compile_definitions(os_features INTERFACE HAVE_INTTYPES_H) +endif () + +# libslirp poll/select/etc. detection +set(sim_use_select 0) +set(sim_use_poll 0) + +if (NOT WIN32) + check_include_file(poll.h have_poll_h) + if (have_poll_h) + set(sim_use_poll 1) + else () + set(sim_use_select 1) + endif () +else () + cmake_push_check_state() + list(APPEND CMAKE_REQUIRED_LIBRARIES "ws2_32") + + check_symbol_exists(WSAPoll "winsock2.h;windows.h" have_wsa_poll) + if (have_wsa_poll) + set(sim_use_poll 1) + else () + set(sim_use_select 1) + endif () + + cmake_pop_check_state() +endif() + +target_compile_definitions(os_features INTERFACE + SIM_USE_POLL=${sim_use_poll} + SIM_USE_SELECT=${sim_use_select} +) + ## Sanitizer support find_package(Sanitizers) diff --git a/cmake/platform-quirks.cmake b/cmake/platform-quirks.cmake index de1cb0f23..3c3b19b31 100644 --- a/cmake/platform-quirks.cmake +++ b/cmake/platform-quirks.cmake @@ -79,11 +79,13 @@ if (WIN32) ## /Ot: Favor fast code ## /Oy: Suppress generating a stack frame (??? why?) add_compile_options("$<$:/EHsc;/GF;/Gy;/Oi;/Ot;/Oy;/Zi>") + add_compile_options("$<$:/EHsc;/GF;/Gy;/Oi;/Ot;/Oy;/Zi>") add_compile_options("$<$:/EHsc;/FC>") if (RELEASE_LTO) ## /LTCG: Link-Time Code Generation. Pair with /GL at compile time. add_compile_options("$<$:/GL>") + add_compile_options("$<$:/GL>") add_link_options("$<$:/LTCG>") message(STATUS "Adding LTO to Release compiler and linker flags") endif () @@ -99,7 +101,7 @@ if (WIN32) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>${use_rtll}") ## Disable automagic add for _MBCS: - add_definitions(-D_SBCS) + add_compile_definitions(_SBCS) if (CMAKE_VERSION VERSION_LESS "3.23") ## -5 Evil hack to ensure that find_package() can match against an empty @@ -109,6 +111,7 @@ if (WIN32) list(APPEND EXTRA_TARGET_CFLAGS "$<$:$<$:/W4>>" + "$<$:$<$:/W4>>" "$<$:/W3>" ) @@ -123,6 +126,13 @@ if (WIN32) list(APPEND EXTRA_TARGET_CFLAGS "/WX") endif () endif () + + ## And there's a target Windows version? + if (TARGET_WINVER) + message(STATUS "Target Windows version set to ${TARGET_WINVER}") + add_compile_definitions(WINVER=${TARGET_WINVER} _WIN32_WINNT=${TARGET_WINVER}) + list(APPEND CMAKE_REQUIRED_DEFINITIONS "-DWINVER=${TARGET_WINVER}" "-D_WIN32_WINNT=${TARGET_WINVER}") + endif () elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") # The MSVC solution builds as 32-bit, but none of the *nix platforms do. # @@ -136,11 +146,10 @@ endif () if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang") # include(fpintrin) - # Turn on warnings about strict overflow/potential overflows. - ## LIST(APPEND EXTRA_TARGET_CFLAGS "-Wall" "-fno-inline" "-fstrict-overflow" "-Wstrict-overflow=3") LIST(APPEND EXTRA_TARGET_CFLAGS "-U__STRICT_ANSI__" "$<$:$<$:-Wall>>" + "$<$:$<$:-Wall>>" ## Only add if WARNINGS_FATAL set; has undesirable consequences with LTO. "$<$:-Wall>" ) @@ -151,7 +160,6 @@ if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang") # the VAX simulators. Reduce optimization and ensure strict overflow is turned off. if (CMAKE_C_COMPILER_ID STREQUAL "GNU") - set(update_o2 TRUE) set(add_werror ${WARNINGS_FATAL}) if (NOT MINGW) @@ -162,7 +170,6 @@ if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang") set(lto_flag "$<$:-flto>") list(APPEND EXTRA_TARGET_CFLAGS "${lto_flag}") list(APPEND EXTRA_TARGET_LFLAGS "${lto_flag}") - set(update_o2 FALSE) set(add_werror TRUE) else () message(STATUS "Compiler does not support Link Time Optimization.") @@ -174,12 +181,6 @@ if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang") message(STATUS "MinGW: Link Time Optimization BROKEN, not added to Release flags") endif () - if (update_o2) - message(STATUS "Replacing '-O3' with '-O2'") - string(REGEX REPLACE "-O3" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") - string(REGEX REPLACE "-O3" "-O2" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") - endif () - if (add_werror) check_c_compiler_flag("-Werror" GCC_W_ERROR_FLAG) if (GCC_W_ERROR_FLAG) @@ -200,12 +201,25 @@ if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang") elseif (CMAKE_C_COMPILER_ID MATCHES ".*Clang") message(STATUS "Adding Clang-specific optimizations to CMAKE_C_FLAGS_RELEASE") list(APPEND opt_flags "-fno-strict-overflow") + + if (WIN32) + list(APPEND EXTRA_TARGET_CFLAGS "-Wmicrosoft") + ## IBM1130 has a copyright symbol (8-bit character), so need to specify the code + ## page to the llvm-rc resource compiler. + if (CMAKE_RC_COMPILER MATCHES ".*windres.exe") + string(APPEND CMAKE_RC_FLAGS " -c 1252") + else () + string(APPEND CMAKE_RC_FLAGS " /C 1252") + endif () + endif () endif() foreach (opt_flag ${opt_flags}) message(STATUS " ${opt_flag}") string(REGEX REPLACE "${opt_flag}[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") string(APPEND CMAKE_C_FLAGS_RELEASE " ${opt_flag}") + string(REGEX REPLACE "${opt_flag}[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") + string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO " ${opt_flag}") string(REGEX REPLACE "${opt_flag}[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") string(APPEND CMAKE_C_FLAGS_MINSIZEREL " ${opt_flag}") endforeach () diff --git a/cmake/pthreads-dep.cmake b/cmake/pthreads-dep.cmake index 81cae146b..c83b2b434 100644 --- a/cmake/pthreads-dep.cmake +++ b/cmake/pthreads-dep.cmake @@ -12,7 +12,7 @@ set(AIO_FLAGS) if (WITH_ASYNC) include(ExternalProject) - if (MSVC OR (WIN32 AND CMAKE_C_COMPILER_ID MATCHES ".*Clang.*with MSVC-like command-line.*")) + if (MSVC OR (WIN32 AND CMAKE_C_COMPILER_ID MATCHES ".*Clang" AND NOT DEFINED ENV{MSYSTEM})) # Pthreads4w: pthreads for windows. if (USING_VCPKG) find_package(PThreads4W REQUIRED) diff --git a/cmake/sanitize-helpers.cmake b/cmake/sanitize-helpers.cmake index 9bdc55ca6..526745c8f 100644 --- a/cmake/sanitize-helpers.cmake +++ b/cmake/sanitize-helpers.cmake @@ -171,10 +171,14 @@ function (sanitizer_add_flags TARGET NAME PREFIX) separate_arguments(flags_list UNIX_COMMAND "${${PREFIX}_${TARGET_COMPILER}_FLAGS} ${SanBlist_${TARGET_COMPILER}_FLAGS}") target_compile_options(${TARGET} PUBLIC "$<$:${flags_list}>") + target_compile_options(${TARGET} PUBLIC "$<$:${flags_list}>") target_compile_options(${TARGET} PUBLIC "$<$:${flags_list}>") separate_arguments(flags_list UNIX_COMMAND "${${PREFIX}_${TARGET_COMPILER}_FLAGS}") - target_link_options(${TARGET} PUBLIC "$<$:${flags_list}>") - target_link_options(${TARGET} PUBLIC "$<$:${flags_list}>") + if (NOT MSVC) + target_link_options(${TARGET} PUBLIC "$<$:${flags_list}>") + target_link_options(${TARGET} PUBLIC "$<$:${flags_list}>") + target_link_options(${TARGET} PUBLIC "$<$:${flags_list}>") + endif () endfunction () diff --git a/cmake/simgen/basic_simulator.py b/cmake/simgen/basic_simulator.py index 9d3eb9d6a..d42c73454 100644 --- a/cmake/simgen/basic_simulator.py +++ b/cmake/simgen/basic_simulator.py @@ -279,6 +279,8 @@ def write_simulator(self, stream, indent, test_label='ibm650'): 'if (WIN32)', ' if (MSVC)', ' set(I650_STACK_FLAG "/STACK:{0}")'.format(self.stack_size), + ' elseif (CMAKE_C_COMPILER_ID MATCHES ".*Clang")', + ' set(I650_STACK_FLAG "-Xlinker" "/STACK:{0}")'.format(self.stack_size), ' else ()', ' set(I650_STACK_FLAG "-Wl,--stack,{0}")'.format(self.stack_size), ' endif ()', diff --git a/cmake/simgen/cmake_container.py b/cmake/simgen/cmake_container.py index 053a75492..1348acacd 100644 --- a/cmake/simgen/cmake_container.py +++ b/cmake/simgen/cmake_container.py @@ -75,6 +75,7 @@ class CMakeBuildSystem: '${NETWORK_OPT}', '$(NETWORK_OPT)', '${SCSI}', '$(SCSI)', '${DISPLAY_OPT}', '$(DISPLAY_OPT)', + '${NETWORK_LDFLAGS}', '$(NETWORK_LDFLAGS)', '${VIDEO_CCDEFS}', '$(VIDEO_CCDEFS)', '${VIDEO_LDFLAGS}', '$(VIDEO_LDFLAGS)', '${BESM6_PANEL_OPT}', '$(BESM6_PANEL_OPT)']) @@ -156,7 +157,7 @@ def extract(self, compile_action, test_name, sim_dir, sim_name, defs, buildrom, def compile_elems_to_ignore(self, elem): - return (elem in self._ignore_compile_elems or elem.endswith('_LDFLAGS')) + return (elem in self._ignore_compile_elems or elem.endswith('_LDFLAGS)') or elem.endswith('_LDFLAGS}')) def source_elems_to_ignore(self, elem): return self.compile_elems_to_ignore(elem) or elem in _special_sources diff --git a/cmake/simh-packaging.cmake b/cmake/simh-packaging.cmake index 6a3ac3978..fdcc14481 100644 --- a/cmake/simh-packaging.cmake +++ b/cmake/simh-packaging.cmake @@ -1,103 +1,103 @@ -## The default runtime support component/family: -cpack_add_component(runtime_support - DISPLAY_NAME "Runtime support" - DESCRIPTION "Required SIMH runtime support (documentation, shared libraries)" - REQUIRED -) - -## Basic documentation for SIMH -install(FILES doc/simh.doc TYPE DOC COMPONENT runtime_support) - -cpack_add_component(altairz80_family - DISPLAY_NAME "Altair Z80 simulator." - DESCRIPTION "The Altair Z80 simulator with M68000 support. Simulators: altairz80" -) -cpack_add_component(att3b2_family - DISPLAY_NAME "ATT&T 3b2 collection" - DESCRIPTION "The AT&T 3b2 simulator family. Simulators: 3b2, 3b2-700" -) -cpack_add_component(b5500_family - DISPLAY_NAME "Burroughs 5500" - DESCRIPTION "The Burroughs 5500 system simulator. Simulators: b5500" -) -cpack_add_component(cdc1700_family - DISPLAY_NAME "CDC 1700" - DESCRIPTION "The Control Data Corporation's systems. Simulators: cdc1700" -) -cpack_add_component(decpdp_family - DISPLAY_NAME "DEC PDP family" - DESCRIPTION "Digital Equipment Corporation PDP systems. Simulators: pdp1, pdp15, pdp4, pdp6, pdp7, pdp8, pdp9" -) -cpack_add_component(default_family - DISPLAY_NAME "Default SIMH simulator family." - DESCRIPTION "The SIMH simulator collection of historical processors and computing systems that do not belong to -any other simulated system family. Simulators: altair, besm6, ssem, tt2500, tx-0" -) -cpack_add_component(dgnova_family - DISPLAY_NAME "DG Nova and Eclipse" - DESCRIPTION "Data General NOVA and Eclipse system simulators. Simulators: eclipse, nova" -) -cpack_add_component(experimental - DISPLAY_NAME "Experimental (work-in-progress) simulators" - DESCRIPTION "Experimental or work-in-progress simulators not in the SIMH mainline simulator suite. Simulators: alpha, pdq3, sage" -) -cpack_add_component(gould_family - DISPLAY_NAME "Gould simulators" - DESCRIPTION "Gould Systems simulators. Simulators: sel32" -) -cpack_add_component(grisys_family - DISPLAY_NAME "GRI Systems GRI-909" - DESCRIPTION "GRI Systems GRI-909 system simulator. Simulators: gri" -) -cpack_add_component(honeywell_family - DISPLAY_NAME "Honeywell H316" - DESCRIPTION "Honeywell H-316 system simulator. Simulators: h316" -) -cpack_add_component(hp_family - DISPLAY_NAME "HP 2100, 3000" - DESCRIPTION "Hewlett-Packard H2100 and H3000 simulators. Simulators: hp2100, hp3000" -) -cpack_add_component(ibm_family - DISPLAY_NAME "IBM" - DESCRIPTION "IBM system simulators: i650. Simulators: i1401, i1620, i650, i701, i7010, i704, i7070, i7080, i7090, i7094, ibm1130, s3" -) -cpack_add_component(imlac_family - DISPLAY_NAME "IMLAC" - DESCRIPTION "IMLAC system simulators. Simulators: imlac" -) -cpack_add_component(intel_family - DISPLAY_NAME "Intel" - DESCRIPTION "Intel system simulators. Simulators: intel-mds, scelbi" -) -cpack_add_component(interdata_family - DISPLAY_NAME "Interdata" - DESCRIPTION "Interdata systems simulators. Simulators: id16, id32" -) -cpack_add_component(lgp_family - DISPLAY_NAME "LGP" - DESCRIPTION "Librascope systems. Simulators: lgp" -) -cpack_add_component(norsk_family - DISPLAY_NAME "ND simulators" - DESCRIPTION "Norsk Data systems simulator family. Simulators: nd100" -) -cpack_add_component(pdp10_family - DISPLAY_NAME "DEC PDP-10 collection" - DESCRIPTION "DEC PDP-10 architecture simulators and variants. Simulators: pdp10, pdp10-ka, pdp10-ki, pdp10-kl, pdp10-ks" -) -cpack_add_component(pdp11_family - DISPLAY_NAME "DEC PDP-11 collection." - DESCRIPTION "DEC PDP-11 and PDP-11-derived architecture simulators. Simulators: pdp11, uc15" -) -cpack_add_component(sds_family - DISPLAY_NAME "SDS simulators" - DESCRIPTION "Scientific Data Systems (SDS) systems. Simulators: sds, sigma" -) -cpack_add_component(swtp_family - DISPLAY_NAME "SWTP simulators" - DESCRIPTION "Southwest Technical Products (SWTP) system simulators. Simulators: swtp6800mp-a, swtp6800mp-a2" -) -cpack_add_component(vax_family - DISPLAY_NAME "DEC VAX simulator collection" - DESCRIPTION "The Digital Equipment Corporation VAX (plural: VAXen) simulator family. Simulators: infoserver100, infoserver1000, infoserver150vxt, microvax1, microvax2, microvax2000, microvax3100, microvax3100e, microvax3100m80, rtvax1000, vax, vax730, vax750, vax780, vax8200, vax8600, vaxstation3100m30, vaxstation3100m38, vaxstation3100m76, vaxstation4000m60, vaxstation4000vlc" -) +## The default runtime support component/family: +cpack_add_component(runtime_support + DISPLAY_NAME "Runtime support" + DESCRIPTION "Required SIMH runtime support (documentation, shared libraries)" + REQUIRED +) + +## Basic documentation for SIMH +install(FILES doc/simh.doc TYPE DOC COMPONENT runtime_support) + +cpack_add_component(altairz80_family + DISPLAY_NAME "Altair Z80 simulator." + DESCRIPTION "The Altair Z80 simulator with M68000 support. Simulators: altairz80" +) +cpack_add_component(att3b2_family + DISPLAY_NAME "ATT&T 3b2 collection" + DESCRIPTION "The AT&T 3b2 simulator family. Simulators: 3b2, 3b2-700" +) +cpack_add_component(b5500_family + DISPLAY_NAME "Burroughs 5500" + DESCRIPTION "The Burroughs 5500 system simulator. Simulators: b5500" +) +cpack_add_component(cdc1700_family + DISPLAY_NAME "CDC 1700" + DESCRIPTION "The Control Data Corporation's systems. Simulators: cdc1700" +) +cpack_add_component(decpdp_family + DISPLAY_NAME "DEC PDP family" + DESCRIPTION "Digital Equipment Corporation PDP systems. Simulators: pdp1, pdp15, pdp4, pdp6, pdp7, pdp8, pdp9" +) +cpack_add_component(default_family + DISPLAY_NAME "Default SIMH simulator family." + DESCRIPTION "The SIMH simulator collection of historical processors and computing systems that do not belong to +any other simulated system family. Simulators: altair, besm6, ssem, tt2500, tx-0" +) +cpack_add_component(dgnova_family + DISPLAY_NAME "DG Nova and Eclipse" + DESCRIPTION "Data General NOVA and Eclipse system simulators. Simulators: eclipse, nova" +) +cpack_add_component(experimental + DISPLAY_NAME "Experimental (work-in-progress) simulators" + DESCRIPTION "Experimental or work-in-progress simulators not in the SIMH mainline simulator suite. Simulators: alpha, pdq3, sage" +) +cpack_add_component(gould_family + DISPLAY_NAME "Gould simulators" + DESCRIPTION "Gould Systems simulators. Simulators: sel32" +) +cpack_add_component(grisys_family + DISPLAY_NAME "GRI Systems GRI-909" + DESCRIPTION "GRI Systems GRI-909 system simulator. Simulators: gri" +) +cpack_add_component(honeywell_family + DISPLAY_NAME "Honeywell H316" + DESCRIPTION "Honeywell H-316 system simulator. Simulators: h316" +) +cpack_add_component(hp_family + DISPLAY_NAME "HP 2100, 3000" + DESCRIPTION "Hewlett-Packard H2100 and H3000 simulators. Simulators: hp2100, hp3000" +) +cpack_add_component(ibm_family + DISPLAY_NAME "IBM" + DESCRIPTION "IBM system simulators: i650. Simulators: i1401, i1620, i650, i701, i7010, i704, i7070, i7080, i7090, i7094, ibm1130, s3" +) +cpack_add_component(imlac_family + DISPLAY_NAME "IMLAC" + DESCRIPTION "IMLAC system simulators. Simulators: imlac" +) +cpack_add_component(intel_family + DISPLAY_NAME "Intel" + DESCRIPTION "Intel system simulators. Simulators: intel-mds, scelbi" +) +cpack_add_component(interdata_family + DISPLAY_NAME "Interdata" + DESCRIPTION "Interdata systems simulators. Simulators: id16, id32" +) +cpack_add_component(lgp_family + DISPLAY_NAME "LGP" + DESCRIPTION "Librascope systems. Simulators: lgp" +) +cpack_add_component(norsk_family + DISPLAY_NAME "ND simulators" + DESCRIPTION "Norsk Data systems simulator family. Simulators: nd100" +) +cpack_add_component(pdp10_family + DISPLAY_NAME "DEC PDP-10 collection" + DESCRIPTION "DEC PDP-10 architecture simulators and variants. Simulators: pdp10, pdp10-ka, pdp10-ki, pdp10-kl, pdp10-ks" +) +cpack_add_component(pdp11_family + DISPLAY_NAME "DEC PDP-11 collection." + DESCRIPTION "DEC PDP-11 and PDP-11-derived architecture simulators. Simulators: pdp11, uc15" +) +cpack_add_component(sds_family + DISPLAY_NAME "SDS simulators" + DESCRIPTION "Scientific Data Systems (SDS) systems. Simulators: sds, sigma" +) +cpack_add_component(swtp_family + DISPLAY_NAME "SWTP simulators" + DESCRIPTION "Southwest Technical Products (SWTP) system simulators. Simulators: swtp6800mp-a, swtp6800mp-a2" +) +cpack_add_component(vax_family + DISPLAY_NAME "DEC VAX simulator collection" + DESCRIPTION "The Digital Equipment Corporation VAX (plural: VAXen) simulator family. Simulators: infoserver100, infoserver1000, infoserver150vxt, microvax1, microvax2, microvax2000, microvax3100, microvax3100e, microvax3100m80, rtvax1000, vax, vax730, vax750, vax780, vax8200, vax8600, vaxstation3100m30, vaxstation3100m38, vaxstation3100m76, vaxstation4000m60, vaxstation4000vlc" +) diff --git a/cmake/simh-simulators.cmake b/cmake/simh-simulators.cmake index 15d58c3b8..bd456fa5e 100644 --- a/cmake/simh-simulators.cmake +++ b/cmake/simh-simulators.cmake @@ -1,123 +1,123 @@ -## -## This is an automagically generated file. Do NOT EDIT. -## Any changes you make will be overwritten!! -## -## Make changes to the SIMH top-level makefile and then run the -## "cmake/generate.py" script to regenerate these files. -## -## cd cmake; python -m generate --help -## -## ------------------------------------------------------------ -set(ALPHAD "${CMAKE_SOURCE_DIR}/alpha") -set(ALTAIRD "${CMAKE_SOURCE_DIR}/ALTAIR") -set(ALTAIRZ80D "${CMAKE_SOURCE_DIR}/AltairZ80") -set(ATT3B2D "${CMAKE_SOURCE_DIR}/3B2") -set(B5500D "${CMAKE_SOURCE_DIR}/B5500") -set(BESM6D "${CMAKE_SOURCE_DIR}/BESM6") -set(CDC1700D "${CMAKE_SOURCE_DIR}/CDC1700") -set(GRID "${CMAKE_SOURCE_DIR}/GRI") -set(H316D "${CMAKE_SOURCE_DIR}/H316") -set(HP2100D "${CMAKE_SOURCE_DIR}/HP2100") -set(HP3000D "${CMAKE_SOURCE_DIR}/HP3000") -set(I1401D "${CMAKE_SOURCE_DIR}/I1401") -set(I1620D "${CMAKE_SOURCE_DIR}/I1620") -set(I650D "${CMAKE_SOURCE_DIR}/I650") -set(I7000D "${CMAKE_SOURCE_DIR}/I7000") -set(I7010D "${CMAKE_SOURCE_DIR}/I7000") -set(I7094D "${CMAKE_SOURCE_DIR}/I7094") -set(IBM1130D "${CMAKE_SOURCE_DIR}/Ibm1130") -set(ID16D "${CMAKE_SOURCE_DIR}/Interdata") -set(ID32D "${CMAKE_SOURCE_DIR}/Interdata") -set(IMLACD "${CMAKE_SOURCE_DIR}/imlac") -set(INTELSYSC "${CMAKE_SOURCE_DIR}/Intel-Systems/common") -set(KA10D "${CMAKE_SOURCE_DIR}/PDP10") -set(KI10D "${CMAKE_SOURCE_DIR}/PDP10") -set(KL10D "${CMAKE_SOURCE_DIR}/PDP10") -set(KS10D "${CMAKE_SOURCE_DIR}/PDP10") -set(LGPD "${CMAKE_SOURCE_DIR}/LGP") -set(ND100D "${CMAKE_SOURCE_DIR}/ND100") -set(NOVAD "${CMAKE_SOURCE_DIR}/NOVA") -set(PDP10D "${CMAKE_SOURCE_DIR}/PDP10") -set(PDP11D "${CMAKE_SOURCE_DIR}/PDP11") -set(PDP18BD "${CMAKE_SOURCE_DIR}/PDP18B") -set(PDP1D "${CMAKE_SOURCE_DIR}/PDP1") -set(PDP6D "${CMAKE_SOURCE_DIR}/PDP10") -set(PDP8D "${CMAKE_SOURCE_DIR}/PDP8") -set(PDQ3D "${CMAKE_SOURCE_DIR}/PDQ-3") -set(S3D "${CMAKE_SOURCE_DIR}/S3") -set(SAGED "${CMAKE_SOURCE_DIR}/SAGE") -set(SDSD "${CMAKE_SOURCE_DIR}/SDS") -set(SEL32D "${CMAKE_SOURCE_DIR}/SEL32") -set(SIGMAD "${CMAKE_SOURCE_DIR}/sigma") -set(SSEMD "${CMAKE_SOURCE_DIR}/SSEM") -set(SWTP6800C "${CMAKE_SOURCE_DIR}/swtp6800/common") -set(SWTP6800D "${CMAKE_SOURCE_DIR}/swtp6800/swtp6800") -set(TT2500D "${CMAKE_SOURCE_DIR}/tt2500") -set(TX0D "${CMAKE_SOURCE_DIR}/TX-0") -set(UC15D "${CMAKE_SOURCE_DIR}/PDP11") -set(VAXD "${CMAKE_SOURCE_DIR}/VAX") - -set(DISPLAYD "${CMAKE_SOURCE_DIR}/display") -set(DISPLAY340 "${DISPLAYD}/type340.c") -set(DISPLAYIII "${DISPLAYD}/iii.c") -set(DISPLAYNG "${DISPLAYD}/ng.c") -set(DISPLAYVT "${DISPLAYD}/vt11.c") - -set(INTELSYSD "${CMAKE_SOURCE_DIR}/Intel-Systems") -set(INTEL_MDSD "${INTELSYSD}/Intel-MDS") -set(SCELBIC "${INTELSYSD}/common") -set(SCELBID "${INTELSYSD}/scelbi") - -## ---------------------------------------- - -if (NOT WITH_VIDEO) - ### Hack: Unset these variables so that they don't expand if - ### not building with video: - set(DISPLAY340 "") - set(DISPLAYIII "") - set(DISPLAYNG "") - set(DISPLAYVT "") -endif () - -## ---------------------------------------- - -add_subdirectory(3B2) -add_subdirectory(ALTAIR) -add_subdirectory(AltairZ80) -add_subdirectory(B5500) -add_subdirectory(BESM6) -add_subdirectory(CDC1700) -add_subdirectory(GRI) -add_subdirectory(H316) -add_subdirectory(HP2100) -add_subdirectory(HP3000) -add_subdirectory(I1401) -add_subdirectory(I1620) -add_subdirectory(I650) -add_subdirectory(I7000) -add_subdirectory(I7094) -add_subdirectory(Ibm1130) -add_subdirectory(Intel-Systems/Intel-MDS) -add_subdirectory(Intel-Systems/scelbi) -add_subdirectory(Interdata) -add_subdirectory(LGP) -add_subdirectory(ND100) -add_subdirectory(NOVA) -add_subdirectory(PDP1) -add_subdirectory(PDP10) -add_subdirectory(PDP11) -add_subdirectory(PDP18B) -add_subdirectory(PDP8) -add_subdirectory(PDQ-3) -add_subdirectory(S3) -add_subdirectory(SAGE) -add_subdirectory(SDS) -add_subdirectory(SEL32) -add_subdirectory(SSEM) -add_subdirectory(TX-0) -add_subdirectory(VAX) -add_subdirectory(alpha) -add_subdirectory(imlac) -add_subdirectory(sigma) -add_subdirectory(swtp6800/swtp6800) -add_subdirectory(tt2500) +## +## This is an automagically generated file. Do NOT EDIT. +## Any changes you make will be overwritten!! +## +## Make changes to the SIMH top-level makefile and then run the +## "cmake/generate.py" script to regenerate these files. +## +## cd cmake; python -m generate --help +## +## ------------------------------------------------------------ +set(ALPHAD "${CMAKE_SOURCE_DIR}/alpha") +set(ALTAIRD "${CMAKE_SOURCE_DIR}/ALTAIR") +set(ALTAIRZ80D "${CMAKE_SOURCE_DIR}/AltairZ80") +set(ATT3B2D "${CMAKE_SOURCE_DIR}/3B2") +set(B5500D "${CMAKE_SOURCE_DIR}/B5500") +set(BESM6D "${CMAKE_SOURCE_DIR}/BESM6") +set(CDC1700D "${CMAKE_SOURCE_DIR}/CDC1700") +set(GRID "${CMAKE_SOURCE_DIR}/GRI") +set(H316D "${CMAKE_SOURCE_DIR}/H316") +set(HP2100D "${CMAKE_SOURCE_DIR}/HP2100") +set(HP3000D "${CMAKE_SOURCE_DIR}/HP3000") +set(I1401D "${CMAKE_SOURCE_DIR}/I1401") +set(I1620D "${CMAKE_SOURCE_DIR}/I1620") +set(I650D "${CMAKE_SOURCE_DIR}/I650") +set(I7000D "${CMAKE_SOURCE_DIR}/I7000") +set(I7010D "${CMAKE_SOURCE_DIR}/I7000") +set(I7094D "${CMAKE_SOURCE_DIR}/I7094") +set(IBM1130D "${CMAKE_SOURCE_DIR}/Ibm1130") +set(ID16D "${CMAKE_SOURCE_DIR}/Interdata") +set(ID32D "${CMAKE_SOURCE_DIR}/Interdata") +set(IMLACD "${CMAKE_SOURCE_DIR}/imlac") +set(INTELSYSC "${CMAKE_SOURCE_DIR}/Intel-Systems/common") +set(KA10D "${CMAKE_SOURCE_DIR}/PDP10") +set(KI10D "${CMAKE_SOURCE_DIR}/PDP10") +set(KL10D "${CMAKE_SOURCE_DIR}/PDP10") +set(KS10D "${CMAKE_SOURCE_DIR}/PDP10") +set(LGPD "${CMAKE_SOURCE_DIR}/LGP") +set(ND100D "${CMAKE_SOURCE_DIR}/ND100") +set(NOVAD "${CMAKE_SOURCE_DIR}/NOVA") +set(PDP10D "${CMAKE_SOURCE_DIR}/PDP10") +set(PDP11D "${CMAKE_SOURCE_DIR}/PDP11") +set(PDP18BD "${CMAKE_SOURCE_DIR}/PDP18B") +set(PDP1D "${CMAKE_SOURCE_DIR}/PDP1") +set(PDP6D "${CMAKE_SOURCE_DIR}/PDP10") +set(PDP8D "${CMAKE_SOURCE_DIR}/PDP8") +set(PDQ3D "${CMAKE_SOURCE_DIR}/PDQ-3") +set(S3D "${CMAKE_SOURCE_DIR}/S3") +set(SAGED "${CMAKE_SOURCE_DIR}/SAGE") +set(SDSD "${CMAKE_SOURCE_DIR}/SDS") +set(SEL32D "${CMAKE_SOURCE_DIR}/SEL32") +set(SIGMAD "${CMAKE_SOURCE_DIR}/sigma") +set(SSEMD "${CMAKE_SOURCE_DIR}/SSEM") +set(SWTP6800C "${CMAKE_SOURCE_DIR}/swtp6800/common") +set(SWTP6800D "${CMAKE_SOURCE_DIR}/swtp6800/swtp6800") +set(TT2500D "${CMAKE_SOURCE_DIR}/tt2500") +set(TX0D "${CMAKE_SOURCE_DIR}/TX-0") +set(UC15D "${CMAKE_SOURCE_DIR}/PDP11") +set(VAXD "${CMAKE_SOURCE_DIR}/VAX") + +set(DISPLAYD "${CMAKE_SOURCE_DIR}/display") +set(DISPLAY340 "${DISPLAYD}/type340.c") +set(DISPLAYIII "${DISPLAYD}/iii.c") +set(DISPLAYNG "${DISPLAYD}/ng.c") +set(DISPLAYVT "${DISPLAYD}/vt11.c") + +set(INTELSYSD "${CMAKE_SOURCE_DIR}/Intel-Systems") +set(INTEL_MDSD "${INTELSYSD}/Intel-MDS") +set(SCELBIC "${INTELSYSD}/common") +set(SCELBID "${INTELSYSD}/scelbi") + +## ---------------------------------------- + +if (NOT WITH_VIDEO) + ### Hack: Unset these variables so that they don't expand if + ### not building with video: + set(DISPLAY340 "") + set(DISPLAYIII "") + set(DISPLAYNG "") + set(DISPLAYVT "") +endif () + +## ---------------------------------------- + +add_subdirectory(3B2) +add_subdirectory(ALTAIR) +add_subdirectory(AltairZ80) +add_subdirectory(B5500) +add_subdirectory(BESM6) +add_subdirectory(CDC1700) +add_subdirectory(GRI) +add_subdirectory(H316) +add_subdirectory(HP2100) +add_subdirectory(HP3000) +add_subdirectory(I1401) +add_subdirectory(I1620) +add_subdirectory(I650) +add_subdirectory(I7000) +add_subdirectory(I7094) +add_subdirectory(Ibm1130) +add_subdirectory(Intel-Systems/Intel-MDS) +add_subdirectory(Intel-Systems/scelbi) +add_subdirectory(Interdata) +add_subdirectory(LGP) +add_subdirectory(ND100) +add_subdirectory(NOVA) +add_subdirectory(PDP1) +add_subdirectory(PDP10) +add_subdirectory(PDP11) +add_subdirectory(PDP18B) +add_subdirectory(PDP8) +add_subdirectory(PDQ-3) +add_subdirectory(S3) +add_subdirectory(SAGE) +add_subdirectory(SDS) +add_subdirectory(SEL32) +add_subdirectory(SSEM) +add_subdirectory(TX-0) +add_subdirectory(VAX) +add_subdirectory(alpha) +add_subdirectory(imlac) +add_subdirectory(sigma) +add_subdirectory(swtp6800/swtp6800) +add_subdirectory(tt2500) diff --git a/libslirp b/libslirp new file mode 160000 index 000000000..c607b93c7 --- /dev/null +++ b/libslirp @@ -0,0 +1 @@ +Subproject commit c607b93c7c2ce6b5242be436a3d53e531bdf358b diff --git a/makefile b/makefile index 79755eb24..a349eb332 100644 --- a/makefile +++ b/makefile @@ -102,6 +102,18 @@ OS_CCDEFS= AIO_CCDEFS= +# Need to set these early: +BIN = BIN/ +SIMHD = . + +# libslirp locations: +LIBSLIRP_DIR=${SIMHD}/libslirp +LIBSLIRP_SRC=${LIBSLIRP_DIR}/src + +# SYS_LDFLAGS: System libraries, e.g., -lm and -lpthread, that should appear +# at the end of the compiler's command line. +SYS_LDFLAGS = + ifneq (,${GREP_OPTIONS}) $(info GREP_OPTIONS is defined in your environment.) $(info ) @@ -367,7 +379,7 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) ifeq (agcc,$(findstring agcc,${GCC})) # Android target build? OS_CCDEFS += -D_GNU_SOURCE AIO_CCDEFS += -DSIM_ASYNCH_IO - OS_LDFLAGS = -lm + SYS_LDFLAGS = -lm else # Non-Android (or Native Android) Builds ifeq (,$(INCLUDES)$(LIBRARIES)) INCPATH:=$(shell LANG=C; ${GCC} -x c -v -E /dev/null 2>&1 | grep -A 10 '> search starts here' | grep '^ ' | tr -d '\n') @@ -452,7 +464,7 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) LIBPATH := $(shell LANG=C; crle | grep 'Default Library Path' | awk '{ print $$5 }' | sed 's/:/ /g') endif LIBEXT = so - OS_LDFLAGS += -lsocket -lnsl + SYS_LDFLAGS += -lsocket -lnsl ifeq (incsfw,$(shell if ${TEST} -d /opt/sfw/include; then echo incsfw; fi)) INCPATH += /opt/sfw/include OS_CCDEFS += -I/opt/sfw/include @@ -471,7 +483,7 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) LIBEXT = a else ifneq (,$(findstring AIX,$(OSTYPE))) - OS_LDFLAGS += -lm -lrt + SYS_LDFLAGS += -lm -lrt ifeq (incopt,$(shell if ${TEST} -d /opt/freeware/include; then echo incopt; fi)) INCPATH += /opt/freeware/include OS_CCDEFS += -I/opt/freeware/include @@ -492,7 +504,7 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) INCPATH := $(shell findpaths -e -a $(HAIKU_ARCH) B_FIND_PATH_HEADERS_DIRECTORY) INCPATH += $(shell findpaths -e B_FIND_PATH_HEADERS_DIRECTORY posix) LIBPATH := $(shell findpaths -e -a $(HAIKU_ARCH) B_FIND_PATH_DEVELOP_LIB_DIRECTORY) - OS_LDFLAGS += -lnetwork + SYS_LDFLAGS += -lnetwork else ifeq (,$(findstring NetBSD,$(OSTYPE))) ifneq (no ldconfig,$(findstring no ldconfig,$(shell which ldconfig 2>&1))) @@ -569,24 +581,24 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) need_search = $(strip $(shell ld -l$(1) /dev/null 2>&1 | grep $(1) | sed s/$(1)//)) LD_SEARCH_NEEDED := $(call need_search,ZzzzzzzZ) ifneq (,$(call find_lib,m)) - OS_LDFLAGS += -lm + SYS_LDFLAGS += -lm $(info using libm: $(call find_lib,m)) endif ifneq (,$(call find_lib,rt)) - OS_LDFLAGS += -lrt + SYS_LDFLAGS += -lrt $(info using librt: $(call find_lib,rt)) endif ifneq (,$(call find_include,pthread)) ifneq (,$(call find_lib,pthread)) AIO_CCDEFS += -DUSE_READER_THREAD -DSIM_ASYNCH_IO - OS_LDFLAGS += -lpthread + SYS_LDFLAGS += -lpthread $(info using libpthread: $(call find_lib,pthread) $(call find_include,pthread)) else LIBEXTSAVE := ${LIBEXT} LIBEXT = a ifneq (,$(call find_lib,pthread)) AIO_CCDEFS += -DUSE_READER_THREAD -DSIM_ASYNCH_IO - OS_LDFLAGS += -lpthread + SYS_LDFLAGS += -lpthread $(info using libpthread: $(call find_lib,pthread) $(call find_include,pthread)) else ifneq (,$(findstring Haiku,$(OSTYPE))) @@ -595,7 +607,7 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) else ifeq (Darwin,$(OSTYPE)) AIO_CCDEFS += -DUSE_READER_THREAD -DSIM_ASYNCH_IO - OS_LDFLAGS += -lpthread + SYS_LDFLAGS += -lpthread $(info using macOS libpthread: $(call find_include,pthread)) endif endif @@ -635,7 +647,7 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) ifneq (,$(call find_include,dlfcn)) ifneq (,$(call find_lib,dl)) OS_CCDEFS += -DSIM_HAVE_DLOPEN=$(LIBSOEXT) - OS_LDFLAGS += -ldl + SYS_LDFLAGS += -ldl $(info using libdl: $(call find_lib,dl) $(call find_include,dlfcn)) else ifneq (,$(findstring BSD,$(OSTYPE))$(findstring AIX,$(OSTYPE))$(findstring Haiku,$(OSTYPE))) @@ -644,7 +656,7 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) else ifneq (,$(call find_lib,dld)) OS_CCDEFS += -DSIM_HAVE_DLOPEN=$(LIBSOEXT) - OS_LDFLAGS += -ldld + SYS_LDFLAGS += -ldld $(info using libdld: $(call find_lib,dld) $(call find_include,dlfcn)) else ifeq (Darwin,$(OSTYPE)) @@ -713,76 +725,88 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) SDLX_CONFIG = sdl2-config endif ifneq (,$(SDLX_CONFIG)) - VIDEO_CCDEFS += -DHAVE_LIBSDL -DUSE_SIM_VIDEO `$(SDLX_CONFIG) --cflags` - VIDEO_LDFLAGS += `$(SDLX_CONFIG) --libs` + VIDEO_CCDEFS += -DHAVE_LIBSDL -DUSE_SIM_VIDEO $(shell $(SDLX_CONFIG) --cflags) + VIDEO_LDFLAGS += $(shell $(SDLX_CONFIG) --libs) VIDEO_FEATURES = - video capabilities provided by libSDL2 (Simple Directmedia Layer) DISPLAYL = ${DISPLAYD}/display.c $(DISPLAYD)/sim_ws.c DISPLAYVT = ${DISPLAYD}/vt11.c DISPLAY340 = ${DISPLAYD}/type340.c DISPLAYNG = ${DISPLAYD}/ng.c DISPLAYIII = ${DISPLAYD}/iii.c - DISPLAY_OPT += -DUSE_DISPLAY $(VIDEO_CCDEFS) $(VIDEO_LDFLAGS) + DISPLAY_OPT += -DUSE_DISPLAY $(VIDEO_CCDEFS) $(info using libSDL2: $(call find_include,SDL2/SDL)) ifeq (Darwin,$(OSTYPE)) VIDEO_CCDEFS += -DSDL_MAIN_AVAILABLE endif - ifneq (,$(and $(BESM6_BUILD), $(or $(and $(call find_include,SDL2/SDL_ttf),$(call find_lib,SDL2_ttf)), $(and $(call find_include,SDL/SDL_ttf),$(call find_lib,SDL_ttf))))) - FONTPATH += /usr/share/fonts /Library/Fonts /usr/lib/jvm /System/Library/Frameworks/JavaVM.framework/Versions /System/Library/Fonts C:/Windows/Fonts - FONTPATH := $(dir $(foreach dir,$(strip $(FONTPATH)),$(wildcard $(dir)/.))) - FONTNAME += DejaVuSans.ttf LucidaSansRegular.ttf FreeSans.ttf AppleGothic.ttf tahoma.ttf - $(info font paths are: $(FONTPATH)) - $(info font names are: $(FONTNAME)) - find_fontfile = $(strip $(firstword $(foreach dir,$(strip $(FONTPATH)),$(wildcard $(dir)/$(1))$(wildcard $(dir)/*/$(1))$(wildcard $(dir)/*/*/$(1))$(wildcard $(dir)/*/*/*/$(1))))) - find_font = $(abspath $(strip $(firstword $(foreach font,$(strip $(FONTNAME)),$(call find_fontfile,$(font)))))) - ifneq (,$(call find_font)) - FONTFILE=$(call find_font) - else - $(info ***) - $(info *** No font file available, BESM-6 video panel disabled.) - $(info ***) - $(info *** To enable the panel display please specify one of:) - $(info *** a font path with FONTPATH=path) - $(info *** a font name with FONTNAME=fontname.ttf) - $(info *** a font file with FONTFILE=path/fontname.ttf) - $(info ***) + ## Don't search for SDL2_ttf unless BESM6 is actually being built! + ifneq (,$(BESM6_BUILD)) + BESM6_PANEL_OPT = $(filter-out -DSDL_MAIN_AVAILABLE,${VIDEO_CCDEFS}) + SDL2_TTF_CFLAGS = $(call find_include,SDL2/SDL_ttf) + SDL2_TTF_LDFLAGS = -lSDL2_ttf + ifeq (,$(and ${SDL2_TTF_CFLAGS},${SDL2_TTF_LDFLAGS})) + SDL2_TTF_CFLAGS = $(call find_include,SDL/SDL_ttf) + SDL2_TTF_LDFLAGS = -lSDL2_ttf endif - endif - ifeq (,$(and ${VIDEO_LDFLAGS}, ${FONTFILE}, $(BESM6_BUILD))) - $(info *** No SDL ttf support available. BESM-6 video panel disabled.) - $(info ***) - ifeq (Darwin,$(OSTYPE)) - ifeq (/opt/local/bin/port,$(shell which port)) - $(info *** Info *** Install the MacPorts libSDL2-ttf development package to provide this) - $(info *** Info *** functionality for your OS X system:) - $(info *** Info *** # port install libsdl2-ttf-dev) + ifneq (,$(and ${SDL2_TTF_CFLAGS},${SDL2_TTF_LDFLAGS})) + $(info using libSDL2_ttf: ${SDL2_TTF_LDFLAGS}, ${SDL2_TTF_CFLAGS}) + FONTPATH += /usr/share/fonts /Library/Fonts /usr/lib/jvm /System/Library/Frameworks/JavaVM.framework/Versions \ + /System/Library/Fonts C:/Windows/Fonts + FONTPATH := $(dir $(foreach dir,$(strip $(FONTPATH)),$(wildcard $(dir)/.))) + FONTNAME += DejaVuSans.ttf LucidaSansRegular.ttf FreeSans.ttf AppleGothic.ttf tahoma.ttf + $(info font paths are: $(FONTPATH)) + $(info font names are: $(FONTNAME)) + find_fontfile = $(strip $(firstword $(foreach dir,$(strip $(FONTPATH)),$(wildcard $(dir)/$(1))$(wildcard $(dir)/*/$(1))$(wildcard $(dir)/*/*/$(1))$(wildcard $(dir)/*/*/*/$(1))))) + find_font = $(abspath $(strip $(firstword $(foreach font,$(strip $(FONTNAME)),$(call find_fontfile,$(font)))))) + ifneq (,$(call find_font)) + FONTFILE=$(call find_font) + $(info Font file: ${FONTFILE}) + ## Presumably, searching for SDL2 already added the correct include path, + ## this is just insurance. + BESM6_PANEL_OPT += -DFONTFILE=${FONTFILE} -I $(subst SDL_ttf.h,,${SDL2_TTF_CFLAGS}) + BESM6_PANEL_LDFLAGS = ${SDL2_TTF_LDFLAGS} + else + $(info ***) + $(info *** No font file available, BESM-6 video panel disabled.) + $(info ***) + $(info *** To enable the panel display please specify one of:) + $(info *** a font path with FONTPATH=path) + $(info *** a font name with FONTNAME=fontname.ttf) + $(info *** a font file with FONTFILE=path/fontname.ttf) + $(info ***) endif - ifeq (/usr/local/bin/brew,$(shell which brew)) + endif + ifeq (,$(and ${SDL2_TTF_LDFLAGS}, ${FONTFILE})) + $(info ***) + $(info *** No SDL ttf support available. BESM-6 video panel disabled.) + $(info ***) + ifeq (Darwin,$(OSTYPE)) ifeq (/opt/local/bin/port,$(shell which port)) - $(info *** Info ***) - $(info *** Info *** OR) - $(info *** Info ***) + $(info *** Info *** Install the MacPorts libSDL2-ttf development package to provide this) + $(info *** Info *** functionality for your OS X system:) + $(info *** Info *** # port install libsdl2-ttf-dev) + endif + ifeq (/usr/local/bin/brew,$(shell which brew)) + ifeq (/opt/local/bin/port,$(shell which port)) + $(info *** Info ***) + $(info *** Info *** OR) + $(info *** Info ***) + endif + $(info *** Info *** Install the HomeBrew sdl2_ttf package to provide this) + $(info *** Info *** functionality for your OS X system:) + $(info *** Info *** $$ brew install sdl2_ttf) endif - $(info *** Info *** Install the HomeBrew sdl2_ttf package to provide this) - $(info *** Info *** functionality for your OS X system:) - $(info *** Info *** $$ brew install sdl2_ttf) - endif - else - ifneq (,$(and $(findstring Linux,$(OSTYPE)),$(call find_exe,apt-get))) - $(info *** Info *** Install the development components of libSDL2-ttf) - $(info *** Info *** packaged for your Linux operating system distribution:) - $(info *** Info *** $$ sudo apt-get install libsdl2-ttf-dev) else - $(info *** Info *** Install the development components of libSDL2-ttf packaged by your) - $(info *** Info *** operating system distribution and rebuild your simulator to) - $(info *** Info *** enable this extra functionality.) + ifneq (,$(and $(findstring Linux,$(OSTYPE)),$(call find_exe,apt-get))) + $(info *** Info *** Install the development components of libSDL2-ttf) + $(info *** Info *** packaged for your Linux operating system distribution:) + $(info *** Info *** $$ sudo apt-get install libsdl2-ttf-dev) + else + $(info *** Info *** Install the development components of libSDL2-ttf packaged by your) + $(info *** Info *** operating system distribution and rebuild your simulator to) + $(info *** Info *** enable this extra functionality.) + endif endif endif - else - ifneq (,$(call find_include,SDL2/SDL_ttf),$(call find_lib,SDL2_ttf)) - $(info using libSDL2_ttf: $(call find_lib,SDL2_ttf) $(call find_include,SDL2/SDL_ttf)) - $(info ***) - BESM6_PANEL_OPT = -DFONTFILE=${FONTFILE} $(filter-out -DSDL_MAIN_AVAILABLE,${VIDEO_CCDEFS}) ${VIDEO_LDFLAGS} -lSDL2_ttf - endif endif endif endif @@ -970,6 +994,17 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) $(info *** Warning ***) endif endif + # poll() vs. select(): + sim_use_select=0 + sim_use_poll=0 + ifneq (,$(call find_include,poll)) + $(info poll()-ing for sockets) + sim_use_poll=1 + else + $(info select()-ing for sockets) + sim_use_select=1 + endif + OS_CCDEFS += -DSIM_USE_SELECT=${sim_use_select} -DSIM_USE_POLL=${sim_use_poll} # Consider other network connections ifneq (,$(call find_lib,vdeplug)) # libvdeplug requires the use of the OS provided libpcap @@ -1059,9 +1094,16 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) NETWORK_CCDEFS += -DUSE_NETWORK endif endif - ifeq (slirp,$(shell if ${TEST} -e slirp_glue/sim_slirp.c; then echo slirp; fi)) - NETWORK_CCDEFS += -Islirp -Islirp_glue -Islirp_glue/qemu -DHAVE_SLIRP_NETWORK -DUSE_SIMH_SLIRP_DEBUG slirp/*.c slirp_glue/*.c + ifeq (libslirp,$(shell if ${TEST} -e ${LIBSLIRP_DIR}; then echo libslirp; fi)) + SLIRP_DEP=${BIN}libslirp.dir/libslirp.a + NETWORK_CCDEFS += -I${LIBSLIRP_SRC} -I${SIMHD}/libslirp/minimal -I${SIMHD}/sim_slirp -I${SIMHD}/sim_slirp/config \ + -DHAVE_SLIRP_NETWORK + NETWORK_CCDEFS += sim_slirp/sim_slirp.c sim_slirp/slirp_poll.c + NETWORK_LDFLAGS += ${BIN}libslirp.dir/libslirp.a NETWORK_LAN_FEATURES += NAT(SLiRP) + ifeq (Darwin,$(OSTYPE)) + OS_LDFLAGS += -lresolv + endif endif ifeq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS))$(findstring HAVE_VDE_NETWORK,$(NETWORK_CCDEFS))) NETWORK_CCDEFS += -DUSE_NETWORK @@ -1189,7 +1231,7 @@ else endif endif OS_CCDEFS += -fms-extensions $(PTHREADS_CCDEFS) - OS_LDFLAGS += -lm -lwsock32 -lwinmm $(PTHREADS_LDFLAGS) + SYS_LDFLAGS += -lm -lwsock32 -lwinmm $(PTHREADS_LDFLAGS) EXE = .exe ifneq (clean,${MAKECMDGOALS}) ifneq (buildtoolsexists,$(shell if exist BIN\buildtools (echo buildtoolsexists) else (mkdir BIN\buildtools))) @@ -1301,8 +1343,12 @@ else OS_LDFLAGS += -lpcre -L../windows-build/PCRE/lib/ $(info using libpcre: $(abspath ../windows-build/PCRE/lib/pcre.a) $(abspath ../windows-build/PCRE/include/pcre.h)) endif - ifeq (slirp,slirp) - NETWORK_OPT += -Islirp -Islirp_glue -Islirp_glue/qemu -DHAVE_SLIRP_NETWORK -DUSE_SIMH_SLIRP_DEBUG slirp/*.c slirp_glue/*.c -lIphlpapi + ifeq (libslirp,$(shell if ${TEST} -e ${LIBSLIRP_DIR}; then echo libslirp; fi)) + SLIRP_DEP=libslirp-dep + NETWORK_CCDEFS += -I${LIBSLIRP_SRC} -I${SIMHD}/libslirp/minimal -I${SIMHD}/sim_slirp -I${SIMHD}/sim_slirp/config \ + -DHAVE_SLIRP_NETWORK + NETWORK_CCDEFS += sim_slirp/sim_slirp.c sim_slirp/slirp_poll.c + NETWORK_LDFLAGS += ${BIN}libslirp.dir/libslirp.a NETWORK_LAN_FEATURES += NAT(SLiRP) endif endif @@ -1418,23 +1464,37 @@ CC := ${GCC} ${CC_STD} -U__STRICT_ANSI__ ${CFLAGS_G} ${CFLAGS_O} ${CFLAGS_GIT} $ ifneq (,${SIM_VERSION_MODE}) CC += -DSIM_VERSION_MODE="${SIM_VERSION_MODE}" endif -LDFLAGS := ${OS_LDFLAGS} ${NETWORK_LDFLAGS} ${LDFLAGS_O} +LDFLAGS := $(strip ${OS_LDFLAGS} ${LDFLAGS_O} ${SYS_LDFLAGS}) # # Common Libraries # -BIN = BIN/ -SIMHD = . SIM = ${SIMHD}/scp.c ${SIMHD}/sim_console.c ${SIMHD}/sim_fio.c \ ${SIMHD}/sim_timer.c ${SIMHD}/sim_sock.c ${SIMHD}/sim_tmxr.c \ ${SIMHD}/sim_ether.c ${SIMHD}/sim_tape.c ${SIMHD}/sim_disk.c \ ${SIMHD}/sim_serial.c ${SIMHD}/sim_video.c ${SIMHD}/sim_imd.c \ - ${SIMHD}/sim_card.c + ${SIMHD}/sim_card.c ${SIMHD}/sim_debtab.c DISPLAYD = ${SIMHD}/display SCSI = ${SIMHD}/sim_scsi.c +## libslirp sources for libslirp.a +LIBSLIRP_SOURCES=${LIBSLIRP_SRC}/arp_table.c ${LIBSLIRP_SRC}/bootp.c ${LIBSLIRP_SRC}/cksum.c \ + ${LIBSLIRP_SRC}/dhcpv6.c ${LIBSLIRP_SRC}/dnssearch.c ${LIBSLIRP_SRC}/if.c \ + ${LIBSLIRP_SRC}/ip6_icmp.c ${LIBSLIRP_SRC}/ip6_input.c ${LIBSLIRP_SRC}/ip6_output.c \ + ${LIBSLIRP_SRC}/ip_icmp.c ${LIBSLIRP_SRC}/ip_input.c ${LIBSLIRP_SRC}/ip_output.c \ + ${LIBSLIRP_SRC}/mbuf.c ${LIBSLIRP_SRC}/misc.c ${LIBSLIRP_SRC}/ncsi.c ${LIBSLIRP_SRC}/ndp_table.c \ + ${LIBSLIRP_SRC}/sbuf.c ${LIBSLIRP_SRC}/slirp.c ${LIBSLIRP_SRC}/socket.c ${LIBSLIRP_SRC}/state.c \ + ${LIBSLIRP_SRC}/stream.c ${LIBSLIRP_SRC}/tcp_input.c ${LIBSLIRP_SRC}/tcp_output.c \ + ${LIBSLIRP_SRC}/tcp_subr.c ${LIBSLIRP_SRC}/tcp_timer.c ${LIBSLIRP_SRC}/tftp.c ${LIBSLIRP_SRC}/udp.c \ + ${LIBSLIRP_SRC}/udp6.c ${LIBSLIRP_SRC}/util.c ${LIBSLIRP_SRC}/version.c ${LIBSLIRP_SRC}/vmstate.c \ + +LIBSLIRP_STUB_SRC=${LIBSLIRP_DIR}/minimal/glib-stubs.c + +LIBSLIRP_OBJS=${subst ${LIBSLIRP_SRC},${BIN}libslirp.dir,${LIBSLIRP_SOURCES:.c=.o}} \ + ${subst ${LIBSLIRP_DIR}/minimal,${BIN}libslirp.dir,${LIBSLIRP_STUB_SRC:.c=.o}} + # # Emulator source files and compile time options # @@ -1444,6 +1504,7 @@ PDP1 = ${PDP1D}/pdp1_lp.c ${PDP1D}/pdp1_cpu.c ${PDP1D}/pdp1_stddev.c \ ${PDP1D}/pdp1_sys.c ${PDP1D}/pdp1_dt.c ${PDP1D}/pdp1_drm.c \ ${PDP1D}/pdp1_clk.c ${PDP1D}/pdp1_dcs.c ${PDP1D}/pdp1_dpy.c ${DISPLAYL} PDP1_OPT = -I ${PDP1D} ${DISPLAY_OPT} $(PDP1_DISPLAY_OPT) +PDP1_LDFLAGS = ${VIDEO_LDFLAGS} ND100D = ${SIMHD}/ND100 @@ -1475,10 +1536,12 @@ PDP18B = ${PDP18BD}/pdp18b_dt.c ${PDP18BD}/pdp18b_drm.c ${PDP18BD}/pdp18b_cpu.c ifneq (,${DISPLAY_OPT}) PDP7_DISPLAY_OPT = -DDISPLAY_TYPE=DIS_TYPE30 -DPIX_SCALE=RES_HALF + PDP7_DISPLAY_LDFLAGS = ${VIDEO_LDFLAGS} endif PDP4_OPT = -DPDP4 -I ${PDP18BD} PDP7_OPT = -DPDP7 -I ${PDP18BD} ${DISPLAY_OPT} $(PDP7_DISPLAY_OPT) +PDP7_LDFLAGS = ${PDP7_DISPLAY_LDFLAGS} PDP9_OPT = -DPDP9 -I ${PDP18BD} PDP15_OPT = -DPDP15 -I ${PDP18BD} @@ -1503,6 +1566,7 @@ PDP11 = ${PDP11D}/pdp11_fp.c ${PDP11D}/pdp11_cpu.c ${PDP11D}/pdp11_dz.c \ ${PDP11D}/pdp11_mb.c ${PDP11D}/pdp11_rr.c \ ${DISPLAYL} ${DISPLAYNG} ${DISPLAYVT} PDP11_OPT = -DVM_PDP11 -I ${PDP11D} ${NETWORK_OPT} ${DISPLAY_OPT} ${AIO_CCDEFS} +PDP11_LDFLAGS = ${VIDEO_LDFLAGS} ${NETWORK_LDFLAGS} UC15D = ${SIMHD}/PDP11 @@ -1527,6 +1591,7 @@ VAX = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c ${VAXD}/vax_io.c \ ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_io_lib.c ${PDP11D}/pdp11_dup.c VAX_OPT = -DVM_VAX -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} ${AIO_CCDEFS} +VAX_LDFLAGS = ${NETWORK_LDFLAGS} VAX410 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ @@ -1538,6 +1603,7 @@ VAX410 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${VAXD}/vax4xx_va.c ${VAXD}/vax4xx_vc.c ${VAXD}/vax_lk.c \ ${VAXD}/vax_vs.c ${VAXD}/vax_gpx.c VAX410_OPT = -DVM_VAX -DVAX_410 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} ${NETWORK_OPT} ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} ${AIO_CCDEFS} +VAX410_LDFLAGS = ${NETWORK_LDFLAGS} VAX420 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ @@ -1548,8 +1614,9 @@ VAX420 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${VAXD}/vax4xx_rd.c ${VAXD}/vax4xx_rz80.c ${VAXD}/vax_xs.c \ ${VAXD}/vax4xx_va.c ${VAXD}/vax4xx_vc.c ${VAXD}/vax4xx_ve.c \ ${VAXD}/vax_lk.c ${VAXD}/vax_vs.c ${VAXD}/vax_gpx.c -VAX420_OPT = -DVM_VAX -DVAX_420 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} \ - ${AIO_CCDEFS} +VAX420_OPT = -DVM_VAX -DVAX_420 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} \ + ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} ${AIO_CCDEFS} +VAX420_LDFLAGS = ${NETWORK_LDFLAGS} VAX411_OPT = ${VAX420_OPT} -DVAX_411 VAX412_OPT = ${VAX420_OPT} -DVAX_412 VAX41A_OPT = ${VAX420_OPT} -DVAX_41A @@ -1566,6 +1633,7 @@ VAX43 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${VAXD}/vax4xx_rz80.c ${VAXD}/vax_xs.c ${VAXD}/vax4xx_vc.c \ ${VAXD}/vax4xx_ve.c ${VAXD}/vax_lk.c ${VAXD}/vax_vs.c VAX43_OPT = -DVM_VAX -DVAX_43 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} ${NETWORK_OPT} ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} ${AIO_CCDEFS} +VAX43_LDFLAGS = ${NETWORK_LDFLAGS} VAX440 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ @@ -1575,6 +1643,7 @@ VAX440 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${VAXD}/vax440_sysdev.c ${VAXD}/vax440_syslist.c ${VAXD}/vax4xx_dz.c \ ${VAXD}/vax_xs.c ${VAXD}/vax_lk.c ${VAXD}/vax_vs.c ${VAXD}/vax4xx_rz94.c VAX440_OPT = -DVM_VAX -DVAX_440 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} ${NETWORK_OPT} ${AIO_CCDEFS} +VAX440_LDFLAGS = ${NETWORK_LDFLAGS} VAX46_OPT = ${VAX440_OPT} -DVAX_46 VAX47_OPT = ${VAX440_OPT} -DVAX_47 VAX48_OPT = ${VAX440_OPT} -DVAX_48 @@ -1587,6 +1656,7 @@ IS1000 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${VAXD}/vax4xx_rz94.c ${VAXD}/vax4nn_stddev.c \ ${VAXD}/is1000_sysdev.c ${VAXD}/is1000_syslist.c IS1000_OPT = -DVM_VAX -DIS_1000 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} ${NETWORK_OPT} ${AIO_CCDEFS} +IS1000_LDFLAGS = ${NETWORK_LDFLAGS} VAX610 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ @@ -1599,8 +1669,9 @@ VAX610 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_io_lib.c -VAX610_OPT = -DVM_VAX -DVAX_610 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} \ - ${AIO_CCDEFS} +VAX610_OPT = -DVM_VAX -DVAX_610 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} \ + ${NETWORK_OPT} ${VIDEO_CCDEFS} ${AIO_CCDEFS} +VAX610_LDFLAGS = ${VIDEO_LDFLAGS} ${NETWORK_LDFLAGS} VAX630 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ @@ -1615,8 +1686,10 @@ VAX630 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_io_lib.c ${PDP11D}/pdp11_dup.c VAX620_OPT = -DVM_VAX -DVAX_620 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} -VAX630_OPT = -DVM_VAX -DVAX_630 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} \ - ${AIO_CCDEFS} +VAX620_LDFLAGS = ${NETWORK_LDFLAGS} +VAX630_OPT = -DVM_VAX -DVAX_630 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} \ + ${NETWORK_OPT} ${VIDEO_CCDEFS} ${AIO_CCDEFS} +VAX630_LDFLAGS = ${VIDEO_LDFLAGS} ${NETWORK_LDFLAGS} VAX730 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ @@ -1632,6 +1705,7 @@ VAX730 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_tc.c ${PDP11D}/pdp11_rk.c \ ${PDP11D}/pdp11_io_lib.c ${PDP11D}/pdp11_ch.c ${PDP11D}/pdp11_dup.c VAX730_OPT = -DVM_VAX -DVAX_730 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} ${AIO_CCDEFS} +VAX730_LDFLAGS = ${NETWORK_LDFLAGS} VAX750 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ @@ -1648,6 +1722,7 @@ VAX750 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_tc.c ${PDP11D}/pdp11_rk.c \ ${PDP11D}/pdp11_io_lib.c ${PDP11D}/pdp11_ch.c VAX750_OPT = -DVM_VAX -DVAX_750 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} ${AIO_CCDEFS} +VAX750_LDFLAGS = ${NETWORK_LDFLAGS} VAX780 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ @@ -1664,6 +1739,7 @@ VAX780 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_tc.c ${PDP11D}/pdp11_rk.c \ ${PDP11D}/pdp11_io_lib.c ${PDP11D}/pdp11_ch.c VAX780_OPT = -DVM_VAX -DVAX_780 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} ${AIO_CCDEFS} +VAX780_LDFLAGS = ${NETWORK_LDFLAGS} VAX8200 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ @@ -1679,6 +1755,7 @@ VAX8200 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_tc.c ${PDP11D}/pdp11_rk.c \ ${PDP11D}/pdp11_io_lib.c ${PDP11D}/pdp11_ch.c ${PDP11D}/pdp11_dup.c VAX8200_OPT = -DVM_VAX -DVAX_820 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} ${AIO_CCDEFS} +VAX8200_LDFLAGS = ${NETWORK_LDFLAGS} VAX8600 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ @@ -1695,6 +1772,7 @@ VAX8600 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_tc.c ${PDP11D}/pdp11_rk.c \ ${PDP11D}/pdp11_io_lib.c ${PDP11D}/pdp11_ch.c VAX8600_OPT = -DVM_VAX -DVAX_860 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} ${AIO_CCDEFS} +VAX8600_LDFLAGS = ${NETWORK_LDFLAGS} PDP10D = ${SIMHD}/PDP10 @@ -1705,7 +1783,8 @@ PDP10 = ${PDP10D}/pdp10_fe.c ${PDP11D}/pdp11_dz.c ${PDP10D}/pdp10_cpu.c \ ${PDP11D}/pdp11_pt.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_dmc.c ${PDP11D}/pdp11_kmc.c \ ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ch.c -PDP10_OPT = -DVM_PDP10 -DUSE_INT64 -I ${PDP10D} -I ${PDP11D} ${NETWORK_OPT} +PDP10_OPT = -DVM_PDP10 -DUSE_INT64 -I ${PDP10D} -I ${PDP11D} ${NETWORK_OPT} ${AIO_CCDEFS} +PDP10_LDFLAGS = ${NETWORK_LDFLAGS} IMLACD = ${SIMHD}/imlac @@ -1714,6 +1793,7 @@ IMLAC = ${IMLACD}/imlac_sys.c ${IMLACD}/imlac_cpu.c \ ${IMLACD}/imlac_tty.c ${IMLACD}/imlac_pt.c ${IMLACD}/imlac_bel.c \ ${DISPLAYL} IMLAC_OPT = -I ${IMLACD} ${DISPLAY_OPT} ${AIO_CCDEFS} +IMLAC_LDFLAGS = ${VIDEO_LDFLAGS} STUBD = ${SIMHD}/stub @@ -1727,6 +1807,7 @@ TT2500 = ${TT2500D}/tt2500_sys.c ${TT2500D}/tt2500_cpu.c \ ${TT2500D}/tt2500_key.c ${TT2500D}/tt2500_uart.c ${TT2500D}/tt2500_rom.c \ ${DISPLAYL} TT2500_OPT = -I ${TT2500D} ${DISPLAY_OPT} ${AIO_CCDEFS} +TT2500_LDFLAGS = ${VIDEO_LDFLAGS} PDP8D = ${SIMHD}/PDP8 @@ -2022,6 +2103,7 @@ TX0D = ${SIMHD}/TX-0 TX0 = ${TX0D}/tx0_cpu.c ${TX0D}/tx0_dpy.c ${TX0D}/tx0_stddev.c \ ${TX0D}/tx0_sys.c ${TX0D}/tx0_sys_orig.c ${DISPLAYL} TX0_OPT = -I ${TX0D} ${DISPLAY_OPT} +TX0_LDFLAGS = ${VIDEO_LDFLAGS} SSEMD = ${SIMHD}/SSEM @@ -2041,6 +2123,7 @@ BESM6 = ${BESM6D}/besm6_cpu.c ${BESM6D}/besm6_sys.c ${BESM6D}/besm6_mmu.c \ ${BESM6D}/besm6_pl.c ${BESM6D}/besm6_mg.c \ ${BESM6D}/besm6_punch.c ${BESM6D}/besm6_punchcard.c ${BESM6D}/besm6_vu.c BESM6_OPT = -I ${BESM6D} -DUSE_INT64 $(BESM6_PANEL_OPT) +BESM6_LDFLAGS = ${BESM6_PANEL_LDFLAGS} ${VIDEO_LDFLAGS} PDP6D = ${SIMHD}/PDP10 ifneq (,${DISPLAY_OPT}) @@ -2054,6 +2137,7 @@ PDP6 = ${PDP6D}/kx10_cpu.c ${PDP6D}/kx10_sys.c ${PDP6D}/kx10_cty.c \ ${DISPLAYL} ${DISPLAY340} PDP6_OPT = -DPDP6=1 -DUSE_INT64 -I ${PDP6D} -DUSE_SIM_CARD ${DISPLAY_OPT} ${PDP6_DISPLAY_OPT} \ ${AIO_CCDEFS} +PDP6_LDFLAGS = ${VIDEO_LDFLAGS} KA10D = ${SIMHD}/PDP10 ifneq (,${DISPLAY_OPT}) @@ -2075,6 +2159,7 @@ KA10 = ${KA10D}/kx10_cpu.c ${KA10D}/kx10_sys.c ${KA10D}/kx10_df.c \ ${KA10D}/ka10_pclk.c ${KA10D}/ka10_tv.c ${KA10D}/ka10_dd.c \ ${KA10D}/kx10_ddc.c ${DISPLAYL} ${DISPLAY340} ${DISPLAYIII} KA10_OPT = -DKA=1 -DUSE_INT64 -I ${KA10D} -DUSE_SIM_CARD ${NETWORK_OPT} ${DISPLAY_OPT} ${KA10_DISPLAY_OPT} ${AIO_CCDEFS} +KA10_LDFLAGS = ${VIDEO_LDFLAGS} ${NETWORK_LDFLAGS} ifneq (${PANDA_LIGHTS},) # ONLY for Panda display. KA10_OPT += -DPANDA_LIGHTS @@ -2095,6 +2180,7 @@ KI10 = ${KI10D}/kx10_cpu.c ${KI10D}/kx10_sys.c ${KI10D}/kx10_df.c \ ${KI10D}/kx10_imp.c ${KI10D}/kx10_dpy.c ${KI10D}/kx10_disk.c \ ${KI10D}/kx10_ddc.c ${KI10D}/kx10_tym.c ${DISPLAYL} ${DISPLAY340} KI10_OPT = -DKI=1 -DUSE_INT64 -I ${KI10D} -DUSE_SIM_CARD ${NETWORK_OPT} ${DISPLAY_OPT} ${KI10_DISPLAY_OPT} ${AIO_CCDEFS} +KI10_LDFLAGS = ${VIDEO_LDFLAGS} ${NETWORK_LDFLAGS} ifneq (${PANDA_LIGHTS},) # ONLY for Panda display. KI10_OPT += -DPANDA_LIGHTS @@ -2110,7 +2196,8 @@ KL10 = ${KL10D}/kx10_cpu.c ${KL10D}/kx10_sys.c ${KL10D}/kx10_df.c \ ${KL10D}/kx10_rp.c ${KL10D}/kx10_tu.c ${KL10D}/kx10_rs.c \ ${KL10D}/kx10_imp.c ${KL10D}/kl10_fe.c ${KL10D}/ka10_pd.c \ ${KL10D}/ka10_ch10.c ${KL10D}/kl10_nia.c ${KL10D}/kx10_disk.c -KL10_OPT = -DKL=1 -DUSE_INT64 -I $(KL10D) -DUSE_SIM_CARD ${NETWORK_OPT} ${AIO_CCDEFS} +KL10_OPT = -DKL=1 -DUSE_INT64 -I $(KL10D) -DUSE_SIM_CARD ${NETWORK_OPT} ${AIO_CCDEFS} +KL10_LDFLAGS = ${NETWORK_LDFLAGS} KS10D = ${SIMHD}/PDP10 KS10 = ${KS10D}/kx10_cpu.c ${KS10D}/kx10_sys.c ${KS10D}/kx10_disk.c \ @@ -2119,6 +2206,7 @@ KS10 = ${KS10D}/kx10_cpu.c ${KS10D}/kx10_sys.c ${KS10D}/kx10_disk.c \ ${KS10D}/ks10_tcu.c ${KS10D}/ks10_lp.c ${KS10D}/ks10_ch11.c \ ${KS10D}/ks10_kmc.c ${KS10D}/ks10_dup.c ${KS10D}/kx10_imp.c KS10_OPT = -DKS=1 -DUSE_INT64 -I $(KS10D) -I $(PDP11D) ${NETWORK_OPT} ${AIO_CCDEFS} +KS10_LDFLAGS = ${NETWORK_LDFLAGS} ATT3B2D = ${SIMHD}/3B2 ATT3B2M400 = ${ATT3B2D}/3b2_cpu.c ${ATT3B2D}/3b2_sys.c \ @@ -2131,6 +2219,7 @@ ATT3B2M400 = ${ATT3B2D}/3b2_cpu.c ${ATT3B2D}/3b2_sys.c \ ${ATT3B2D}/3b2_ports.c ${ATT3B2D}/3b2_ctc.c \ ${ATT3B2D}/3b2_ni.c ATT3B2M400_OPT = -DUSE_INT64 -DUSE_ADDR64 -DREV2 -I ${ATT3B2D} ${NETWORK_OPT} ${AIO_CCDEFS} +ATT3B2M400_LDFLAGS = ${NETWORK_LDFLAGS} ATT3B2M700 = ${ATT3B2D}/3b2_cpu.c ${ATT3B2D}/3b2_sys.c \ ${ATT3B2D}/3b2_rev3_sys.c ${ATT3B2D}/3b2_rev3_mmu.c \ @@ -2141,6 +2230,7 @@ ATT3B2M700 = ${ATT3B2D}/3b2_cpu.c ${ATT3B2D}/3b2_sys.c \ ${ATT3B2D}/3b2_io.c ${ATT3B2D}/3b2_ports.c \ ${ATT3B2D}/3b2_scsi.c ${ATT3B2D}/3b2_ni.c ATT3B2M700_OPT = -DUSE_INT64 -DUSE_ADDR64 -DREV3 -I ${ATT3B2D} ${NETWORK_OPT} ${AIO_CCDEFS} +ATT3B2M700_LDFLAGS = ${NETWORK_LDFLAGS} SIGMAD = ${SIMHD}/sigma SIGMA = ${SIGMAD}/sigma_cpu.c ${SIGMAD}/sigma_sys.c ${SIGMAD}/sigma_cis.c \ @@ -2159,6 +2249,7 @@ SEL32 = ${SEL32D}/sel32_cpu.c ${SEL32D}/sel32_sys.c ${SEL32D}/sel32_chan.c \ ${SEL32D}/sel32_hsdp.c ${SEL32D}/sel32_mfp.c ${SEL32D}/sel32_scsi.c \ ${SEL32D}/sel32_ec.c ${SEL32D}/sel32_ipu.c SEL32_OPT = -I $(SEL32D) -DUSE_INT32 -DSEL32 ${NETWORK_OPT} +SEL32_LDFLAGS = ${NETWORK_LDFLAGS} ### ### Experimental simulators @@ -2222,9 +2313,10 @@ EXPERIMENTAL = alpha pdq3 sage experimental : ${EXPERIMENTAL} -clean : +clean :: ifeq (${WIN32},) - ${RM} -rf ${BIN} + ${RM} -rf ${SIMHD}/sim_slirp/config/glib-endian.h ${SIMHD}/sim_slirp/config/libslirp-version.h \ + ${SIMHD}/sim_slirp/config/mk-glib-endian ${BIN} else if exist BIN rmdir /s /q BIN endif @@ -2245,7 +2337,7 @@ pdp1 : ${BIN}pdp1${EXE} ${BIN}pdp1${EXE} : ${PDP1} ${SIM} ${MKDIRBIN} - ${CC} ${PDP1} ${SIM} ${PDP1_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${PDP1} ${SIM} ${PDP1_OPT} ${CC_OUTSPEC} ${PDP1_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${PDP1D},pdp1)) $@ $(call find_test,${PDP1D},pdp1) ${TEST_ARG} endif @@ -2263,7 +2355,7 @@ pdp7 : ${BIN}pdp7${EXE} ${BIN}pdp7${EXE} : ${PDP18B} ${PDP18BD}/pdp18b_dpy.c ${DISPLAYL} ${DISPLAY340} ${SIM} ${MKDIRBIN} - ${CC} ${PDP18B} ${PDP18BD}/pdp18b_dpy.c ${DISPLAYL} ${DISPLAY340} ${SIM} ${PDP7_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${PDP18B} ${PDP18BD}/pdp18b_dpy.c ${DISPLAYL} ${DISPLAY340} ${SIM} ${PDP7_OPT} ${CC_OUTSPEC} ${PDP7_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${PDP18BD},pdp7)) $@ $(call find_test,${PDP18BD},pdp7) ${TEST_ARG} endif @@ -2297,9 +2389,9 @@ endif pdp10 : ${BIN}pdp10${EXE} -${BIN}pdp10${EXE} : ${PDP10} ${SIM} +${BIN}pdp10${EXE} : ${PDP10} ${SIM} ${SLIRP_DEP} ${MKDIRBIN} - ${CC} ${PDP10} ${SIM} ${PDP10_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${PDP10} ${SIM} ${PDP10_OPT} ${CC_OUTSPEC} ${PDP10_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${PDP10D},pdp10)) $@ $(call find_test,${PDP10D},pdp10) ${TEST_ARG} endif @@ -2308,7 +2400,7 @@ imlac : ${BIN}imlac${EXE} ${BIN}imlac${EXE} : ${IMLAC} ${SIM} ${MKDIRBIN} - ${CC} ${IMLAC} ${SIM} ${IMLAC_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${IMLAC} ${SIM} ${IMLAC_OPT} ${CC_OUTSPEC} ${IMLAC_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${IMLAC},imlac)) $@ $(call find_test,${IMLACD},imlac) ${TEST_ARG} endif @@ -2323,16 +2415,16 @@ tt2500 : ${BIN}tt2500${EXE} ${BIN}tt2500${EXE} : ${TT2500} ${SIM} ${MKDIRBIN} - ${CC} ${TT2500} ${SIM} ${TT2500_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${TT2500} ${SIM} ${TT2500_OPT} ${CC_OUTSPEC} ${TT2500_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${TT2500},tt2500)) $@ $(call find_test,${TT2500D},tt2500) ${TEST_ARG} endif pdp11 : ${BIN}pdp11${EXE} -${BIN}pdp11${EXE} : ${PDP11} ${SIM} ${BUILD_ROMS} +${BIN}pdp11${EXE} : ${PDP11} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${PDP11} ${SIM} ${PDP11_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${PDP11} ${SIM} ${PDP11_OPT} ${CC_OUTSPEC} ${PDP11_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${PDP11D},pdp11)) $@ $(call find_test,${PDP11D},pdp11) ${TEST_ARG} endif @@ -2350,9 +2442,9 @@ microvax3900 : vax vax : ${BIN}vax${EXE} -${BIN}vax${EXE} : ${VAX} ${SIM} ${BUILD_ROMS} +${BIN}vax${EXE} : ${VAX} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX} ${SIM} ${VAX_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${VAX} ${SIM} ${VAX_OPT} ${CC_OUTSPEC} ${VAX_LDFLAGS} ${LDFLAGS} ifeq (${WIN32},) cp ${BIN}vax${EXE} ${BIN}microvax3900${EXE} else @@ -2364,180 +2456,180 @@ endif microvax2000 : ${BIN}microvax2000${EXE} -${BIN}microvax2000${EXE} : ${VAX410} ${SIM} ${BUILD_ROMS} +${BIN}microvax2000${EXE} : ${VAX410} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX410} ${SCSI} ${SIM} ${VAX410_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX410} ${SCSI} ${SIM} ${VAX410_OPT} -o $@ ${VAX410_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif infoserver100 : ${BIN}infoserver100${EXE} -${BIN}infoserver100${EXE} : ${VAX420} ${SCSI} ${SIM} ${BUILD_ROMS} +${BIN}infoserver100${EXE} : ${VAX420} ${SCSI} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX420} ${SCSI} ${SIM} ${VAX411_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX420} ${SCSI} ${SIM} ${VAX411_OPT} -o $@ ${VAX420_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif infoserver150vxt : ${BIN}infoserver150vxt${EXE} -${BIN}infoserver150vxt${EXE} : ${VAX420} ${SCSI} ${SIM} ${BUILD_ROMS} +${BIN}infoserver150vxt${EXE} : ${VAX420} ${SCSI} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX420} ${SCSI} ${SIM} ${VAX412_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX420} ${SCSI} ${SIM} ${VAX412_OPT} -o $@ ${VAX420_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif microvax3100 : ${BIN}microvax3100${EXE} -${BIN}microvax3100${EXE} : ${VAX420} ${SCSI} ${SIM} ${BUILD_ROMS} +${BIN}microvax3100${EXE} : ${VAX420} ${SCSI} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX420} ${SCSI} ${SIM} ${VAX41A_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX420} ${SCSI} ${SIM} ${VAX41A_OPT} -o $@ ${VAX420_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif microvax3100e : ${BIN}microvax3100e${EXE} -${BIN}microvax3100e${EXE} : ${VAX420} ${SCSI} ${SIM} ${BUILD_ROMS} +${BIN}microvax3100e${EXE} : ${VAX420} ${SCSI} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX420} ${SCSI} ${SIM} ${VAX41D_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX420} ${SCSI} ${SIM} ${VAX41D_OPT} -o $@ ${VAX420_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif vaxstation3100m30 : ${BIN}vaxstation3100m30${EXE} -${BIN}vaxstation3100m30${EXE} : ${VAX420} ${SCSI} ${SIM} ${BUILD_ROMS} +${BIN}vaxstation3100m30${EXE} : ${VAX420} ${SCSI} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX420} ${SCSI} ${SIM} ${VAX42A_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX420} ${SCSI} ${SIM} ${VAX42A_OPT} -o $@ ${VAX420_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif vaxstation3100m38 : ${BIN}vaxstation3100m38${EXE} -${BIN}vaxstation3100m38${EXE} : ${VAX420} ${SCSI} ${SIM} ${BUILD_ROMS} +${BIN}vaxstation3100m38${EXE} : ${VAX420} ${SCSI} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX420} ${SCSI} ${SIM} ${VAX42B_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX420} ${SCSI} ${SIM} ${VAX42B_OPT} -o $@ ${VAX420_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif vaxstation3100m76 : ${BIN}vaxstation3100m76${EXE} -${BIN}vaxstation3100m76${EXE} : ${VAX43} ${SCSI} ${SIM} ${BUILD_ROMS} +${BIN}vaxstation3100m76${EXE} : ${VAX43} ${SCSI} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX43} ${SCSI} ${SIM} ${VAX43_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX43} ${SCSI} ${SIM} ${VAX43_OPT} -o $@ ${VAX43_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif vaxstation4000m60 : ${BIN}vaxstation4000m60${EXE} -${BIN}vaxstation4000m60${EXE} : ${VAX440} ${SCSI} ${SIM} ${BUILD_ROMS} +${BIN}vaxstation4000m60${EXE} : ${VAX440} ${SCSI} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX440} ${SCSI} ${SIM} ${VAX46_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX440} ${SCSI} ${SIM} ${VAX46_OPT} -o $@ ${VAX440_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif microvax3100m80 : ${BIN}microvax3100m80${EXE} -${BIN}microvax3100m80${EXE} : ${VAX440} ${SCSI} ${SIM} ${BUILD_ROMS} +${BIN}microvax3100m80${EXE} : ${VAX440} ${SCSI} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX440} ${SCSI} ${SIM} ${VAX47_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX440} ${SCSI} ${SIM} ${VAX47_OPT} -o $@ ${VAX440_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif vaxstation4000vlc : ${BIN}vaxstation4000vlc${EXE} -${BIN}vaxstation4000vlc${EXE} : ${VAX440} ${SCSI} ${SIM} ${BUILD_ROMS} +${BIN}vaxstation4000vlc${EXE} : ${VAX440} ${SCSI} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX440} ${SCSI} ${SIM} ${VAX48_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX440} ${SCSI} ${SIM} ${VAX48_OPT} -o $@ ${VAX440_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif infoserver1000 : ${BIN}infoserver1000${EXE} -${BIN}infoserver1000${EXE} : ${IS1000} ${SCSI} ${SIM} ${BUILD_ROMS} +${BIN}infoserver1000${EXE} : ${IS1000} ${SCSI} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${IS1000} ${SCSI} ${SIM} ${IS1000_OPT} -o $@ ${LDFLAGS} + ${CC} ${IS1000} ${SCSI} ${SIM} ${IS1000_OPT} -o $@ ${IS1000_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif microvax1 : ${BIN}microvax1${EXE} -${BIN}microvax1${EXE} : ${VAX610} ${SIM} ${BUILD_ROMS} +${BIN}microvax1${EXE} : ${VAX610} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX610} ${SIM} ${VAX610_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX610} ${SIM} ${VAX610_OPT} -o $@ ${VAX610_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif rtvax1000 : ${BIN}rtvax1000${EXE} -${BIN}rtvax1000${EXE} : ${VAX630} ${SIM} ${BUILD_ROMS} +${BIN}rtvax1000${EXE} : ${VAX630} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX630} ${SIM} ${VAX620_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX630} ${SIM} ${VAX620_OPT} -o $@ ${VAX620_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif microvax2 : ${BIN}microvax2${EXE} -${BIN}microvax2${EXE} : ${VAX630} ${SIM} ${BUILD_ROMS} +${BIN}microvax2${EXE} : ${VAX630} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX630} ${SIM} ${VAX630_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX630} ${SIM} ${VAX630_OPT} -o $@ ${VAX630_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif vax730 : ${BIN}vax730${EXE} -${BIN}vax730${EXE} : ${VAX730} ${SIM} ${BUILD_ROMS} +${BIN}vax730${EXE} : ${VAX730} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX730} ${SIM} ${VAX730_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX730} ${SIM} ${VAX730_OPT} -o $@ ${VAX730_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif vax750 : ${BIN}vax750${EXE} -${BIN}vax750${EXE} : ${VAX750} ${SIM} ${BUILD_ROMS} +${BIN}vax750${EXE} : ${VAX750} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX750} ${SIM} ${VAX750_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX750} ${SIM} ${VAX750_OPT} -o $@ ${VAX750_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif vax780 : ${BIN}vax780${EXE} -${BIN}vax780${EXE} : ${VAX780} ${SIM} ${BUILD_ROMS} +${BIN}vax780${EXE} : ${VAX780} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX780} ${SIM} ${VAX780_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${VAX780} ${SIM} ${VAX780_OPT} ${CC_OUTSPEC} ${VAX780_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif vax8200 : ${BIN}vax8200${EXE} -${BIN}vax8200${EXE} : ${VAX8200} ${SIM} ${BUILD_ROMS} +${BIN}vax8200${EXE} : ${VAX8200} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX8200} ${SIM} ${VAX8200_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${VAX8200} ${SIM} ${VAX8200_OPT} ${CC_OUTSPEC} ${VAX780_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif vax8600 : ${BIN}vax8600${EXE} -${BIN}vax8600${EXE} : ${VAX8600} ${SIM} ${BUILD_ROMS} +${BIN}vax8600${EXE} : ${VAX8600} ${SIM} ${SLIRP_DEP} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX8600} ${SIM} ${VAX8600_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${VAX8600} ${SIM} ${VAX8600_OPT} ${CC_OUTSPEC} ${VAX8600_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif @@ -2661,9 +2753,9 @@ endif sel32: ${BIN}sel32${EXE} -${BIN}sel32${EXE}: ${SEL32} ${SIM} +${BIN}sel32${EXE}: ${SEL32} ${SIM} ${SLIRP_DEP} ${MKDIRBIN} - ${CC} ${SEL32} ${SIM} ${SEL32_OPT} $(CC_OUTSPEC) ${LDFLAGS} + ${CC} ${SEL32} ${SIM} ${SEL32_OPT} $(CC_OUTSPEC) ${SEL32_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${SEL32D},sel32)) $@ $(call find_test,${SEL32D},sel32) $(TEST_ARG) endif @@ -2791,7 +2883,7 @@ tx-0 : ${BIN}tx-0${EXE} ${BIN}tx-0${EXE} : ${TX0} ${SIM} ${MKDIRBIN} - ${CC} ${TX0} ${SIM} ${TX0_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${TX0} ${SIM} ${TX0_OPT} ${CC_OUTSPEC} ${TX0_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${TX0D},tx-0)) $@ $(call find_test,${TX0D},tx-0) ${TEST_ARG} endif @@ -2819,7 +2911,7 @@ besm6 : ${BIN}besm6${EXE} ${BIN}besm6${EXE} : ${BESM6} ${SIM} ifneq (1,${CPP_BUILD}${CPP_FORCE}) ${MKDIRBIN} - ${CC} ${BESM6} ${SIM} ${BESM6_OPT} ${BESM6_PANEL_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${BESM6} ${SIM} ${BESM6_OPT} ${BESM6_PANEL_OPT} ${CC_OUTSPEC} ${BESM6_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${BESM6D},besm6)) $@ $(call find_test,${BESM6D},besm6) ${TEST_ARG} endif @@ -2876,9 +2968,9 @@ endif 3b2 : ${BIN}3b2${EXE} -${BIN}3b2${EXE} : ${ATT3B2M400} ${SIM} +${BIN}3b2${EXE} : ${ATT3B2M400} ${SIM} ${SLIRP_DEP} ${MKDIRBIN} - ${CC} ${ATT3B2M400} ${SIM} ${ATT3B2M400_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${ATT3B2M400} ${SIM} ${ATT3B2M400_OPT} ${CC_OUTSPEC} ${ATT3B2M400_LDFLAGS} ${LDFLAGS} ifeq (${WIN32},) cp ${BIN}3b2${EXE} ${BIN}3b2-400${EXE} else @@ -2890,9 +2982,9 @@ endif 3b2-700 : ${BIN}3b2-700${EXE} -${BIN}3b2-700${EXE} : ${ATT3B2M700} ${SIM} +${BIN}3b2-700${EXE} : ${ATT3B2M700} ${SIM} ${SLIRP_DEP} ${MKDIRBIN} - ${CC} ${ATT3B2M700} ${SCSI} ${SIM} ${ATT3B2M700_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${ATT3B2M700} ${SCSI} ${SIM} ${ATT3B2M700_OPT} ${CC_OUTSPEC} ${ATT3B2M700_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${ATT3B2D},3b2-700)) $@ $(call find_test,${ATT3B2D},3b2-700) ${TEST_ARG} endif @@ -2964,43 +3056,43 @@ pdp6 : ${BIN}pdp6${EXE} ${BIN}pdp6${EXE} : ${PDP6} ${SIM} ${MKDIRBIN} - ${CC} ${PDP6} ${PDP6_DPY} ${SIM} ${PDP6_OPT} ${CC_OUTSPEC} ${LDFLAGS} ${PDP6_LDFLAGS} + ${CC} ${PDP6} ${PDP6_DPY} ${SIM} ${PDP6_OPT} ${CC_OUTSPEC} ${PDP6_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${PDP10D},pdp6)) $@ $(call find_test,${PDP10D},pdp6) ${TEST_ARG} endif pdp10-ka : ${BIN}pdp10-ka${EXE} -${BIN}pdp10-ka${EXE} : ${KA10} ${SIM} +${BIN}pdp10-ka${EXE} : ${KA10} ${SIM} ${SLIRP_DEP} ${MKDIRBIN} - ${CC} ${KA10} ${KA10_DPY} ${SIM} ${KA10_OPT} ${CC_OUTSPEC} ${LDFLAGS} ${KA10_LDFLAGS} + ${CC} ${KA10} ${KA10_DPY} ${SIM} ${KA10_OPT} ${CC_OUTSPEC} ${KA10_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${PDP10D},ka10)) $@ $(call find_test,${PDP10D},ka10) ${TEST_ARG} endif pdp10-ki : ${BIN}pdp10-ki${EXE} -${BIN}pdp10-ki${EXE} : ${KI10} ${SIM} +${BIN}pdp10-ki${EXE} : ${KI10} ${SIM} ${SLIRP_DEP} ${MKDIRBIN} - ${CC} ${KI10} ${KI10_DPY} ${SIM} ${KI10_OPT} ${CC_OUTSPEC} ${LDFLAGS} ${KI10_LDFLAGS} + ${CC} ${KI10} ${KI10_DPY} ${SIM} ${KI10_OPT} ${CC_OUTSPEC} ${KI10_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${PDP10D},ki10)) $@ $(call find_test,${PDP10D},ki10) ${TEST_ARG} endif pdp10-kl : ${BIN}pdp10-kl${EXE} -${BIN}pdp10-kl${EXE} : ${KL10} ${SIM} +${BIN}pdp10-kl${EXE} : ${KL10} ${SIM} ${SLIRP_DEP} ${MKDIRBIN} - ${CC} ${KL10} ${SIM} ${KL10_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${KL10} ${SIM} ${KL10_OPT} ${CC_OUTSPEC} ${KL10_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${PDP10D},kl10)) $@ $(call find_test,${PDP10D},kl10) ${TEST_ARG} endif pdp10-ks : ${BIN}pdp10-ks${EXE} -${BIN}pdp10-ks${EXE} : ${KS10} ${SIM} +${BIN}pdp10-ks${EXE} : ${KS10} ${SIM} ${SLIRP_DEP} ${MKDIRBIN} - ${CC} ${KS10} ${SIM} ${KS10_OPT} ${CC_OUTSPEC} ${LDFLAGS} + ${CC} ${KS10} ${SIM} ${KS10_OPT} ${CC_OUTSPEC} ${NETWORK_LDFLAGS} ${LDFLAGS} ifneq (,$(call find_test,${PDP10D},ks10)) $@ $(call find_test,${PDP10D},ks10) ${TEST_ARG} endif @@ -3014,3 +3106,69 @@ ${BIN}frontpaneltest${EXE} : frontpanel/FrontPanelTest.c sim_sock.c sim_frontpan ${MKDIRBIN} ${CC} frontpanel/FrontPanelTest.c sim_sock.c sim_frontpanel.c ${CC_OUTSPEC} ${LDFLAGS} ${OS_CURSES_DEFS} +## libslirp library and configuration: + +RANLIB=$(shell which ranlib) +ifeq (,${RANLIB}) +RANLIB=: +endif + +LIBSLIRP_CONFIG_SRC=${SIMHD}/sim_slirp/config/libslirp_config.c +LIBSLIRP_CONFIG_TEST=${BIN}libslirp.dir/libslirp_config + +test_feature = \ + $(strip $(shell mkdir -p ${BIN}libslirp.dir > /dev/null 2>&1 && \ + ${GCC} ${CC_STD} -o ${LIBSLIRP_CONFIG_TEST} -D$(1) ${LIBSLIRP_CONFIG_SRC} > /dev/null 2>&1 && \ + ${LIBSLIRP_CONFIG_TEST} > /dev/null 2>&1 && \ + echo "Detected feature: $(2)" 1>&2 && \ + echo "feature" )) + +LIBSLIRP_FEATURES = -DBUILDING_LIBSLIRP -DLIBSLIRP_STATIC + +ifneq ($(call test_feature,TEST_VASPRINTF,vasprintf),) + LIBSLIRP_FEATURES += -DHAVE_VASPRINTF +else + ifneq ($(call test_feature,TEST_VASPRINTF_GNU_SOURCE,vasprintf with _GNU_SOURCE),) + LIBSLIRP_FEATURES += -DHAVE_VASPRINTF -D_GNU_SOURCE + endif +endif + +ifneq ($(call test_feature,TEST_CLOCK_GETTIME,clock_gettime),) + LIBSLIRP_FEATURES += -DHAVE_CLOCK_GETTIME -DHAVE_TIME_H +else + ifneq ($(call test_feature,TEST_GETTIMEOFDAY,gettimeofday),) + LIBSLIRP_FEATURES += -DHAVE_GETTIMEOFDAY -DHAVE_SYS_TIME_H + endif +endif + +ifneq ($(call test_feature,TEST_INET_PTON,inet_pton),) + LIBSLIRP_FEATURES += -DHAVE_INET_PTON +endif + +BUILD_LIBSLIRP_INCS=-I ${LIBSLIRP_SRC} -I ${LIBSLIRP_DIR}/minimal -I ${SIMHD}/sim_slirp/config + +${BIN}libslirp.dir/%.o: ${LIBSLIRP_SRC}/%.c + @mkdir -p ${BIN}libslirp.dir + ${GCC} ${CC_STD} ${CFLAGS_G} ${CFLAGS_O} ${CFLAGS_I} $(strip ${LIBSLIRP_FEATURES}) ${BUILD_LIBSLIRP_INCS} -o $@ -c $< + +${BIN}libslirp.dir/%.o: ${LIBSLIRP_DIR}/minimal/%.c + @mkdir -p ${BIN}libslirp.dir + ${GCC} ${CC_STD} ${CFLAGS_G} ${CFLAGS_O} ${CFLAGS_I} $(strip ${LIBSLIRP_FEATURES}) ${BUILD_LIBSLIRP_INCS} -o $@ -c $< + +${BIN}libslirp.dir/libslirp.a: \ + ${SIMHD}/sim_slirp/config/libslirp-version.h \ + ${SIMHD}/sim_slirp/config/glib-endian.h \ + ${LIBSLIRP_OBJS} + ${AR} rv $@ ${LIBSLIRP_OBJS} + ${RANLIB} $@ + +${SIMHD}/sim_slirp/config/libslirp-version.h: ${SIMHD}/sim_slirp/config/libslirp-version.awk + @ echo "Updating ${SIMHD}/sim_slirp/config/libslirp-version.h" + @ awk -f ${SIMHD}/sim_slirp/config/libslirp-version.awk ${SIMHD}/libslirp/meson.build > ${SIMHD}/sim_slirp/config/libslirp-version.h + +${SIMHD}/sim_slirp/config/glib-endian.h: ${SIMHD}/sim_slirp/config/mk-glib-endian + @ echo "Updating ${SIMHD}/sim_slirp/config/glib-endian.h" + @ ${SIMHD}/sim_slirp/config/mk-glib-endian > ${SIMHD}/sim_slirp/config/glib-endian.h + +${SIMHD}/sim_slirp/config/mk-glib-endian: ${SIMHD}/sim_slirp/config/mk-glib-endian.c + ${GCC} ${CC_STD} ${CFLAGS_G} ${CFLAGS_O} ${CFLAGS_I} -o $@ $< diff --git a/scp.c b/scp.c index 7d9ea9cf1..0fffb76be 100644 --- a/scp.c +++ b/scp.c @@ -376,6 +376,9 @@ pthread_mutex_t sim_timer_lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t sim_timer_wake = PTHREAD_COND_INITIALIZER; pthread_mutex_t sim_tmxr_poll_lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t sim_tmxr_poll_cond = PTHREAD_COND_INITIALIZER; + +pthread_mutex_t sim_debug_lock = PTHREAD_MUTEX_INITIALIZER; + int32 sim_tmxr_poll_count; pthread_t sim_asynch_main_threadid; UNIT * volatile sim_asynch_queue; @@ -400,7 +403,7 @@ if (AIO_QUEUE_VAL != QUEUE_LIST_END) { /* List !Empty */ ++migrated; uptr = q; q = q->a_next; - uptr->a_next = NULL; /* hygiene */ + uptr->a_next = NULL; /* hygiene */ if (uptr->a_activate_call != &sim_activate_notbefore) { a_event_time = uptr->a_event_time-((sim_asynch_inst_latency+1)/2); if (a_event_time < 0) @@ -434,7 +437,7 @@ else { uptr->a_activate_call = caller; do { q = AIO_QUEUE_VAL; - uptr->a_next = q; /* Mark as on list */ + uptr->a_next = q; /* Mark as on list */ } while (q != AIO_QUEUE_SET(uptr, q)); } AIO_IUNLOCK; @@ -448,6 +451,13 @@ if (sim_idle_wait) { t_bool sim_asynch_enabled = FALSE; #endif +/* sim_unit_aio_pending(): Test if the UNIT has pending asynch I/O. Does not + * depend on being in the main simulator thread, unlike sim_is_active(). */ +t_bool sim_unit_aio_pending(UNIT *uptr) +{ + return (uptr->next != NULL) || AIO_IS_ACTIVE(uptr); +} + /* The per-simulator init routine is a weak global that defaults to NULL The other per-simulator pointers can be overridden by the init routine @@ -12227,7 +12237,7 @@ t_bool sim_is_active (UNIT *uptr) { AIO_VALIDATE(uptr); AIO_UPDATE_QUEUE; -return (((uptr->next) || AIO_IS_ACTIVE(uptr) || ((uptr->dynflags & UNIT_TMR_UNIT) ? sim_timer_is_active (uptr) : FALSE)) ? TRUE : FALSE); +return ((sim_unit_aio_pending(uptr) || ((uptr->dynflags & UNIT_TMR_UNIT) ? sim_timer_is_active (uptr) : FALSE)) ? TRUE : FALSE); } /* sim_activate_time - return activation time @@ -13660,7 +13670,7 @@ if (sim_deb_switches & SWMASK ('F')) { /* filtering disabled? */ _debug_fwrite (buf, len); /* output now. */ return; /* done */ } -AIO_LOCK; +AIO_DEBUG_LOCK; if (debug_line_offset + len + 1 > debug_line_bufsize) { /* realloc(NULL, size) == malloc(size). Initialize the malloc()-ed space. Only need to test debug_line_buf since SIMH allocates both buffers at the same @@ -13745,7 +13755,7 @@ while (NULL != (eol = strchr (debug_line_buf, '\n')) || flush) { memmove (debug_line_buf, eol + 1, debug_line_offset); debug_line_buf[debug_line_offset] = '\0'; } -AIO_UNLOCK; +AIO_DEBUG_UNLOCK; } static void _sim_debug_write (const char *buf, size_t len) @@ -13814,14 +13824,15 @@ return some_match ? some_match : debtab_nomatch; /* Prints standard debug prefix unless previous call unterminated */ -static const char *sim_debug_prefix (uint32 dbits, DEVICE* dptr, UNIT* uptr) +static const char *sim_debug_prefix (const char *dev_name, const char *debug_type) { -const char* debug_type = _get_dbg_verb (dbits, dptr, uptr); char tim_t[32] = ""; char tim_a[32] = ""; char pc_s[MAX_WIDTH + 1] = ""; struct timespec time_now; +AIO_DEBUG_LOCK; + if (sim_deb_switches & (SWMASK ('T') | SWMASK ('R') | SWMASK ('A'))) { sim_rtcn_get_time(&time_now, 0); if (sim_deb_switches & SWMASK ('R')) @@ -13852,10 +13863,56 @@ if (sim_deb_switches & SWMASK ('P')) { sprintf(pc_s, "-%s:", sim_PC->name); sprint_val (&pc_s[strlen(pc_s)], val, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT); } -sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ", tim_t, tim_a, sim_gtime(), pc_s, AIO_MAIN_THREAD ? "" : "+", dptr->name, debug_type); + +sprintf(debug_line_prefix, "DBG(%s%s%.0f%s)%s> %s %s: ", tim_t, tim_a, sim_gtime(), pc_s, AIO_MAIN_THREAD ? "" : "+", dev_name, debug_type); +AIO_DEBUG_UNLOCK; + return debug_line_prefix; } +/* Expand the newlines in a debug message: */ + +void sim_debug_expand_newlines(char *buf, size_t len, const char *debug_prefix) +{ +size_t i, j; + +/* Output the formatted data expanding newlines where they exist */ +AIO_DEBUG_LOCK; +for (i = j = 0; i < len; ++i) { + if ('\n' == buf[i]) { + if (i >= j) { + if ((i != j) || (i == 0)) { + if (!debug_unterm) /* print prefix when required */ + _sim_debug_write (debug_prefix, strlen (debug_prefix)); + _sim_debug_write (&buf[j], i-j); + _sim_debug_write ("\r\n", 2); + } + debug_unterm = 0; + } + j = i + 1; + } + else { + if (buf[i] == 0) { /* Imbedded \0 character in formatted result? */ + fprintf (stderr, "sim_debug() formatted result: '%s'\r\n" + " has an imbedded \\0 character.\r\n" + "DON'T DO THAT!\r\n", buf); + abort(); + } + } + } +if (i > j) { + if (!debug_unterm) /* print prefix when required */ + _sim_debug_write (debug_prefix, strlen (debug_prefix)); + _sim_debug_write (&buf[j], i-j); + } + +/* Set unterminated flag for next time */ + +debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm; +AIO_DEBUG_UNLOCK; +} + + void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs) { int32 i, fields, offset; @@ -13907,11 +13964,13 @@ void sim_debug_bits_hdr(uint32 dbits, DEVICE* dptr, const char *header, BITFIELD* bitdefs, uint32 before, uint32 after, int terminate) { if (sim_deb && dptr && (dptr->dctrl & dbits)) { - TMLN *saved_oline = sim_oline; + TMLN *saved_oline; + AIO_DEBUG_LOCK; + saved_oline = sim_oline; sim_oline = NULL; /* avoid potential debug to active socket */ if (!debug_unterm) - fprintf(sim_deb, "%s", sim_debug_prefix(dbits, dptr, NULL)); /* print prefix if required */ + fprintf(sim_deb, "%s", sim_debug_prefix(dptr->name, NULL)); /* print prefix if required */ if (header) fprintf(sim_deb, "%s: ", header); fprint_fields (sim_deb, (t_value)before, (t_value)after, bitdefs); /* print xlation, transition */ @@ -13919,6 +13978,7 @@ if (sim_deb && dptr && (dptr->dctrl & dbits)) { fprintf(sim_deb, "\r\n"); debug_unterm = terminate ? 0 : 1; /* set unterm for next */ sim_oline = saved_oline; /* restore original socket */ + AIO_DEBUG_UNLOCK; } } @@ -13932,9 +13992,9 @@ sim_debug_bits_hdr(dbits, dptr, NULL, bitdefs, before, after, terminate); void sim_printf (const char* fmt, ...) { char stackbuf[STACKBUFSIZE]; -int32 bufsize = sizeof(stackbuf); +size_t bufsize = sizeof(stackbuf); char *buf = stackbuf; -int32 len; +int len; va_list arglist; while (1) { /* format passed string, args */ @@ -13948,18 +14008,23 @@ while (1) { /* format passed string, arg /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */ - if ((len < 0) || (len >= bufsize-1)) { + if ((len > 0) && ((size_t) len >= bufsize - 1)) { if (buf != stackbuf) free (buf); bufsize = bufsize * 2; - if (bufsize < len + 2) - bufsize = len + 2; + if (bufsize < (size_t) (len + 2)) + bufsize = (size_t) (len + 2); buf = (char *) malloc (bufsize); if (buf == NULL) /* out of memory */ return; buf[bufsize-1] = '\0'; continue; } + else if (len < 0) { + /* Output error. Dubious as to whether this really happens with + * vsprintf() or vsprintf(). */ + return; + } break; } @@ -13977,10 +14042,11 @@ if (sim_is_running) { } else fprintf (stdout, "%s", buf); -if ((!sim_oline) && (sim_log && (sim_log != stdout))) +if ((sim_oline == NULL) && (sim_log != NULL && sim_log != stdout)) fprintf (sim_log, "%s", buf); -if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log)) +if (sim_deb != NULL && (sim_deb != stdout) && (sim_deb != sim_log)) { _sim_debug_write (buf, strlen (buf)); +} if (buf != stackbuf) free (buf); @@ -14098,13 +14164,18 @@ return stat | ((stat != SCPE_OK) ? SCPE_NOMESSAGE : 0); void _sim_vdebug (uint32 dbits, DEVICE* dptr, UNIT *uptr, const char* fmt, va_list arglist) { if (sim_deb && dptr && ((dptr->dctrl | (uptr ? uptr->dctrl : 0)) & dbits)) { - TMLN *saved_oline = sim_oline; + TMLN *saved_oline; char stackbuf[STACKBUFSIZE]; int32 bufsize = sizeof(stackbuf); char *buf = stackbuf; - int32 i, j, len; - const char* debug_prefix = sim_debug_prefix(dbits, dptr, uptr); /* prefix to print if required */ + int32 len; + /* prefix to print when required */ + const char* debug_prefix; + AIO_DEBUG_LOCK; + + debug_prefix = sim_debug_prefix(dptr->name, _get_dbg_verb (dbits, dptr, uptr)); + saved_oline = sim_oline; sim_oline = NULL; /* avoid potential debug to active socket */ buf[bufsize-1] = '\0'; @@ -14124,50 +14195,34 @@ if (sim_deb && dptr && ((dptr->dctrl | (uptr ? uptr->dctrl : 0)) & dbits)) { if (bufsize < len + 2) bufsize = len + 2; buf = (char *) malloc (bufsize); - if (buf == NULL) /* out of memory */ + if (buf == NULL) { /* out of memory */ + AIO_DEBUG_UNLOCK; return; + } buf[bufsize-1] = '\0'; continue; } break; } -/* Output the formatted data expanding newlines where they exist */ + sim_debug_expand_newlines(buf, len, debug_prefix); - for (i = j = 0; i < len; ++i) { - if ('\n' == buf[i]) { - if (i >= j) { - if ((i != j) || (i == 0)) { - if (!debug_unterm) /* print prefix when required */ - _sim_debug_write (debug_prefix, strlen (debug_prefix)); - _sim_debug_write (&buf[j], i-j); - _sim_debug_write ("\r\n", 2); - } - debug_unterm = 0; - } - j = i + 1; - } - else { - if (buf[i] == 0) { /* Imbedded \0 character in formatted result? */ - fprintf (stderr, "sim_debug() formatted result: '%s'\r\n" - " has an imbedded \\0 character.\r\n" - "DON'T DO THAT!\r\n", buf); - abort(); - } - } - } - if (i > j) { - if (!debug_unterm) /* print prefix when required */ - _sim_debug_write (debug_prefix, strlen (debug_prefix)); - _sim_debug_write (&buf[j], i-j); - } - -/* Set unterminated flag for next time */ - - debug_unterm = len ? (((buf[len-1]=='\n')) ? 0 : 1) : debug_unterm; if (buf != stackbuf) free (buf); sim_oline = saved_oline; /* restore original socket */ + AIO_DEBUG_UNLOCK; + } +} + +void sim_misc_debug (const char *debug_thing, const char *debug_type, const char* msg) +{ +if (sim_deb != NULL) { + char *buf = strdup(msg); + + AIO_DEBUG_LOCK; + sim_debug_expand_newlines(buf, strlen(buf), sim_debug_prefix(debug_thing, debug_type)); + AIO_DEBUG_UNLOCK; + free(buf); } } diff --git a/scp.h b/scp.h index 04199d65b..af503ae1d 100644 --- a/scp.h +++ b/scp.h @@ -261,6 +261,7 @@ void sim_debug_bits (uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs, #define CANT_USE_MACRO_VA_ARGS 1 #endif void _sim_vdebug (uint32 dbits, DEVICE* dptr, UNIT *uptr, const char* fmt, va_list arglist); +void sim_misc_debug (const char *debug_thing, const char *debug_type, const char* msg); #ifdef CANT_USE_MACRO_VA_ARGS #define _sim_debug_device sim_debug void sim_debug (uint32 dbits, DEVICE* dptr, const char *fmt, ...) GCC_FMT_ATTR(3, 4); @@ -335,6 +336,7 @@ extern BRKTYPTAB *sim_brk_type_desc; /* type descriptions */ extern const char *sim_prog_name; /* executable program name */ extern FILE *stdnul; extern t_bool sim_asynch_enabled; +extern t_bool sim_unit_aio_pending(UNIT *uptr); #if defined(SIM_ASYNCH_IO) int sim_aio_update_queue (void); void sim_aio_activate (ACTIVATE_API caller, UNIT *uptr, int32 event_time); @@ -382,6 +384,10 @@ extern int32 sim_vm_initial_ips; /* base estimate of simu extern const char *sim_vm_interval_units; /* Simulator can change this - default "instructions" */ extern const char *sim_vm_step_unit; /* Simulator can change this - default "instruction" */ +/* Debug table manipulation: */ +extern DEBTAB *sim_combine_debtabs(const DEBTAB *tab1, const DEBTAB *tab2); +extern size_t sim_debtab_nelems(const DEBTAB *debtab); +extern void sim_fill_debtab_flags(DEBTAB *debtab); /* Core SCP libraries can potentially have unit test routines. These defines help implement consistent unit test functionality */ diff --git a/sigma/CMakeLists.txt b/sigma/CMakeLists.txt index 3e17a9474..927224a47 100644 --- a/sigma/CMakeLists.txt +++ b/sigma/CMakeLists.txt @@ -31,8 +31,8 @@ add_simulator(sigma sigma_rad.c sigma_rtc.c sigma_tt.c - sigma_cp.c sigma_cr.c + sigma_cp.c INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} LABEL sigma diff --git a/sim_console.c b/sim_console.c index 1c0e82d4b..d159862a0 100644 --- a/sim_console.c +++ b/sim_console.c @@ -161,7 +161,6 @@ /* Forward declarations of platform specific routines */ static t_stat sim_os_poll_kbd (void); -static t_bool sim_os_poll_kbd_ready (int ms_timeout); static t_stat sim_os_putchar (int32 out); static t_stat sim_os_ttinit (void); static t_stat sim_os_ttrun (void); @@ -658,7 +657,7 @@ for (i=connections=0; ismp_reg_count) { uint32 reg; - DEVICE *dptr = NULL; + DEVICE *samp_dptr = NULL; if (rem->smp_sample_dither_pct) fprintf (st, "Register Bit Sampling is occurring every %d %s (dithered %d percent)\n", rem->smp_sample_interval, sim_vm_interval_units, rem->smp_sample_dither_pct); @@ -668,13 +667,13 @@ for (i=connections=0; ismp_reg_count; reg++) { if (rem->smp_regs[reg].indirect) fprintf (st, " indirect "); - if (dptr != rem->smp_regs[reg].dptr) + if (samp_dptr != rem->smp_regs[reg].dptr) fprintf (st, "%s ", rem->smp_regs[reg].dptr->name); if (rem->smp_regs[reg].reg->depth > 1) fprintf (st, "%s[%d]%s", rem->smp_regs[reg].reg->name, rem->smp_regs[reg].idx, ((reg + 1) < rem->smp_reg_count) ? ", " : ""); else fprintf (st, "%s%s", rem->smp_regs[reg].reg->name, ((reg + 1) < rem->smp_reg_count) ? ", " : ""); - dptr = rem->smp_regs[reg].dptr; + samp_dptr = rem->smp_regs[reg].dptr; } fprintf (st, "\n"); if (sim_switches & SWMASK ('D')) @@ -3483,9 +3482,12 @@ return SCPE_OK; #include #include #define RAW_MODE 0 +typedef BOOL (WINAPI *std_output_writer_fn)(HANDLE, const void *, DWORD, LPDWORD, LPVOID); + static HANDLE std_input; static HANDLE std_output; static HANDLE std_error; +static std_output_writer_fn std_output_writer = NULL; static DWORD saved_input_mode; static DWORD saved_output_mode; static DWORD saved_error_mode; @@ -3531,11 +3533,14 @@ ControlHandler(DWORD dwCtrlType) static t_stat sim_os_ttinit (void) { +DWORD mode; + sim_debug (DBG_TRC, &sim_con_telnet, "sim_os_ttinit()\n"); SetConsoleCtrlHandler( ControlHandler, TRUE ); std_input = GetStdHandle (STD_INPUT_HANDLE); std_output = GetStdHandle (STD_OUTPUT_HANDLE); +std_output_writer = GetConsoleMode(std_output, &mode) ? WriteConsoleA : (std_output_writer_fn) WriteFile; std_error = GetStdHandle (STD_ERROR_HANDLE); if ((std_input) && /* Not Background process? */ (std_input != INVALID_HANDLE_VALUE)) @@ -3667,17 +3672,6 @@ if ((sim_brk_char && ((c & 0177) == sim_brk_char)) || (c & SCPE_BREAK)) return c | SCPE_KFLAG; } -static t_bool sim_os_poll_kbd_ready (int ms_timeout) -{ -sim_debug (DBG_TRC, &sim_con_telnet, "sim_os_poll_kbd_ready()\n"); -if ((std_input == NULL) || /* No keyboard for */ - (std_input == INVALID_HANDLE_VALUE)) { /* background processes */ - Sleep (ms_timeout); - return FALSE; - } -return (WAIT_OBJECT_0 == WaitForSingleObject (std_input, ms_timeout)); -} - #define BELL_CHAR 7 /* Bell Character */ #define BELL_INTERVAL_MS 500 /* No more than 2 Bell Characters Per Second */ @@ -3690,16 +3684,15 @@ return (WAIT_OBJECT_0 == WaitForSingleObject (std_input, ms_timeout)); static uint8 out_buf[ESC_HOLD_MAX]; /* Buffered characters pending output */ static int32 out_ptr = 0; -static void sim_console_write(uint8 *outbuf, int32 outsz) +static inline void sim_console_write(uint8 *outbuf, int32 outsz) { DWORD unused; - DWORD mode; - - if (GetConsoleMode(std_output, &mode)) { - WriteConsoleA(std_output, outbuf, outsz, &unused, NULL); - } else { - BOOL result = WriteFile(std_output, outbuf, outsz, &unused, NULL); - } + BOOL result; + + /* Useful to see the return value from std_output_writer. */ + result = std_output_writer(std_output, outbuf, outsz, &unused, NULL); + /* But squelch the set-but-not-used warnings. */ + (void) result; } static t_stat sim_out_hold_svc (UNIT *uptr) @@ -4055,22 +4048,6 @@ if (sim_int_char && (buf[0] == sim_int_char)) return (buf[0] | SCPE_KFLAG); } -static t_bool sim_os_poll_kbd_ready (int ms_timeout) -{ -fd_set readfds; -struct timeval timeout; - -if (!sim_ttisatty()) { /* skip if !tty */ - sim_os_ms_sleep (ms_timeout); - return FALSE; - } -FD_ZERO (&readfds); -FD_SET (0, &readfds); -timeout.tv_sec = (ms_timeout*1000)/1000000; -timeout.tv_usec = (ms_timeout*1000)%1000000; -return (1 == select (1, &readfds, NULL, NULL, &timeout)); -} - static t_stat sim_os_putchar (int32 out) { char c; diff --git a/sim_debtab.c b/sim_debtab.c new file mode 100644 index 000000000..3890d3544 --- /dev/null +++ b/sim_debtab.c @@ -0,0 +1,98 @@ +/* sim_debtab.c: + ------------------------------------------------------------------------------ + + 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 AUTHOR 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. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + ------------------------------------------------------------------------------ + + This module provides DEBTAB debug table manipulation functions. + +*/ + +#include "sim_defs.h" +#include "scp.h" + +/* Count the elements in the debugging table. */ +size_t sim_debtab_nelems(const DEBTAB *debtab) +{ + const DEBTAB *p; + + for (p = debtab; p->name != NULL; ++p) + /* NOP */ ; + + return (p - debtab); +} + +/* Combine two DEBTAB debug tables, returning the resulting combined + * table. Both tables have NULL as the last element's name. */ +DEBTAB *sim_combine_debtabs(const DEBTAB *tab1, const DEBTAB *tab2) +{ + size_t n_combined = 0; + const DEBTAB *p; + DEBTAB *combined; + + n_combined = sim_debtab_nelems(tab1) + sim_debtab_nelems(tab2) + 1; + combined = (DEBTAB *) malloc(n_combined * sizeof(DEBTAB)); + n_combined = 0; + + for (p = tab1; p->name != NULL; ++p, n_combined++) + combined[n_combined] = *p; + for (p = tab2; p->name != NULL; ++p, n_combined++) + combined[n_combined] = *p; + + combined[n_combined].name = NULL; + return combined; +} + +/* Fill debug mask holes in the debugging table: If an entry's mask == 0, + * find an unused bit in the existing debugging table's mask and assign + * that unused bit to the entry's mask. */ +void sim_fill_debtab_flags(DEBTAB *debtab) +{ + uint32_t dbg_bitmask = 0, new_flag; + DEBTAB *p; + int i; + + /* Augment the device's debugging table with the poll and socket flags, + * so that debugging looks correct in the output (see _get_dbg_verb() in + * scp.c) */ + dbg_bitmask = 0; + for (p = debtab; p->name != NULL; ++p) + dbg_bitmask |= p->mask; + + for (p = debtab, new_flag = 1, i = sizeof(dbg_bitmask) * 8; p->name != NULL && i > 0; /* empty */) { + while (i > 0 && (new_flag & dbg_bitmask) != 0) { + new_flag <<= 1; + --i; + } + + /* Found a hole in the existing debugging flags */ + if (i > 0) { + /* Find a need for the new flag */ + while (p->mask != 0 && p->name != NULL) + ++p; + if (p->name != NULL) { + p->mask = new_flag; + } + } + } +} diff --git a/sim_defs.h b/sim_defs.h index fbb32ecd1..01a106eb2 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -153,10 +153,16 @@ extern int sim_vax_snprintf(char *buf, size_t buf_size, const char *fmt, ...); #include #include #include +#include #undef PACKED /* avoid macro name collision */ #undef ERROR /* avoid macro name collision */ #undef MEM_MAPPED /* avoid macro name collision */ #include + +#if defined(_MSC_VER) +/* Disable unreferenced formal parameter warnings (4100) */ +#pragma warning(disable: 4100) +#endif #endif #ifdef USE_REGEX @@ -338,7 +344,11 @@ typedef uint32 t_addr; #else # define PACKED_BEGIN #if defined(_WIN32) -# define PACKED_END __attribute__((gcc_struct, packed)) +# if !defined(__clang__) +# define PACKED_END __attribute__((gcc_struct, packed)) +# else +# define PACKED_END __attribute__((packed)) +# endif #else # define PACKED_END __attribute__((packed)) #endif @@ -1166,6 +1176,7 @@ extern int32 sim_tmxr_poll_count; extern pthread_cond_t sim_tmxr_poll_cond; extern pthread_mutex_t sim_tmxr_poll_lock; extern pthread_t sim_asynch_main_threadid; +extern pthread_mutex_t sim_debug_lock; extern UNIT * volatile sim_asynch_queue; extern volatile t_bool sim_idle_wait; extern int32 sim_asynch_check; @@ -1209,8 +1220,9 @@ extern int32 sim_asynch_inst_latency; #define AIO_MAIN_THREAD (pthread_equal ( pthread_self(), sim_asynch_main_threadid )) #define AIO_LOCK \ pthread_mutex_lock(&sim_asynch_lock) -#define AIO_UNLOCK \ - pthread_mutex_unlock(&sim_asynch_lock) +#define AIO_UNLOCK pthread_mutex_unlock(&sim_asynch_lock) +#define AIO_DEBUG_LOCK pthread_mutex_lock(&sim_debug_lock) +#define AIO_DEBUG_UNLOCK pthread_mutex_unlock(&sim_debug_lock) #define AIO_IS_ACTIVE(uptr) (((uptr)->a_is_active ? (uptr)->a_is_active (uptr) : FALSE) || ((uptr)->a_next)) #if defined(SIM_ASYNCH_MUX) #define AIO_CANCEL(uptr) \ @@ -1263,6 +1275,13 @@ extern int32 sim_asynch_inst_latency; #define AIO_QUEUE_MODE "Lock free asynchronous event queue" #define AIO_INIT \ do { \ + pthread_mutexattr_t attr; \ + \ + pthread_mutexattr_init (&attr); \ + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \ + pthread_mutex_init (&sim_debug_lock, &attr); \ + pthread_mutexattr_destroy (&attr); \ + \ sim_asynch_main_threadid = pthread_self(); \ /* Empty list/list end uses the point value (void *)1. \ This allows NULL in an entry's a_next pointer to \ @@ -1277,6 +1296,7 @@ extern int32 sim_asynch_inst_latency; pthread_cond_destroy(&sim_timer_wake); \ pthread_mutex_destroy(&sim_tmxr_poll_lock); \ pthread_cond_destroy(&sim_tmxr_poll_cond); \ + pthread_mutex_destroy(&sim_debug_lock); \ } while (0) #ifdef _WIN32 #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) @@ -1308,6 +1328,7 @@ extern int32 sim_asynch_inst_latency; pthread_mutexattr_init (&attr); \ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \ pthread_mutex_init (&sim_asynch_lock, &attr); \ + pthread_mutex_init (&sim_debug_lock, &attr); \ pthread_mutexattr_destroy (&attr); \ sim_asynch_main_threadid = pthread_self(); \ /* Empty list/list end uses the point value (void *)1. \ @@ -1323,6 +1344,7 @@ extern int32 sim_asynch_inst_latency; pthread_cond_destroy(&sim_timer_wake); \ pthread_mutex_destroy(&sim_tmxr_poll_lock); \ pthread_cond_destroy(&sim_tmxr_poll_cond); \ + pthread_mutex_destroy(&sim_debug_lock); \ } while (0) #define AIO_ILOCK AIO_LOCK #define AIO_IUNLOCK AIO_UNLOCK @@ -1381,6 +1403,8 @@ extern int32 sim_asynch_inst_latency; #define AIO_MAIN_THREAD TRUE #define AIO_LOCK #define AIO_UNLOCK +#define AIO_DEBUG_LOCK +#define AIO_DEBUG_UNLOCK #define AIO_CLEANUP #define AIO_EVENT_BEGIN(uptr) #define AIO_EVENT_COMPLETE(uptr, reason) @@ -1390,6 +1414,9 @@ extern int32 sim_asynch_inst_latency; #define AIO_TLS #endif /* SIM_ASYNCH_IO */ +/* Unused argument macro */ +#define SIM_UNUSED_ARG(arg) (void ) (arg); + #ifdef __cplusplus } #endif diff --git a/sim_ether.c b/sim_ether.c index 7faabbd3f..b530b5849 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -454,7 +454,9 @@ t_stat eth_mac_scan_ex (ETH_MAC* mac, const char* strmac, UNIT *uptr) (6 != sscanf(strmac, "%x.%x.%x.%x.%x.%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5])) && (6 != sscanf(strmac, "%x-%x-%x-%x-%x-%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]))) return sim_messagef (SCPE_ARG, "Invalid MAC address format: '%s'\n", strmac); - for (i=0; i<6; i++) + + memset(newmac, 0, sizeof(newmac) / sizeof(newmac[0])); + for (i=0; i<6; i++) { if (a[i] > 0xFF) return sim_messagef (SCPE_ARG, "Invalid MAC address byte value: %02X\n", a[i]); else { @@ -468,6 +470,7 @@ t_stat eth_mac_scan_ex (ETH_MAC* mac, const char* strmac, UNIT *uptr) mask = 0xFF << shift; newmac[i] = (unsigned char)((a[i] & mask) | (g[i] & ~mask)); } + } /* final check - mac cannot be broadcast or multicast address */ if (!memcmp(newmac, zeros, sizeof(ETH_MAC)) || /* broadcast */ @@ -676,7 +679,7 @@ t_stat ethq_init(ETH_QUE* que, int max) /* create dynamic queue if it does not exist */ if (!que->item) { que->item = (struct eth_item *) calloc(max, sizeof(struct eth_item)); - if (!que->item) { + if (NULL == que->item) { /* failed to allocate memory */ sim_printf("EthQ: failed to allocate dynamic queue[%d]\n", max); return SCPE_MEM; @@ -779,6 +782,9 @@ ethq_insert_data(que, type, pack->oversize ? pack->oversize : pack->msg, pack->u t_stat eth_show_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char *desc) { +SIM_UNUSED_ARG(dptr); +SIM_UNUSED_ARG(desc); + return eth_show (st, uptr, val, NULL); } @@ -895,6 +901,11 @@ t_stat eth_show (FILE* st, UNIT* uptr, int32 val, CONST void* desc) ETH_LIST list[ETH_MAX_DEVICE]; int number; + SIM_UNUSED_ARG(uptr); + SIM_UNUSED_ARG(val); + SIM_UNUSED_ARG(desc); + + number = eth_devices(ETH_MAX_DEVICE, list, FALSE); fprintf(st, "ETH devices:\n"); if (number == -1) @@ -1055,6 +1066,8 @@ static int eth_host_pcap_devices(int used, int max, ETH_LIST* list) { int i; +SIM_UNUSED_ARG(max); + for (i=0; ihost_nic_phy_hw_addr, 0, sizeof(dev->host_nic_phy_hw_addr)); dev->have_host_nic_phy_addr = 0; if (dev->eth_api != ETH_API_PCAP) @@ -1984,7 +1999,7 @@ while (dev->handle) { if (do_select) { #ifdef HAVE_SLIRP_NETWORK if (dev->eth_api == ETH_API_NAT) { - sel_ret = sim_slirp_select ((SLIRP*)dev->handle, 250); + sel_ret = sim_slirp_select ((SimSlirpNetwork *) dev->handle, 250); } else #endif @@ -2062,7 +2077,7 @@ while (dev->handle) { #endif /* HAVE_VDE_NETWORK */ #ifdef HAVE_SLIRP_NETWORK case ETH_API_NAT: - sim_slirp_dispatch ((SLIRP*)dev->handle); + sim_slirp_dispatch ((SimSlirpNetwork *) dev->handle); status = 1; break; #endif /* HAVE_SLIRP_NETWORK */ @@ -2088,17 +2103,6 @@ while (dev->handle) { } break; } - if ((status > 0) && (dev->asynch_io)) { - int wakeup_needed; - - pthread_mutex_lock (&dev->lock); - wakeup_needed = (dev->read_queue.count != 0); - pthread_mutex_unlock (&dev->lock); - if (wakeup_needed) { - sim_debug(dev->dbit, dev->dptr, "Queueing automatic poll\n"); - sim_activate_abs (dev->dptr->units, dev->asynch_io_latency); - } - } if (status < 0) { ++dev->receive_packet_errors; _eth_error (dev, "_eth_reader"); @@ -2136,26 +2140,27 @@ sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL); sim_debug(dev->dbit, dev->dptr, "Writer Thread Starting\n"); pthread_mutex_lock (&dev->writer_lock); -while (dev->handle) { +while (dev->handle != NULL) { pthread_cond_wait (&dev->writer_cond, &dev->writer_lock); while (NULL != (request = dev->write_requests)) { - if (dev->handle == NULL) /* Shutting down? */ - break; - /* Pull buffer off request list */ - dev->write_requests = request->next; - pthread_mutex_unlock (&dev->writer_lock); - - if (dev->throttle_delay != ETH_THROT_DISABLED_DELAY) { - uint32 packet_delta_time = sim_os_msec() - dev->throttle_packet_time; - dev->throttle_events <<= 1; - dev->throttle_events += (packet_delta_time < dev->throttle_time) ? 1 : 0; - if ((dev->throttle_events & dev->throttle_mask) == dev->throttle_mask) { - sim_os_ms_sleep (dev->throttle_delay); - ++dev->throttle_count; + if (dev->handle != NULL) { + /* Pull buffer off request list */ + dev->write_requests = request->next; + pthread_mutex_unlock (&dev->writer_lock); + + if (dev->throttle_delay != ETH_THROT_DISABLED_DELAY) { + uint32 packet_delta_time = sim_os_msec() - dev->throttle_packet_time; + dev->throttle_events <<= 1; + dev->throttle_events += (packet_delta_time < dev->throttle_time) ? 1 : 0; + if ((dev->throttle_events & dev->throttle_mask) == dev->throttle_mask) { + sim_os_ms_sleep (dev->throttle_delay); + ++dev->throttle_count; + } + dev->throttle_packet_time = sim_os_msec(); } - dev->throttle_packet_time = sim_os_msec(); - } - dev->write_status = _eth_write(dev, &request->packet, NULL); + dev->write_status = _eth_write(dev, &request->packet, NULL); + } else + break; /* Shutting down? */ pthread_mutex_lock (&dev->writer_lock); /* Put buffer on free buffer list */ @@ -2194,11 +2199,11 @@ dev->asynch_io = sim_asynch_enabled; dev->asynch_io_latency = latency; pthread_mutex_lock (&dev->lock); wakeup_needed = (dev->read_queue.count != 0); -pthread_mutex_unlock (&dev->lock); if (wakeup_needed) { sim_debug(dev->dbit, dev->dptr, "Queueing automatic poll\n"); sim_activate_abs (dev->dptr->units, dev->asynch_io_latency); } +pthread_mutex_unlock (&dev->lock); #endif return SCPE_OK; } @@ -2644,7 +2649,7 @@ switch (eth_api) { #endif #ifdef HAVE_SLIRP_NETWORK case ETH_API_NAT: - sim_slirp_close((SLIRP*)pcap); + sim_slirp_close((SimSlirpNetwork *) pcap); break; #endif case ETH_API_UDP: @@ -3082,7 +3087,7 @@ if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) { #endif #ifdef HAVE_SLIRP_NETWORK case ETH_API_NAT: - status = sim_slirp_send((SLIRP*)dev->handle, (char *)packet->msg, (size_t)packet->len, 0); + status = sim_slirp_send((SimSlirpNetwork *)dev->handle, (char *)packet->msg, (size_t)packet->len, 0); if ((status == (int)packet->len) || (status == 0)) status = 0; else @@ -3113,7 +3118,7 @@ if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) { } /* if packet->len */ /* call optional write callback function */ -if (routine) +if (routine != NULL) (routine)(status); return ((status == 0) ? SCPE_OK : SCPE_IOERR); @@ -3792,6 +3797,7 @@ if (bpf_used ? to_me : (to_me && !from_me)) { /* This must be done before any needed CRC calculation */ _eth_fix_ip_xsum_offload(dev, (const u_char*)data, len); + memset(crc_data, 0, sizeof(crc_data) / sizeof(crc_data[0])); if (dev->need_crc) crc_len = eth_get_packet_crc32_data(data, len, crc_data); @@ -3799,8 +3805,25 @@ if (bpf_used ? to_me : (to_me && !from_me)) { pthread_mutex_lock (&dev->lock); ethq_insert_data(&dev->read_queue, ETH_ITM_NORMAL, data, 0, len, crc_len, crc_data, 0); + if (dev->read_queue.count == 1 || (dev->asynch_io && !sim_unit_aio_pending(dev->dptr->units))) { + /* Kick the simulator's lower half UNIT handler if the read queue's depth is 1 (just received + * a packet) or an ansynchronous service event is not already scheduled. + * + * This allows packets to accumulate while ensuring that there is a pending UNIT event + * to processes them. Otherwise, the simulator's receiver will stall and unprocessed + * packets will accumulate. */ + + sim_activate_abs (dev->dptr->units, dev->asynch_io_latency); + sim_debug(dev->dbit, dev->dptr, "Scheduling UNIT service event to drain queue (depth = %d)\n", + dev->read_queue.count); + } else { + sim_debug(dev->dbit, dev->dptr, "Deferred -- pending UNIT service event (depth = %d)\n", + dev->read_queue.count); + } + ++dev->packets_received; pthread_mutex_unlock (&dev->lock); + free(moved_data); } #else /* !USE_READER_THREAD */ @@ -3837,7 +3860,7 @@ if (bpf_used ? to_me : (to_me && !from_me)) { int eth_read(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) { -int status; +int status = 0; /* make sure device exists */ @@ -4119,9 +4142,9 @@ if (hash) { if (dev->dptr->dctrl & dev->dbit) { sim_debug(dev->dbit, dev->dptr, "Filter Set\n"); for (i = 0; i < addr_count; i++) { - char mac[20]; - eth_mac_fmt(&dev->filter_address[i], mac); - sim_debug(dev->dbit, dev->dptr, " Addr[%d]: %s\n", i, mac); + char mac_daddy[20]; + eth_mac_fmt(&dev->filter_address[i], mac_daddy); + sim_debug(dev->dbit, dev->dptr, " Addr[%d]: %s\n", i, mac_daddy); } if (dev->all_multicast) { sim_debug(dev->dbit, dev->dptr, "All Multicast\n"); @@ -4294,7 +4317,7 @@ if (dev->bpf_filter) fprintf(st, " BPF Filter: %s\n", dev->bpf_filter); #if defined(HAVE_SLIRP_NETWORK) if (dev->eth_api == ETH_API_NAT) - sim_slirp_show ((SLIRP *)dev->handle, st); + sim_slirp_show ((SimSlirpNetwork *) dev->handle, st); #endif } @@ -4338,6 +4361,9 @@ static uint32 valcrc32[] = { 0x6C311115, 0x8520007D, 0x65623584, 0x8C7324EC, 0x7E975837, 0x9786495F, 0x77C47CA6, 0x9ED56DCE, 0x497D8351, 0xA06C9239, 0x402EA7C0, 0xA93FB6A8, 0x5BDBCA73, 0xB2CADB1B, 0x5288EEE2, 0xBB99FF8A}; +SIM_UNUSED_ARG(dptr); + + for (val=0; val <= 0xFF; val++) { memset (data, val, sizeof (data)); if (valcrc32[val] != eth_crc32 (0, data, sizeof (data))) { @@ -4496,6 +4522,8 @@ return (errors == 0) ? SCPE_OK : SCPE_IERR; t_stat sim_ether_test (DEVICE *dptr, const char *cptr) { +SIM_UNUSED_ARG(cptr); + t_stat stat = SCPE_OK; SIM_TEST_INIT; diff --git a/sim_printf_fmts.h b/sim_printf_fmts.h index e31389381..3363045d3 100644 --- a/sim_printf_fmts.h +++ b/sim_printf_fmts.h @@ -29,17 +29,17 @@ * POINTER_FMT: Format modifier for pointers, e.g. "%08" POINTER_FMT "X" */ -#if defined (_WIN32) || defined(_WIN64) +#if defined (_WIN32) || defined(_WIN64) || defined(__MINGW64__) || defined(__MINGW32__) -# if defined(__MINGW64__) -# define LL_FMT "I64" -# define SIZE_T_FMT "I64" -# elif defined(_MSC_VER) || defined(__MINGW32__) +# if defined(__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO # define LL_FMT "ll" -# define SIZE_T_FMT "z" # else - /* Graceful fail -- shouldn't ever default to this on a Windows platform. */ -# define LL_FMT "ll" +# define LL_FMT "I64" +# endif + +# if defined(__MINGW64__) || defined(_WIN64) +# define SIZE_T_FMT "I64" +# elif defined(__MINGW32__) || defined(_WIN32) # define SIZE_T_FMT "I32" # endif @@ -75,7 +75,6 @@ # define POINTER_FMT "" #endif - #if defined (USE_INT64) && defined (USE_ADDR64) # define T_ADDR_FMT T_UINT64_FMT #else diff --git a/sim_slirp/config/.gitignore b/sim_slirp/config/.gitignore new file mode 100644 index 000000000..20eb0abd3 --- /dev/null +++ b/sim_slirp/config/.gitignore @@ -0,0 +1,3 @@ +mk-glib-endian +libslirp-version.h +glib-endian.h diff --git a/sim_slirp/config/libslirp-version.awk b/sim_slirp/config/libslirp-version.awk new file mode 100644 index 000000000..edc7ba010 --- /dev/null +++ b/sim_slirp/config/libslirp-version.awk @@ -0,0 +1,52 @@ +# libslirp-version.awk: Generate the libslirp-version.h header: +# +# 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 AUTHOR 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. +# +# Except as contained in this notice, the name of the author shall not be +# used in advertising or otherwise to promote the sale, use or other dealings +# in this Software without prior written authorization from the author. + +/ +version : '.*'/ { + vstr = $3; + sub(/'/, "", vstr); + sub(/',/, "", vstr); + split(vstr, vparts, "."); + print "#ifndef LIBSLIRP_VERSION_H_"; + print "#define LIBSLIRP_VERSION_H_"; + print ""; + print "#ifdef __cplusplus"; + print "extern \"C\" {"; + print "#endif"; + print ""; + print "#define SLIRP_MAJOR_VERSION ", vparts[1]; + print "#define SLIRP_MINOR_VERSION ", vparts[2]; + print "#define SLIRP_MICRO_VERSION ", vparts[3]; + print "#define SLIRP_VERSION_STRING \"" vstr "\""; + print ""; + print "#define SLIRP_CHECK_VERSION(major,minor,micro) \\"; + print " (SLIRP_MAJOR_VERSION > (major) || \\"; + print " (SLIRP_MAJOR_VERSION == (major) && SLIRP_MINOR_VERSION > (minor)) || \\"; + print " (SLIRP_MAJOR_VERSION == (major) && SLIRP_MINOR_VERSION == (minor) && \\"; + print " SLIRP_MICRO_VERSION >= (micro)))"; + print ""; + print "#ifdef __cplusplus"; + print "} /* extern \"C\" */"; + print "#endif"; + print ""; + print "#endif /* LIBSLIRP_VERSION_H_ */"; +} diff --git a/sim_slirp/config/libslirp_config.c b/sim_slirp/config/libslirp_config.c new file mode 100644 index 000000000..4519e094b --- /dev/null +++ b/sim_slirp/config/libslirp_config.c @@ -0,0 +1,46 @@ +/* Feature test program for libslirp. + * + * Only used by the makefile to set the minimal glib features. Patterned + * off the way CMake does testing for library functions. + * + * - If the source compiles, with the appropriate TEST_* symbol defined, + * then the resulting libslirp_config program is executed, which should + * exit with a success (0) status. + * + * - Any failure along the way and the makefile will not detect the feature + * and won't update the LIBSLIR_FEATURES variable. + */ + +#if defined(TEST_VASPRINTF_GNU_SOURCE) +#define _GNU_SOURCE +#endif + +#include + +#if defined(TEST_CLOCK_GETTIME) +#include +#endif +#if defined(TEST_GETTIMEOFDAY) +#include +#endif +#if defined(TEST_INET_PTON) +#include +#endif + +int main(void) +{ +#if defined(TEST_VASPRINTF) || defined(TEST_VASPRINTF_GNU_SOURCE) + (void (*)()) (vasprintf); +#endif +#if defined(TEST_CLOCK_GETTIME) + (void (*)()) (clock_gettime); +#endif +#if defined(TEST_GETTIMEOFDAY) + (void (*)()) (gettimeofday); +#endif +#if defined(TEST_INET_PTON) + (void (*)()) (inet_pton); +#endif + + return 0; +} diff --git a/sim_slirp/config/mk-glib-endian.c b/sim_slirp/config/mk-glib-endian.c new file mode 100644 index 000000000..51bf05e55 --- /dev/null +++ b/sim_slirp/config/mk-glib-endian.c @@ -0,0 +1,65 @@ +#include +#include +#include "sim_printf_fmts.h" + +#if defined(HAVE_INTTYPES_H) +#include +#endif + +/* Bridge until printf format patch accepted. */ +#if defined(__MINGW64__) || defined(_WIN64) || defined(__WIN64) +# if defined(PRIu64) +# define SIM_PRIsize_t PRIu64 +# else +# define SIM_PRIsize_t "llu" +# endif +#elif defined(__MINGW32__) || defined(_WIN32) || defined(__WIN32) +# define SIM_PRIsize_t "zu" +#elif defined(__GNU_LIBRARY__) || defined(__GLIBC__) || defined(__GLIBC_MINOR__) || \ + defined(__APPLE__) +/* GNU libc (Linux) and macOS */ +# define SIM_PRIsize_t "zu" +#else +# define SIM_PRIsize_t "u" +#endif + +const char *preamble[] = { + "/* Automagically generated endianness include.", + " *", + " * Also defines GLIB_SIZE_VOID_P using the CMake CMAKE_SIZEOF_VOID_P", + " * substitution. Probably not where this manifest constant really", + " * belongs, but there's not really a better place for it. */", + "", + "#if !defined(_GLIB_ENDIAN_H)", + "#define _GLIB_ENDIAN_H", + "" + "#define G_BIG_ENDIAN 0x1234", + "#define G_LITTLE_ENDIAN 0x4321", + "" +}; + +const char *epilog[] = { + "", + "#endif /* _GLIB_ENDIAN_H */" +}; + +const int endian_test = 0x1234; + +int main(void) { + size_t i; + + for (i = 0; i < sizeof(preamble) / sizeof(preamble[0]); ++i) { + fputs(preamble[i], stdout); + fputc('\n', stdout); + } + + printf("#define G_BYTE_ORDER %s\n", (*((const char *) &endian_test) == 1) ? "G_BIG_ENDIAN" : "G_LITTLE_ENDIAN"); + printf("#define GLIB_SIZEOF_VOID_P %" SIM_PRIsize_t "\n", sizeof(void *)); + + for (i = 0; i < sizeof(epilog) / sizeof(epilog[0]); ++i) { + fputs(epilog[i], stdout); + fputc('\n', stdout); + } + + return 0; +} diff --git a/sim_slirp/sim_slirp.c b/sim_slirp/sim_slirp.c new file mode 100644 index 000000000..b684cd0bb --- /dev/null +++ b/sim_slirp/sim_slirp.c @@ -0,0 +1,719 @@ +/* sim_slirp.c: + ------------------------------------------------------------------------------ + Copyright (c) 2015, Mark Pizzolato + Copyright (c) 2024, B. Scott Michel + + 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 AUTHOR 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. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + ------------------------------------------------------------------------------ + + This module provides the interface needed between sim_ether and libslirp to + provide NAT network functionality. + +*/ +#define SIMH_IP_NETWORK 0x0a000200 /* aka 10.0.2.0 */ +#define SIMH_IP_NETMASK 0xffffff00 /* aka 255.255.255.0 */ +#define SIMH_GATEWAY_ADDR 0x0a000202 /* aka 10.0.2.2 (SIMH's address) */ +#define SIMH_RESOLVER_ADDR 0x0a000203 /* aka 10.0.2.3 (DNS resolver) */ + +/* IPv6 private address range (ULA) blessed by IANA */ +#define SIMH_IP6_NETWORK "fd00:cafe:dead:beef::" +#define SIMH_IP6_PREFIX_LEN 64 +#define SIMH_GW_ADDR6 "fd00:cafe:dead:beef::2" /* SIMH's IPv6 address */ + +#include +#include /* Paranoia for Win32/64 */ + +#include "libslirp.h" +#include "sim_defs.h" +#include "scp.h" +#include "sim_sock.h" +#include "sim_slirp_network.h" +#include "sim_printf_fmts.h" + +#if !defined(_WIN32) +# define simh_inet_aton inet_aton +#else +# define simh_inet_aton slirp_inet_aton +# if WINVER < 0x0601 +# undef inet_pton +# define inet_pton sim_inet_pton +# endif +#endif + +#define IS_TCP 0 +#define IS_UDP 1 + +static const char *tcpudp[] = {"TCP", "UDP"}; + +/* Additional debugging flags added to the device's debug table. */ +DEBTAB slirp_dbgtable[] = { + { "POLL", 0, "Show libslirp polling callback activity" }, + { "SOCKET", 0, "Show libslirp socket registration activity" }, + { NULL } +}; + +/*~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~= + * Port redirection management: + *~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=*/ + +static int parse_redirect_port(struct redir_tcp_udp **head, const char *buff, int is_udp) +{ + char gbuf[4 * CBUFSIZE]; + uint32 inaddr = INADDR_ANY; + int port = 0; + int lport = 0; + char *ipaddrstr = NULL; + char *portstr = NULL; + struct redir_tcp_udp *newp; + + gbuf[sizeof(gbuf) - 1] = '\0'; + strncpy(gbuf, buff, sizeof(gbuf) - 1); + if (((ipaddrstr = strchr(gbuf, ':')) == NULL) || (*(ipaddrstr + 1) == 0)) { + sim_printf("redir %s syntax error\n", tcpudp[is_udp]); + return -1; + } + *ipaddrstr++ = 0; + + if ((ipaddrstr) && (((portstr = strchr(ipaddrstr, ':')) == NULL) || (*(portstr + 1) == 0))) { + sim_printf("redir %s syntax error\n", tcpudp[is_udp]); + return -1; + } + *portstr++ = 0; + + sscanf(gbuf, "%d", &lport); + sscanf(portstr, "%d", &port); + if (ipaddrstr != NULL) { + struct in_addr addr; + + if (simh_inet_aton(ipaddrstr, &addr)) { + inaddr = addr.s_addr; + } + } + + if (inaddr == INADDR_ANY) { + sim_printf("%s redirection error: an IP address must be specified\n", tcpudp[is_udp]); + return -1; + } + + if ((newp = (struct redir_tcp_udp *) calloc(1, sizeof(struct redir_tcp_udp))) == NULL) + return -1; + + newp->is_udp = is_udp; + newp->simh_host_port = port; + simh_inet_aton(ipaddrstr, &newp->sim_local_inaddr); + newp->sim_local_port = lport; + newp->next = *head; + *head = newp; + return 0; +} + +/* do_redirects: Adds the proxied (forwarded) ports from the guest network to the + * outside network. */ +static int do_redirects(SimSlirpNetwork *slirp, struct redir_tcp_udp *head) +{ + struct in_addr host_addr; + int ret = 0; + + host_addr.s_addr = htonl(INADDR_ANY); + if (head != NULL) { + ret = do_redirects(slirp, head->next); + if (slirp_add_hostfwd(slirp->slirp_cxn, head->is_udp, host_addr, head->sim_local_port, + head->sim_local_inaddr, head->simh_host_port) < 0) { + sim_printf("Can't establish redirector for: redir %s =%d:%s:%d\n", tcpudp[head->is_udp], + head->sim_local_port, sim_inet_ntoa4(&head->sim_local_inaddr), + head->simh_host_port); + ++ret; + } + } + return ret; +} + +static unsigned int collect_slirp_debug(const char *dbg_tokens, int *err) +{ + unsigned int slirp_dbg = 0; + + while (dbg_tokens != NULL && *dbg_tokens != '\0' && *err == 0) { + if (!strncasecmp(dbg_tokens, "CALL", 4)) { + slirp_dbg |= SLIRP_DBG_CALL; + } else if (!strncasecmp(dbg_tokens, "MISC", 4)) { + slirp_dbg |= SLIRP_DBG_MISC; + } else if (!strncasecmp(dbg_tokens, "ERROR", 5)) { + slirp_dbg |= SLIRP_DBG_ERROR; + } else if (!strncasecmp(dbg_tokens, "VERBOSE_CALL", 13)) { + slirp_dbg |= SLIRP_DBG_VERBOSE_CALL; + } else if (!strncasecmp(dbg_tokens, "ALL", 3)) { + slirp_dbg |= (SLIRP_DBG_CALL | SLIRP_DBG_MISC | SLIRP_DBG_ERROR | SLIRP_DBG_VERBOSE_CALL); + } else + *err = 1; + + if (*err == 0) { + dbg_tokens = strchr(dbg_tokens, ';'); + if (dbg_tokens != NULL) + ++dbg_tokens; + } + } + + return slirp_dbg; +} + +/* SIMH uses a custom logger to output libslirp messages. */ + +static void output_stderr_noexit(const char *fmt, va_list args) +{ + char stackbuf[256]; + char *buf = stackbuf; + size_t bufsize = sizeof(stackbuf); + int vlen; + + do { + vlen = vsnprintf(buf, bufsize, fmt, args); + if (vlen < 0 || ((size_t) vlen) >= bufsize - 2) { + /* Reallocate a larger buffer... */ + if (buf != stackbuf) + free(buf); + bufsize *= 2; + if (bufsize < (size_t) (vlen + 2)) + bufsize = (size_t) (vlen + 2); + buf = (char *) calloc(bufsize, sizeof(char)); + if (buf == NULL) + return; + } + } while (vlen < 0 || (size_t) vlen >= bufsize - 1); + + buf[vlen++] = '\n'; + buf[vlen] = '\0'; + + sim_misc_debug("libslirp", "trace", buf); + + if (buf != stackbuf) + free(buf); +} + +static void output_stderr_exit(const char *fmt, va_list args) +{ + output_stderr_noexit(fmt, args); + exit(1); + g_assert_not_reached(); +} + +static void libslirp_guest_error(const char *msg, void *opaque) +{ + /* SimSlirpNetwork *slirp = (SimSlirpNetwork *) opaque; */ + GLIB_UNUSED_PARAM(opaque); + + if (sim_deb != NULL) { + fprintf(sim_deb, "libslirp guest error: %s\n", msg); + fflush(sim_deb); + } + + fprintf(stderr, "libslirp guest error: %s\n", msg); + fflush(stderr); +} + +static GLibLogger simh_logger = { + .logging_enabled = 1, + .output_warning = output_stderr_noexit, + .output_debug = output_stderr_noexit, + .output_error = output_stderr_exit, + .output_critical = output_stderr_exit +}; + +/* Forward decl's... */ +static int initialize_poll_fds(SimSlirpNetwork *slirp); +static slirp_ssize_t invoke_sim_packet_callback(const void *buf, size_t len, void *opaque); +static void notify_callback(void *opaque); + +SimSlirpNetwork *sim_slirp_open(const char *args, void *pkt_opaque, packet_callback pkt_callback, DEVICE *dptr, uint32 dbit, + char *errbuf, size_t errbuf_size) +{ + SimSlirpNetwork *slirp = (SimSlirpNetwork *) calloc(1, sizeof(*slirp)); + SlirpConfig *cfg = &slirp->slirp_config; + SlirpCb *cbs = &slirp->slirp_callbacks; + + char *targs = strdup(args); + const char *tptr = targs; + const char *cptr; + char tbuf[CBUFSIZE], gbuf[CBUFSIZE], abuf[CBUFSIZE]; + int err; + struct in6_addr default_ipv6_prefix, default_ipv6_gw; + + /* Default IPv6 address -- FIXME */ + inet_pton(AF_INET6, SIMH_IP6_NETWORK, &default_ipv6_prefix); + inet_pton(AF_INET6, SIMH_GW_ADDR6, &default_ipv6_gw); + + /* Version 1 config */ + cfg->version = SLIRP_CONFIG_VERSION_MAX; + cfg->restricted = 0; + cfg->in_enabled = 1; + cfg->vnetwork.s_addr = htonl(SIMH_IP_NETWORK); + cfg->vnetmask.s_addr = htonl(SIMH_IP_NETMASK); + cfg->vhost.s_addr = htonl(SIMH_GATEWAY_ADDR); + cfg->in6_enabled = 0; + cfg->vprefix_addr6 = default_ipv6_prefix; + cfg->vprefix_len = SIMH_IP6_PREFIX_LEN; + cfg->vhost6 = default_ipv6_gw; + cfg->vnameserver.s_addr = htonl(SIMH_RESOLVER_ADDR); + + /* Version 2 config: nothing used */ + /* Version 3 config: */ + cfg->disable_dns = 0; + + /* Version 4 config */ + /* DHCP enabled by default. */ + cfg->disable_dhcp = 0; + + /* Version 5 config: nothing used */ + + /* SIMH state/config */ + slirp->args = (char *) calloc(1 + strlen(args), sizeof(char)); + strcpy(slirp->args, args); + pthread_mutex_init(&slirp->libslirp_access, NULL); + + slirp->original_debflags = dptr->debflags; + dptr->debflags = sim_combine_debtabs(dptr->debflags, slirp_dbgtable); + sim_fill_debtab_flags(dptr->debflags); + slirp->flag_offset = sim_debtab_nelems(slirp->original_debflags); + + /* Parse through arguments... */ + err = 0; + while (*tptr && !err) { + tptr = get_glyph_nc(tptr, tbuf, ','); + if (!tbuf[0]) + break; + cptr = tbuf; + cptr = get_glyph(cptr, gbuf, '='); + if (0 == MATCH_CMD(gbuf, "DHCP")) { + cfg->disable_dhcp = 0; + if (cptr != NULL && *cptr != '\0') + simh_inet_aton(cptr, &cfg->vdhcp_start); + continue; + } + if (0 == MATCH_CMD(gbuf, "TFTP")) { + if (cptr != NULL && *cptr != '\0') + slirp->the_tftp_path = strdup(cptr); + else { + strlcpy(errbuf, "Missing TFTP Path", errbuf_size); + err = 1; + } + continue; + } + if (0 == MATCH_CMD(gbuf, "BOOTFILE")) { + if (cptr && *cptr) + slirp->the_bootfile = strdup(cptr); + else { + strlcpy(errbuf, "Missing DHCP Boot file name", errbuf_size); + err = 1; + } + continue; + } + if ((0 == MATCH_CMD(gbuf, "NAMESERVER")) || (0 == MATCH_CMD(gbuf, "DNS"))) { + if (cptr && *cptr) + simh_inet_aton(cptr, &cfg->vnameserver); + else { + strlcpy(errbuf, "Missing nameserver", errbuf_size); + err = 1; + } + continue; + } + if (0 == MATCH_CMD(gbuf, "DNSSEARCH")) { + if (cptr != NULL && *cptr) { + int count = 0; + char *name; + + slirp->dns_search = strdup(cptr); + name = slirp->dns_search; + do { + ++count; + slirp->dns_search_domains = (char **)realloc(cfg->vdnssearch, (count + 1) * sizeof(char *)); + slirp->dns_search_domains[count] = NULL; + slirp->dns_search_domains[count - 1] = name; + if (NULL != (name = strchr(name, ','))) { + *name = '\0'; + ++name; + } + } while (NULL != name && *name); + } else { + strlcpy(errbuf, "Missing DNS search list", errbuf_size); + err = 1; + } + continue; + } + if (0 == MATCH_CMD(gbuf, "GATEWAY") || 0 == MATCH_CMD(gbuf, "GW")) { + if (cptr && *cptr) { + cptr = get_glyph(cptr, abuf, '/'); + if (cptr && *cptr) + cfg->vnetmask.s_addr = htonl(~((1 << (32 - atoi(cptr))) - 1)); + simh_inet_aton(abuf, &cfg->vhost); + } else { + strlcpy(errbuf, "Missing host", errbuf_size); + err = 1; + } + continue; + } + if (0 == MATCH_CMD(gbuf, "NETWORK")) { + if (cptr && *cptr) { + cptr = get_glyph(cptr, abuf, '/'); + if (cptr && *cptr) + cfg->vnetmask.s_addr = htonl(~((1 << (32 - atoi(cptr))) - 1)); + simh_inet_aton(abuf, &cfg->vnetwork); + } else { + strlcpy(errbuf, "Missing network", errbuf_size); + err = 1; + } + continue; + } + if (0 == MATCH_CMD(gbuf, "NODHCP")) { + cfg->disable_dhcp = 1; + continue; + } + if (0 == MATCH_CMD(gbuf, "UDP")) { + if (cptr && *cptr) + err = parse_redirect_port(&slirp->rtcp, cptr, IS_UDP); + else { + strlcpy(errbuf, "Missing UDP port mapping", errbuf_size); + err = 1; + } + continue; + } + if (0 == MATCH_CMD(gbuf, "TCP")) { + if (cptr && *cptr) + err = parse_redirect_port(&slirp->rtcp, cptr, IS_TCP); + else { + strlcpy(errbuf, "Missing TCP port mapping", errbuf_size); + err = 1; + } + continue; + } + if (0 == MATCH_CMD(gbuf, "IPV6")) { + cfg->in6_enabled = 1; + continue; + } + if (0 == MATCH_CMD(gbuf, "SLIRP")) { + unsigned int slirp_dbg = collect_slirp_debug(cptr, &err); + + if (!err) { + slirp_set_debug(slirp_dbg); + continue; + } + } + if (0 == MATCH_CMD(gbuf, "NOSLIRP")) { + unsigned int slirp_dbg = collect_slirp_debug(cptr, &err); + + if (!err) { + slirp_reset_debug(slirp_dbg); + continue; + } + } + snprintf(errbuf, errbuf_size - 1, "Unexpected NAT argument: %s", gbuf); + err = 1; + } + + if (err) { + sim_slirp_close(slirp); + free(targs); + return NULL; + } + + /* Adjust the network prefix, update the guest's configuration. */ + cfg->vnetwork.s_addr = cfg->vhost.s_addr & cfg->vnetmask.s_addr; + if ((cfg->vhost.s_addr & ~cfg->vnetmask.s_addr) == 0) + cfg->vhost.s_addr = htonl(ntohl(cfg->vnetwork.s_addr) | 2); + if (cfg->vdhcp_start.s_addr == 0) + cfg->vdhcp_start.s_addr = htonl(ntohl(cfg->vnetwork.s_addr) | 15); + if (cfg->vnameserver.s_addr == 0) + cfg->vnameserver.s_addr = htonl(ntohl(cfg->vnetwork.s_addr) | 3); + + /* Set the DNS search domains */ + cfg->vdnssearch = (const char **) slirp->dns_search_domains; + + /* Set the BOOTP file and TFTP path in the Slirp config: */ + cfg->bootfile = slirp->the_bootfile; + cfg->tftp_path = slirp->the_tftp_path; + + /* Initialize the callbacks: */ + slirp->pkt_callback = pkt_callback; + slirp->pkt_opaque = pkt_opaque; + glib_set_logging_hooks(&simh_logger); + + cbs->send_packet = invoke_sim_packet_callback; + cbs->guest_error = libslirp_guest_error; + cbs->clock_get_ns = sim_clock_get_ns; + cbs->register_poll_socket = register_poll_socket; + cbs->unregister_poll_socket = unregister_poll_socket; + cbs->notify = notify_callback; + cbs->timer_mod = simh_timer_mod; + cbs->timer_free = simh_timer_free; + cbs->timer_new_opaque = simh_timer_new_opaque; + + slirp->slirp_cxn = slirp_new(cfg, cbs, (void *) slirp); + + /* Capture the debugging info. */ + slirp->dbit = dptr->dctrl = dbit; + slirp->dptr = dptr; + + initialize_poll_fds(slirp); + + if (do_redirects(slirp, slirp->rtcp)) { + sim_slirp_close(slirp); + slirp = NULL; + } else { + sim_slirp_show(slirp, stdout); + if (sim_log != NULL && sim_log != stdout) + sim_slirp_show(slirp, sim_log); + if (sim_deb != NULL && sim_deb != stdout && sim_deb != sim_log) + sim_slirp_show(slirp, sim_deb); + } + + free(targs); + return slirp; +} + +void sim_slirp_close(SimSlirpNetwork *slirp) +{ + struct redir_tcp_udp *rtmp; + + if (slirp == NULL) + return; + + free(slirp->args); + free(slirp->the_tftp_path); + free(slirp->the_bootfile); + free(slirp->dns_search); + free(slirp->dns_search_domains); + + if (slirp->slirp_cxn != NULL) { + while ((rtmp = slirp->rtcp) != NULL) { + slirp_remove_hostfwd(slirp->slirp_cxn, rtmp->is_udp, rtmp->sim_local_inaddr, rtmp->sim_local_port); + slirp->rtcp = rtmp->next; + free(rtmp); + } + + slirp_cleanup(slirp->slirp_cxn); + } + + if (slirp->dptr != NULL) { + free(slirp->dptr->debflags); + slirp->dptr->debflags = slirp->original_debflags; + } + +#if SIM_USE_SELECT + free(slirp->lut); +#else + free(slirp->fds); +#endif + + pthread_mutex_destroy(&slirp->libslirp_access); + free(slirp); +} + +t_stat sim_slirp_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ + GLIB_UNUSED_PARAM(dptr); + GLIB_UNUSED_PARAM(uptr); + GLIB_UNUSED_PARAM(flag); + GLIB_UNUSED_PARAM(cptr); + + fprintf(st, "%s", + "NAT options:\n" + " DHCP{=dhcp_start_address} Enables DHCP server and specifies\n" + " guest LAN DHCP start IP address\n" + " BOOTFILE=bootfilename specifies DHCP returned Boot Filename\n" + " TFTP=tftp-base-path Enables TFTP server and specifies\n" + " base file path\n" + " NAMESERVER=nameserver_ipaddres specifies DHCP nameserver IP address\n" + " DNS=nameserver_ipaddres specifies DHCP nameserver IP address\n" + " DNSSEARCH=domain{:domain{:domain}} specifies DNS Domains search suffixes\n" + " GATEWAY=host_ipaddress{/masklen} specifies LAN gateway IP address\n" + " NETWORK=network_ipaddress{/masklen} specifies LAN network address\n" + " UDP=port:address:address's-port maps host UDP port to guest port\n" + " TCP=port:address:address's-port maps host TCP port to guest port\n" + " NODHCP disables DHCP server\n\n" + "Default NAT Options: GATEWAY=10.0.2.2, masklen=24(netmask is 255.255.255.0)\n" + " DHCP=10.0.2.15, NAMESERVER=10.0.2.3\n" + " Nameserver defaults to proxy traffic to host system's active nameserver\n\n" + "The 'address' field in the UDP and TCP port mappings are the simulated\n" + "(guest) system's IP address which, if DHCP allocated would default to\n" + "10.0.2.15 or could be statically configured to any address including\n" + "10.0.2.4 thru 10.0.2.14.\n\n" + "NAT limitations\n\n" + "There are four limitations of NAT mode which users should be aware of:\n\n" + " 1) ICMP protocol limitations:\n" + " Some frequently used network debugging tools (e.g. ping or tracerouting)\n" + " rely on the ICMP protocol for sending/receiving messages. While some\n" + " ICMP support is available on some hosts (ping may or may not work),\n" + " some other tools may not work reliably.\n\n" + " 2) Receiving of UDP broadcasts is not reliable:\n" + " The guest does not reliably receive broadcasts, since, in order to save\n" + " resources, it only listens for a certain amount of time after the guest\n" + " has sent UDP data on a particular port.\n\n" + " 3) Protocols such as GRE, DECnet, LAT and Clustering are unsupported:\n" + " Protocols other than TCP and UDP are not supported.\n\n" + " 4) Forwarding host ports < 1024 impossible:\n" + " On Unix-based hosts (e.g. Linux, Solaris, Mac OS X) it is not possible\n" + " to bind to ports below 1024 from applications that are not run by root.\n" + " As a result, if you try to configure such a port forwarding, the attach\n" + " will fail.\n\n" + "These limitations normally don't affect standard network use. But the\n" + "presence of NAT has also subtle effects that may interfere with protocols\n" + "that are normally working. One example is NFS, where the server is often\n" + "configured to refuse connections from non-privileged ports (i.e. ports not\n" + " below 1024).\n"); + return SCPE_OK; +} + +/* Initialize the select/poll file descriptor arrays. */ +static int initialize_poll_fds(SimSlirpNetwork *slirp) +{ +#if SIM_USE_SELECT + size_t i; + + FD_ZERO(&slirp->readfds); + FD_ZERO(&slirp->writefds); + FD_ZERO(&slirp->exceptfds); + + /* Start out with a generous number of LUT slots */ + slirp->lut_alloc = FDS_ALLOC_INIT; + slirp->lut = (SOCKET *) malloc(slirp->lut_alloc * sizeof(SOCKET)); + + for (i = 0; i < slirp->lut_alloc; ++i) + slirp->lut[i] = INVALID_SOCKET; +#else + /* poll()-based file descriptor polling. */ + slirp->n_fds = FDS_ALLOC_INIT; + slirp->fd_idx = 0; + slirp->fds = (sim_pollfd_t *) calloc(slirp->n_fds, sizeof(sim_pollfd_t)); +#endif + + return 0; +} + +/* Show NAT network statistics. */ +void sim_slirp_show(SimSlirpNetwork *slirp, FILE *st) +{ + struct redir_tcp_udp *rtmp; + const SlirpConfig *cfg = &slirp->slirp_config; + char *conn_info; + + if (slirp == NULL || slirp->slirp_cxn == NULL) + return; + + fprintf(st, "NAT args: %s\n", (slirp->args != NULL ? slirp->args : "(none given)")); + fprintf(st, "NAT network setup:\n"); + fprintf(st, " gateway = %s", sim_inet_ntoa4(&cfg->vhost)); + fprintf(st, " (%s)\n", sim_inet_ntoa4(&cfg->vnetmask)); +#if defined(AF_INET6) + fprintf(st, " IPv6 = %sabled.\n", slirp->slirp_config.in6_enabled ? "en" : "dis"); + if (slirp->slirp_config.in6_enabled) { + fprintf(st, " V6 Prefix = %s/%d\n", sim_inet_ntoa6(&slirp->slirp_config.vprefix_addr6), + slirp->slirp_config.vprefix_len); + fprintf(st, " V6 Gateway = %s\n", sim_inet_ntoa6(&slirp->slirp_config.vhost6)); + } +#endif + fprintf(st, " DNS = %s\n", sim_inet_ntoa4(&cfg->vnameserver)); + if (cfg->vdhcp_start.s_addr != 0) + fprintf(st, " dhcp_start = %s\n", sim_inet_ntoa4(&cfg->vdhcp_start)); + if (cfg->bootfile != NULL) + fprintf(st, " dhcp bootfile = %s\n", cfg->bootfile); + if (cfg->vdnssearch) { + const char **domains = cfg->vdnssearch; + + fprintf(st, " DNS domains = "); + while (*domains != NULL) { + fprintf(st, "%s%s", (domains != cfg->vdnssearch) ? ", " : "", *domains); + ++domains; + } + fprintf(st, "\n"); + } + if (cfg->tftp_path != NULL) + fprintf(st, " tftp prefix = %s\n", cfg->tftp_path); + rtmp = slirp->rtcp; + while (rtmp != NULL) { + fprintf(st, " redir %3s = %d:%s:%d\n", tcpudp[rtmp->is_udp], rtmp->sim_local_port, + sim_inet_ntoa4(&rtmp->sim_local_inaddr), rtmp->simh_host_port); + rtmp = rtmp->next; + } + + if ((conn_info = slirp_connection_info(slirp->slirp_cxn)) != NULL) { + fputs(conn_info, st); + free(conn_info); + } +} + +/*~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~= + * The libslirp interface. + * + * libslirp has an inverted sense of input and output. "Input" means "input into libslirp", whereas "output" means + * output to the guest (the simulator via sim_ether and friends.) + *~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=*/ + +/* Invoke the SIMH packet callback. */ +static slirp_ssize_t invoke_sim_packet_callback(const void *buf, size_t len, void *opaque) +{ + SimSlirpNetwork *slirp = (SimSlirpNetwork *) opaque; + + /* Note: Should really range check len for int bounds. */ + slirp->pkt_callback(slirp->pkt_opaque, buf, (int) len); + /* FIXME: the packet callback should tell us how many octets were written. + * For the time being, though, assume it was successful. */ + return len; +} + +int sim_slirp_send(SimSlirpNetwork *slirp, const char *msg, size_t len, int flags) +{ + GLIB_UNUSED_PARAM(flags); + + /* Just send the packet up to libslirp. */ + pthread_mutex_lock(&slirp->libslirp_access); + slirp_input(slirp->slirp_cxn, (const uint8_t *) msg, (int) len); + pthread_mutex_unlock(&slirp->libslirp_access); + + return (int) len; +} + +/* I/O thread notify callback from Slirp. Indicates that there's packet data waiting, I/O events + * are pending. */ +static void notify_callback(void *opaque) +{ + /* SimSlirpNetwork *slirp = (SimSlirpNetwork *) opaque; */ + GLIB_UNUSED_PARAM(opaque); +} + +void sim_slirp_dispatch(SimSlirpNetwork *slirp) +{ + /* Outbound packets directly to slirp_input() and packets going to the + * simulator are handled in sim_slirp_select(). + * + * Packet traffic between the simulator and libslirp is handled in + * sim_slirp_select(). + */ + + GLIB_UNUSED_PARAM(slirp); +} + +int64_t sim_clock_get_ns(void *opaque) +{ + GLIB_UNUSED_PARAM(opaque); + + /* Internally, libslirp cuts the nanoseconds down to milliseconds. */ + return ((uint64_t) sim_os_msec()) * 10000000ull; +} diff --git a/sim_slirp/sim_slirp.h b/sim_slirp/sim_slirp.h new file mode 100644 index 000000000..f7a3aa068 --- /dev/null +++ b/sim_slirp/sim_slirp.h @@ -0,0 +1,28 @@ +#if !defined(SIM_SLIRP_H) + +#if defined(HAVE_SLIRP_NETWORK) + +#include "sim_defs.h" +#include "libslirp.h" + + +typedef struct sim_slirp SimSlirpNetwork; + +typedef void (*packet_callback)(void *opaque, const unsigned char *buf, int len); + +SimSlirpNetwork *sim_slirp_open (const char *args, void *pkt_opaque, packet_callback pkt_callback, DEVICE *dptr, uint32 dbit, char *errbuf, size_t errbuf_size); +void sim_slirp_close (SimSlirpNetwork *slirp); +int sim_slirp_send (SimSlirpNetwork *slirp, const char *msg, size_t len, int flags); +int sim_slirp_select (SimSlirpNetwork *slirp, int ms_timeout); +void sim_slirp_dispatch (SimSlirpNetwork *slirp); +t_stat sim_slirp_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +void sim_slirp_show (SimSlirpNetwork *slirp, FILE *st); + +/* Internal support functions: */ +int64_t sim_clock_get_ns(void *opaque); + +#endif /* HAVE_SLIRP_NETWORK */ + + +#define SIM_SLIRP_H +#endif diff --git a/sim_slirp/sim_slirp_network.h b/sim_slirp/sim_slirp_network.h new file mode 100644 index 000000000..c8afa8708 --- /dev/null +++ b/sim_slirp/sim_slirp_network.h @@ -0,0 +1,139 @@ +/* sim_network_state.h: Header file for the SimSlirpNetwork structure. + * + * Previously, this structure was locally defined in sim_slirp.c, which is + * inconvenient when referring to the structure members (scroll up to refer, + * scroll down to code.) Broken out as its own entity. + */ + +#include "sim_sock.h" +#include "sim_slirp.h" +#include "libslirp.h" + +#if !defined(SLIRP_NETWORK_STATE_H) + +#if !defined(USE_READER_THREAD) +#define pthread_mutex_init(mtx, val) +#define pthread_mutex_destroy(mtx) +#define pthread_mutex_lock(mtx) +#define pthread_mutex_unlock(mtx) +#define pthread_mutex_t int +#endif + +/* WSAPoll() is available on Windows Vista (> 0x0600) and higher, otherwise revert to + * select(). */ +#if SIM_USE_POLL && defined(WINVER) && WINVER < 0x0600 +# undef SIM_USE_SELECT +# undef SIM_USE_POLL +# define SIM_USE_SELECT 1 +# define SIM_USE_POLL 0 +#endif + +#if !defined(SIM_USE_SELECT) && !defined(SIM_USE_POLL) +# error "sim_slirp.c: Configuration error: define SIM_USE_SELECT, SIM_USE_POLL" +#endif + +#if SIM_USE_SELECT + SIM_USE_POLL > 1 +# error "sim_slirp.c: Configuration error: set one of SIM_USE_SELECT, SIM_USE_POLL to 1." +#endif + +/* Abstract the poll structure as sim_pollfd_t */ +#if SIM_USE_POLL +# if (defined(_WIN32) || defined(_WIN64)) + typedef WSAPOLLFD sim_pollfd_t; +# else +# include + typedef struct pollfd sim_pollfd_t; +# endif +#endif + +#if SIM_USE_SELECT +#define SIM_INVALID_MAX_FD ((slirp_os_socket) -1) +#endif + +/* sim_slirp debugging: */ +enum { + DBG_POLL = 0, + DBG_SOCKET = 1 +}; + +struct sim_slirp { + SlirpConfig slirp_config; + SlirpCb slirp_callbacks; + Slirp *slirp_cxn; + + char *args; + +#if defined(USE_READER_THREAD) + /* Access lock to libslirp. libslirp is not threaded or protected. */ + pthread_mutex_t libslirp_access; +#endif + + /* DNS search domains (argument copy) */ + char *dns_search; + char **dns_search_domains; + /* Boot file and TFTP path prefix (argument copy) */ + char *the_bootfile; + char *the_tftp_path; + /* UDP and TCP ports that SIMH proxies to the Slirp network */ + struct redir_tcp_udp *rtcp; + /* SIMH's packet callback and associated packet data. */ + packet_callback pkt_callback; + void *pkt_opaque; + + /* Debugging bitmasks: */ + DEBTAB *original_debflags; + size_t flag_offset; + + /* I/O event tracking/handling (used to be the GPollFD array): */ +#if SIM_USE_SELECT + /* select() needs a lookup table to map SOCKETs to an integer index. */ + fd_set readfds; + fd_set writefds; + fd_set exceptfds; + slirp_os_socket max_fd; + + /* Lookup table: */ + slirp_os_socket *lut; + size_t lut_alloc; +#else + /* More generally, this is for poll(). */ + + /* Poll file descriptor array */ + sim_pollfd_t *fds; + /* Next descriptor to use */ + size_t fd_idx; + /* Total allocated descriptors */ + size_t n_fds; +#endif + + /* SIMH debug info: */ + DEVICE *dptr; + uint32 dbit; +}; + +/* Simulator -> host network redirection state. */ +struct redir_tcp_udp { + int is_udp; + /* SIMH host port, e.g., 2223. */ + int simh_host_port; + /* The simulator's IP address, e.g., 10.0.2.4 or 10.0.2.15 */ + struct in_addr sim_local_inaddr; + /* The simulator's port, e.g., 23 */ + int sim_local_port; + struct redir_tcp_udp *next; +}; + +/* File descriptor array initial allocation, incremental (linear) allocation. */ +#define FDS_ALLOC_INIT 32 +#define FDS_ALLOC_INCR 32 + +/* slirp_poll.c externs: */ +void register_poll_socket(slirp_os_socket fd, void *opaque); +void unregister_poll_socket(slirp_os_socket fd, void *opaque); + +void *simh_timer_new_opaque(SlirpTimerId id, void *cb_opaque, void *opaque); +void simh_timer_free(void *the_timer, void *opaque); +void simh_timer_mod(void *timer, int64_t expire_time, void *opaque); + +#define SLIRP_NETWORK_STATE_H +#endif diff --git a/sim_slirp/slirp_poll.c b/sim_slirp/slirp_poll.c new file mode 100644 index 000000000..ef7e0def6 --- /dev/null +++ b/sim_slirp/slirp_poll.c @@ -0,0 +1,553 @@ +/* sim_slirp.c: + ------------------------------------------------------------------------------ + Copyright (c) 2024, B. Scott Michel + + 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 AUTHOR 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. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + ------------------------------------------------------------------------------ + + This module encapsulates the poll()/select() interface to libslirp. + +*/ + +#include +#include /* Paranoia for Win32/64 */ +#include + +#include "libslirp.h" +#include "sim_defs.h" +#include "scp.h" +#include "sim_sock.h" +#include "sim_slirp_network.h" +#include "sim_printf_fmts.h" + +#if defined(HAVE_INTTYPES_H) +#include +#endif + +#if defined(_WIN64) +# if defined(PRIu64) +# define SIM_PRIsocket PRIu64 +# else +# define SIM_PRIsocket "llu" +# endif +#elif defined(_WIN32) +# if defined(PRIu32) +# define SIM_PRIsocket PRIu32 +# else +# define SIM_PRIsocket "lu" +# endif +#else +# define SIM_PRIsocket "u" +#endif + +/* Forward decl's: */ +static int add_poll_callback(slirp_os_socket fd, int events, void *opaque); +static int get_events_callback(int idx, void *opaque); +static void simh_timer_check(Slirp *slirp); + +/* Protocol functions: */ +static void initialize_poll(SimSlirpNetwork *slirp, uint32 tmo, struct timeval *tv); +static int do_poll(SimSlirpNetwork *slirp, int ms_timeout, struct timeval *timeout); +static void report_error(SimSlirpNetwork *slirp); + +static inline uint32_t slirp_dbg_mask(const SimSlirpNetwork *slirp, size_t flag) +{ + return (slirp != NULL && slirp->dptr != NULL) ? slirp->dptr->debflags[slirp->flag_offset + flag].mask : 0; +} + +#if SIM_USE_SELECT +/* Socket identifier pretty-printer: */ +static const char *print_socket(slirp_os_socket s) +{ + static char retbuf[64]; + +#if defined(_WIN64) + sprintf(retbuf, "%llu", s); +#elif defined(_WIN32) + sprintf(retbuf, "%u", s); +#else + sprintf(retbuf, "%d", s); +#endif + + return retbuf; +} +#endif + +/*~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~= + * The libslirp poll()/select() interface: + * + * sim_slirp_select() is simply a driver function that invokes three "protocol" functions to initialize, poll and + * report an error. The protocol functions isolate functionality without making sim_slirp_select() overly complex. + *~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=*/ + +int sim_slirp_select(SimSlirpNetwork *slirp, int ms_timeout) +{ + int retval = 0; + uint32 slirp_timeout = ms_timeout; + struct timeval tv; + + if (slirp == NULL) + /* Will cause the reader thread to exit! */ + return -1; + + /* Note: It's a generally good practice to acquire a mutex and hold it until an operation + * completes. In this case, though, poll()/select() will block and prevent outbound writes + * via sim_slirp_send(), which itself blocks waiting for the mutex. + * + * Hold the mutex only when calling libslirp functions, reacquire when needed. + */ + pthread_mutex_lock(&slirp->libslirp_access); + + /* Check on expiring libslirp timers. */ + simh_timer_check(slirp->slirp_cxn); + + /* Ask libslirp to poll for I/O events. */ + initialize_poll(slirp, slirp_timeout, &tv); + slirp_pollfds_fill_socket(slirp->slirp_cxn, &slirp_timeout, add_poll_callback, slirp); + + pthread_mutex_unlock(&slirp->libslirp_access); + + retval = do_poll(slirp, ms_timeout, &tv); + + if (retval > 0) { + /* The libslirp idiom invokes slirp_pollfds_poll within the same function as slirp_pollfds_fill(). */ + pthread_mutex_lock(&slirp->libslirp_access); + slirp_pollfds_poll(slirp->slirp_cxn, 0, get_events_callback, slirp); + pthread_mutex_unlock(&slirp->libslirp_access); + } else if (retval < 0) { + report_error(slirp); + } + + return retval; +} + +/*~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~= + * "Protocol" functions. These functions abide by the one function definition rule. + *~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=*/ + +#if (defined(_WIN32) || defined(_WIN64)) && SIM_USE_POLL +static inline int poll(WSAPOLLFD *fds, size_t n_fds, int timeout) +{ + return WSAPoll(fds, (ULONG) n_fds, timeout); +} +#endif + +static void initialize_poll(SimSlirpNetwork *slirp, uint32 tmo, struct timeval *tv) +{ +#if SIM_USE_SELECT + tv->tv_sec = tmo / 1000; + tv->tv_usec = (tmo % 1000) * 1000; + + FD_ZERO(&slirp->readfds); + FD_ZERO(&slirp->writefds); + FD_ZERO(&slirp->exceptfds); + + slirp->max_fd = SIM_INVALID_MAX_FD; +#elif SIM_USE_POLL + /* Reinitialize and reset */ + memset(slirp->fds, 0, slirp->fd_idx * sizeof(sim_pollfd_t)); + slirp->fd_idx = 0; +#endif +} + +static int do_poll(SimSlirpNetwork *slirp, int ms_timeout, struct timeval *timeout) +{ + int retval = 0; + +#if SIM_USE_SELECT +# if defined(_WIN32) + /* Windows: The first argument to select(), nfds, is ignored by winsock2. You could pass a + * random value and winsock2 wouldn't care. 0xdeadbeef seems appropriate. + * + * The only way to know whether there is work to be done is to examine the fd_count member in + * the fd_set structure. + */ + if (slirp->readfds.fd_count + slirp->writefds.fd_count + slirp->exceptfds.fd_count > 0) { + retval = select(/* ignored */ 0xdeadbeef, &slirp->readfds, &slirp->writefds, &slirp->exceptfds, timeout); + if (retval > 0) + sim_debug(slirp_dbg_mask(slirp, DBG_POLL), slirp->dptr, + "do_poll(): select() returned %d (read: %u, write: %u, except: %u)\n", + retval, slirp->readfds.fd_count, slirp->writefds.fd_count, slirp->exceptfds.fd_count); + } +# else + if (slirp->max_fd != SIM_INVALID_MAX_FD) { + retval = select(slirp->max_fd + 1, &slirp->readfds, &slirp->writefds, &slirp->exceptfds, &imeout); + if (retval > 0) + sim_debug(slirp_dbg_mask(slirp, DBG_POLL), slirp->dptr, "do_poll(): select() returned %d\n", retval); + } +# endif +#elif SIM_USE_POLL + if (slirp->fd_idx > 0) { + sim_debug(slirp_dbg_mask(slirp, DBG_POLL), slirp->dptr, + "poll()-ing for %" SIZE_T_FMT "u sockets\n", slirp->fd_idx); + + retval = poll(slirp->fds, slirp->fd_idx, ms_timeout); + if (retval > 0) + sim_debug(slirp_dbg_mask(slirp, DBG_POLL), slirp->dptr, "do_poll(): poll() returned %d\n", retval); + } +#endif + + return retval; +} + +static void report_error(SimSlirpNetwork *slirp) +{ +#if defined(_WIN32) + char *wsaMsgBuffer = NULL; + int wsaError = WSAGetLastError(); + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + WSAGetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* The user default language */ + (LPTSTR) &wsaMsgBuffer, + 0, + NULL); + + if (sim_deb != stdout && sim_deb != stderr) { + fprintf(stderr, "sim_slirp_select() winsock error: %d (%s)", wsaError, wsaMsgBuffer); + fflush(stderr); + } + sim_messagef(SCPE_IERR, "sim_slirp_select(): WSAGetLastError() %d (%s)\n", wsaError, wsaMsgBuffer); + LocalFree(wsaMsgBuffer); +#else + sim_messagef(SCPE_IERR, "sim_slirp_select(): do_poll() -- errno = %d, %s\n", errno, g_strerror(errno)); +#endif +} + +/* Add new socket file descriptors to the Slirp I/O event tracking state. */ +void register_poll_socket(slirp_os_socket fd, void *opaque) +{ +#if SIM_USE_SELECT + SimSlirpNetwork *slirp = (SimSlirpNetwork *) opaque; + size_t i; + + for (i = 0; i < slirp->lut_alloc; ++i) { + if (slirp->lut[i] == INVALID_SOCKET) { + slirp->lut[i] = fd; + break; + } + } + + if (i == slirp->lut_alloc) { + SOCKET *new_lut; + size_t j = slirp->lut_alloc; + + /* Linear growth. */ + slirp->lut_alloc += FDS_ALLOC_INCR; + new_lut = (SOCKET *) realloc(slirp->lut, slirp->lut_alloc * sizeof(SOCKET)); + ASSURE(new_lut != NULL); + for (/* empty */; j < slirp->lut_alloc; ++j) + new_lut[j] = INVALID_SOCKET; + + slirp->lut = new_lut; + slirp->lut[i] = fd; + } + + sim_debug(slirp_dbg_mask(slirp, DBG_SOCKET), slirp->dptr, "register_poll_socket(%s) index %" SIZE_T_FMT "d\n", + print_socket(fd), i); +#elif SIM_USE_POLL + /* Not necessary for poll(). */ + (void) opaque; +#endif +} + +/* Reap a disused socket. */ +void unregister_poll_socket(slirp_os_socket fd, void *opaque) +{ + GLIB_UNUSED_PARAM(opaque); + +#if SIM_USE_SELECT + SimSlirpNetwork *slirp = (SimSlirpNetwork *) opaque; + size_t i; + + for (i = 0; i < slirp->lut_alloc; ++i) { + if (slirp->lut[i] == fd) { + slirp->lut[i] = INVALID_SOCKET; + sim_debug(slirp_dbg_mask(slirp, DBG_SOCKET), slirp->dptr, + "unregister_poll_socket(%s) index %" SIZE_T_FMT "d\n", print_socket(fd), i); + break; + } + } +#elif SIM_USE_POLL + /* Not necessary for poll(). */ + (void) opaque; +#endif +} + +/* Debugging output for add/get event callbacks. */ +static void poll_debugging(uint32_t dbits, DEVICE *dev, const char *prefix, int events) +{ + static struct transtab { + int slirp_event; + const char *slirp_event_str; + } translations[] = { + { SLIRP_POLL_IN, " SLIRP_POLL_IN" }, + { SLIRP_POLL_OUT, " SLIRP_POLL_OUT" }, + { SLIRP_POLL_PRI, " SLIRP_POLL_PRI" }, + { SLIRP_POLL_ERR, " SLIRP_POLL_ERR" }, + { SLIRP_POLL_HUP, " SLIRP_POLL_HUP" } + }; + static const size_t n_translations = sizeof(translations) / sizeof(translations[0]); + char *msg = calloc(96 + strlen(prefix) + 1, sizeof(char)); + + strcpy(msg, prefix); + if (events != 0) { + size_t i; + + strcat(msg, ": "); + for (i = 0; i < n_translations; ++i) { + if (translations[i].slirp_event & events) + strcat(msg, translations[i].slirp_event_str); + } + } else { + strcat(msg, ": [no events]"); + } + strcat(msg, "\n"); + + /* Don't need to escape "%"-s in msg, since there aren't any. */ + sim_debug(dbits, dev, "%s", msg); + if (sim_deb != NULL) + fflush(sim_deb); + free(msg); +} + +/* select()/poll() callback: For the sockets that Slirp (slirp_cxn) needs to examine for + * events, this callback adds them to the select file descriptor set or the poll array. */ +static int add_poll_callback(slirp_os_socket fd, int events, void *opaque) +{ + SimSlirpNetwork *slirp = (SimSlirpNetwork *) opaque; + int retval = -1; + char prefix[128]; + +#if SIM_USE_SELECT + size_t i; + const int event_mask = (SLIRP_POLL_IN | SLIRP_POLL_OUT | SLIRP_POLL_PRI); + + for (i = 0; i < slirp->lut_alloc; ++i) { + if (slirp->lut[i] == fd) { + if (events & SLIRP_POLL_IN) { + FD_SET(fd, &slirp->readfds); + } + if (events & SLIRP_POLL_OUT) { + FD_SET(fd, &slirp->writefds); + } + if (events & SLIRP_POLL_PRI) { + FD_SET(fd, &slirp->exceptfds); + } + + retval = (int) i; + + if (slirp->max_fd == SIM_INVALID_MAX_FD || fd > slirp->max_fd) + slirp->max_fd = fd; + + break; + } + + sprintf(prefix, "add_poll_callback(%s)/select (0x%04x)", print_socket(fd), events & event_mask); + poll_debugging(slirp_dbg_mask(slirp, DBG_POLL), slirp->dptr, prefix, events & event_mask); + } +#elif SIM_USE_POLL + if (slirp->fd_idx == slirp->n_fds) { + size_t j = slirp->n_fds; + sim_pollfd_t *new_fds; + + slirp->n_fds += FDS_ALLOC_INCR; + new_fds = (sim_pollfd_t *) realloc(slirp->fds, slirp->n_fds * sizeof(sim_pollfd_t)); + ASSURE(new_fds != NULL); + memset(new_fds + j, 0, (slirp->n_fds - j) * sizeof(sim_pollfd_t)); + slirp->fds = new_fds; + } + + short poll_events = 0; + + if (events & SLIRP_POLL_IN) { + poll_events |= POLLIN; + } + if (events & SLIRP_POLL_OUT) { + poll_events |= POLLOUT; + } +#if !defined(_WIN32) && !defined(_WIN64) + /* Not supported on Windows. Unless you like EINVAL. :-) */ + if (events & SLIRP_POLL_PRI) { + poll_events |= POLLPRI; + } + if (events & SLIRP_POLL_ERR) { + poll_events |= POLLERR; + } + if (events & SLIRP_POLL_HUP) { + poll_events |= POLLHUP; + } +#endif + + sprintf(prefix, "add_poll_callback(%" SIM_PRIsocket ")/poll (0x%04x)", fd, events); + poll_debugging(slirp_dbg_mask(slirp, DBG_POLL), slirp->dptr, prefix, events); + + slirp->fds[slirp->fd_idx].fd = fd; + slirp->fds[slirp->fd_idx].events = poll_events; + slirp->fds[slirp->fd_idx].revents = 0; + + retval = (int) slirp->fd_idx++; +#endif + + return retval; +} + +static int get_events_callback(int idx, void *opaque) +{ + const SimSlirpNetwork *slirp = (SimSlirpNetwork *) opaque; + int event = 0; + char prefix[128]; + +#if SIM_USE_SELECT + const int event_mask = (SLIRP_POLL_IN | SLIRP_POLL_OUT | SLIRP_POLL_PRI); + + if (idx >= 0 && (size_t) idx < slirp->lut_alloc) { + slirp_os_socket fd = slirp->lut[idx]; + + if (FD_ISSET(fd, &slirp->readfds)) { + event |= SLIRP_POLL_IN; + } + if (FD_ISSET(fd, &slirp->writefds)) { + event |= SLIRP_POLL_OUT; + } + if (FD_ISSET(fd, &slirp->exceptfds)) { + event |= SLIRP_POLL_PRI; + } + + sprintf(prefix, "get_events_callback(%s)/select (0x%04x)", print_socket(fd), event & event_mask); + poll_debugging(slirp_dbg_mask(slirp, DBG_POLL), slirp->dptr, prefix, event & event_mask); + } +#elif SIM_USE_POLL + if (idx < slirp->fd_idx) { + short poll_events = slirp->fds[idx].revents; + + if (poll_events & POLLIN) { + event |= SLIRP_POLL_IN; + } + if (poll_events & POLLOUT) { + event |= SLIRP_POLL_OUT; + } + if (poll_events & POLLPRI) { + event |= SLIRP_POLL_PRI; + } + if (poll_events & POLLERR) { + event |= SLIRP_POLL_ERR; + } + if (poll_events & POLLHUP) { + event |= SLIRP_POLL_HUP; + } + + sprintf(prefix, "get_events_callback(%" SIM_PRIsocket ")/poll (0x%04x)", slirp->fds[idx].fd, event); + poll_debugging(slirp_dbg_mask(slirp, DBG_POLL), slirp->dptr, prefix, event); + } +#endif + + return event; +} + + +/*~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~= + * libslirp timer management: This exclusively applies to IPv6. + *~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=*/ + +static struct slirp_timer_s { + SlirpTimerId id; /*< libslirp's timer identifier */ + void *cb_opaque; /*< Opaque thing to pass to the callback */ + int64_t expire_time_ns; /*< Expiration time, nanoseconds */ + struct slirp_timer_s *next; +} *slirp_timer_list = NULL; + +void *simh_timer_new_opaque(SlirpTimerId id, void *cb_opaque, void *opaque) +{ + struct slirp_timer_s *retval = (struct slirp_timer_s *) calloc(1, sizeof(struct slirp_timer_s)); + + GLIB_UNUSED_PARAM(opaque); + + retval->id = id; + retval->cb_opaque = cb_opaque; + + retval->next = slirp_timer_list; + slirp_timer_list = retval; + + return retval; +} + +void simh_timer_free(void *the_timer, void *opaque) +{ + struct slirp_timer_s *timer = the_timer; + struct slirp_timer_s **t; + + GLIB_UNUSED_PARAM(opaque); + + for (t = &slirp_timer_list; *t != NULL && *t != timer; t = &((*t) ->next)) + /* empty */; + + if (*t != NULL) + *t = timer->next; + + free(timer); +} + +void simh_timer_mod(void *the_timer, int64_t expire_time, void *opaque) +{ + struct slirp_timer_s *timer = the_timer; + struct slirp_timer_s **t; + + GLIB_UNUSED_PARAM(opaque); + + /* Upconvert to nanoseconds, unexpire. */ + timer->expire_time_ns = expire_time * 1000ll * 1000ll; + + /* Remove from the list. */ + for (t = &slirp_timer_list; *t != NULL && *t != timer; t = &((*t)->next)) + /* empty */; + + if (*t != NULL) + *t = timer->next; + + /* Reinsert in sorted order. */ + for (t = &slirp_timer_list; *t != NULL && expire_time < (*t)->expire_time_ns; t = &((*t)->next)) + /* empty */; + + timer->next = *t; + *t = timer; +} + +void simh_timer_check(Slirp *slirp) +{ + int64_t time_now = sim_clock_get_ns(NULL); + struct slirp_timer_s *t; + + GLIB_UNUSED_PARAM(slirp); + + for (t= slirp_timer_list; t != NULL && t->expire_time_ns <= time_now; /* empty */) { + /* libslirp's timer function that invoked us might call simh_timer_mod(), which + * potentially moves t->next. Keep track of the next element separately so that + * we keep synchronized with the list's order. */ + struct slirp_timer_s *t_next = t->next; + + slirp_handle_timer(slirp, t->id, t->cb_opaque); + t = t_next; + } +} diff --git a/sim_sock.c b/sim_sock.c index cd67895c3..071b1af4e 100644 --- a/sim_sock.c +++ b/sim_sock.c @@ -51,10 +51,6 @@ extern "C" { #include #include -#if defined(AF_INET6) && defined(_WIN32) -#include -#endif - #ifdef SIM_HAVE_DLOPEN #include #endif @@ -872,6 +868,83 @@ return sim_parse_addr (cptr, host, hostlen, default_host, port, port_len, defaul } +/* Convert IP address to its printable format. Supports IPv6. */ +static const char *sim_inet_ntoa(int family, const void *addr) +{ +#if !defined(WINVER) || WINVER >= 0x0603 + static char fmt_address[48]; + + inet_ntop(family, addr, fmt_address, sizeof(fmt_address) - 1); + return fmt_address; +#else + /* Squelch unused arg warning */ + (void)(family); + + return inet_ntoa(*((const struct in_addr *) addr)); +#endif +} + +/* Convert IPv4 address to printable format. */ +const char *sim_inet_ntoa4(const struct in_addr *v4addr) +{ + return sim_inet_ntoa(AF_INET, v4addr); +} + +/* Convert IPv6 address to printable format. */ +#if defined(AF_INET6) +const char *sim_inet_ntoa6(const struct in6_addr *addr) +{ +# if !defined(WINVER) || WINVER >= 0x0603 + return sim_inet_ntoa(AF_INET6, addr); +# else + struct sockaddr_storage ss; + DWORD s = INET6_ADDRSTRLEN; + static char dst[INET6_ADDRSTRLEN + 1]; + + ZeroMemory(&ss, sizeof(ss)); + ss.ss_family = AF_INET6; + ((struct sockaddr_in6 *) &ss)->sin6_addr = *addr; + return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0) ? dst : NULL; +# endif +} +#else +const char *sim_inet_ntoa6(const void *v6addr) +{ + return "IPv6 not supported"; +} +#endif + + +#if defined(WINVER) && WINVER < 0x0601 +/* Windows 7 and below stub, used by sim_slirp/sim_slirp.c */ + +int sim_inet_pton(int af, const char *src, void *dst) +{ + struct sockaddr_storage ss; + int size = sizeof(ss); + char src_copy[INET6_ADDRSTRLEN+1]; + + ZeroMemory(&ss, sizeof(ss)); + /* stupid non-const API */ + strncpy (src_copy, src, INET6_ADDRSTRLEN+1); + src_copy[INET6_ADDRSTRLEN] = 0; + + if (WSAStringToAddress(src_copy, af, NULL, (struct sockaddr *)&ss, &size) == 0) { + switch(af) { + case AF_INET: + *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr; + return 1; + case AF_INET6: + *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr; + return 1; + } + } + return 0; +} + +#endif + + void sim_init_sock (void) { #if defined (_WIN32) diff --git a/sim_sock.h b/sim_sock.h index 7ae40f59f..7daab6274 100644 --- a/sim_sock.h +++ b/sim_sock.h @@ -53,6 +53,8 @@ extern "C" { #if defined (_WIN32) /* Windows */ #include #include +#include +#include #elif !defined (__OS2__) || defined (__EMX__) /* VMS, Mac, Unix, OS/2 EMX */ #include /* for fcntl, getpid */ @@ -69,7 +71,10 @@ extern "C" { #define WSAGetLastError() errno /* Windows macros */ #define WSASetLastError(err) errno = err +#if !defined(closesocket) +/* libslirp defines this too. */ #define closesocket close +#endif #define SOCKET int #if defined(__hpux) #define WSAEWOULDBLOCK EAGAIN @@ -111,31 +116,46 @@ extern "C" { #define sim_printf printf #endif -int sim_parse_addr (const char *cptr, char *host, size_t hostlen, const char *default_host, - char *port, size_t port_len, const char *default_port, - const char *validate_addr); -int sim_parse_addr_ex (const char *cptr, char *host, size_t hostlen, const char *default_host, - char *port, size_t port_len, char *localport, size_t local_port_len, const char *default_port); -int sim_addr_acl_check (const char *validate_addr, const char *acl); -#define SIM_SOCK_OPT_REUSEADDR 0x0001 -#define SIM_SOCK_OPT_DATAGRAM 0x0002 -#define SIM_SOCK_OPT_NODELAY 0x0004 -#define SIM_SOCK_OPT_BLOCKING 0x0008 -SOCKET sim_master_sock_ex (const char *hostport, int *parse_status, int opt_flags); -#define sim_master_sock(hostport, parse_status) sim_master_sock_ex(hostport, parse_status, ((sim_switches & SWMASK ('U')) ? SIM_SOCK_OPT_REUSEADDR : 0)) -SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, int opt_flags); +int sim_parse_addr(const char *cptr, char *host, size_t hostlen, const char *default_host, + char *port, size_t port_len, const char *default_port, + const char *validate_addr); +int sim_parse_addr_ex(const char *cptr, char *host, size_t hostlen, const char *default_host, + char *port, size_t port_len, char *localport, size_t local_port_len, const char *default_port); +const char *sim_inet_ntoa4(const struct in_addr *addr); +#if defined(AF_INET6) +const char *sim_inet_ntoa6(const struct in6_addr *addr); +#else +const char *sim_inet_ntoa6(const void *addr); +#endif +#if defined(WINVER) && WINVER < 0x0601 +int sim_inet_pton(int af, const char *src, void *dst); +#endif + +int sim_addr_acl_check(const char *validate_addr, const char *acl); + +#define SIM_SOCK_OPT_REUSEADDR 0x0001 +#define SIM_SOCK_OPT_DATAGRAM 0x0002 +#define SIM_SOCK_OPT_NODELAY 0x0004 +#define SIM_SOCK_OPT_BLOCKING 0x0008 +SOCKET sim_master_sock_ex(const char *hostport, int *parse_status, int opt_flags); + +#define sim_master_sock(hostport, parse_status) sim_master_sock_ex(hostport, parse_status, ((sim_switches & SWMASK('U')) ? SIM_SOCK_OPT_REUSEADDR : 0)) +SOCKET sim_connect_sock_ex(const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, int opt_flags); + #define sim_connect_sock(hostport, default_host, default_port) sim_connect_sock_ex(NULL, hostport, default_host, default_port, SIM_SOCK_OPT_BLOCKING) -SOCKET sim_accept_conn_ex (SOCKET master, char **connectaddr, int opt_flags); +SOCKET sim_accept_conn_ex(SOCKET master, char **connectaddr, int opt_flags); + #define sim_accept_conn(master, connectaddr) sim_accept_conn_ex(master, connectaddr, 0) -int sim_check_conn (SOCKET sock, int rd); -int sim_read_sock (SOCKET sock, char *buf, int nbytes); -int sim_write_sock (SOCKET sock, const char *msg, int nbytes); -void sim_close_sock (SOCKET sock); -const char *sim_get_err_sock (const char *emsg); -SOCKET sim_err_sock (SOCKET sock, const char *emsg); -int sim_getnames_sock (SOCKET sock, char **socknamebuf, char **peernamebuf); -void sim_init_sock (void); -void sim_cleanup_sock (void); + +int sim_check_conn(SOCKET sock, int rd); +int sim_read_sock(SOCKET sock, char *buf, int nbytes); +int sim_write_sock(SOCKET sock, const char *msg, int nbytes); +void sim_close_sock(SOCKET sock); +const char *sim_get_err_sock(const char *emsg); +SOCKET sim_err_sock(SOCKET sock, const char *emsg); +int sim_getnames_sock(SOCKET sock, char **socknamebuf, char **peernamebuf); +void sim_init_sock(void); +void sim_cleanup_sock(void); #ifdef __cplusplus } diff --git a/slirp/CMakeLists.txt b/slirp/CMakeLists.txt deleted file mode 100644 index 4875471cf..000000000 --- a/slirp/CMakeLists.txt +++ /dev/null @@ -1,56 +0,0 @@ -## Compile SLirp as its own standalone library - -if (WITH_NETWORK) - set(SLIRP_SOURCES - "${CMAKE_SOURCE_DIR}/slirp/arp_table.c" - "${CMAKE_SOURCE_DIR}/slirp/bootp.c" - "${CMAKE_SOURCE_DIR}/slirp/bootp.h" - "${CMAKE_SOURCE_DIR}/slirp/cksum.c" - "${CMAKE_SOURCE_DIR}/slirp/dnssearch.c" - "${CMAKE_SOURCE_DIR}/slirp/if.c" - "${CMAKE_SOURCE_DIR}/slirp/ip_icmp.c" - "${CMAKE_SOURCE_DIR}/slirp/ip_input.c" - "${CMAKE_SOURCE_DIR}/slirp/ip_output.c" - "${CMAKE_SOURCE_DIR}/slirp/mbuf.c" - "${CMAKE_SOURCE_DIR}/slirp/misc.c" - "${CMAKE_SOURCE_DIR}/slirp/sbuf.c" - "${CMAKE_SOURCE_DIR}/slirp/slirp.c" - "${CMAKE_SOURCE_DIR}/slirp/socket.c" - "${CMAKE_SOURCE_DIR}/slirp/tcp_input.c" - "${CMAKE_SOURCE_DIR}/slirp/tcp_output.c" - "${CMAKE_SOURCE_DIR}/slirp/tcp_subr.c" - "${CMAKE_SOURCE_DIR}/slirp/tcp_timer.c" - "${CMAKE_SOURCE_DIR}/slirp/tftp.c" - "${CMAKE_SOURCE_DIR}/slirp/udp.c" - "${CMAKE_SOURCE_DIR}/slirp_glue/glib_qemu_stubs.c" - "${CMAKE_SOURCE_DIR}/slirp_glue/sim_slirp.c") - - add_library(slirp STATIC "${SLIRP_SOURCES}") - target_compile_definitions(slirp - PRIVATE - HAVE_SLIRP_NETWORK - USE_SIMH_SLIRP_DEBUG - $<$,$>>: - _WINSOCK_DEPRECATED_NO_WARNINGS - _CRT_NONSTDC_NO_WARNINGS - _CRT_SECURE_NO_WARNINGS> - INTERFACE - HAVE_SLIRP_NETWORK - USE_SIMH_SLIRP_DEBUG) - - target_include_directories(slirp - PRIVATE - "${CMAKE_SOURCE_DIR}" - "${CMAKE_SOURCE_DIR}/slirp" - "${CMAKE_SOURCE_DIR}/slirp_glue/qemu" - PUBLIC - "${CMAKE_SOURCE_DIR}/slirp_glue" - $<$:${CMAKE_SOURCE_DIR}/slirp_glue/qemu/win32/include>) - - target_compile_options(slirp PRIVATE ${EXTRA_TARGET_CFLAGS}) - target_link_options(slirp PRIVATE ${EXTRA_TARGET_LFLAGS}) - target_link_libraries(slirp PUBLIC $<$:Iphlpapi>) -else (WITH_NETWORK) - # Otherwise, just make slirp an empty interface library. - add_library(slirp INTERFACE) -endif (WITH_NETWORK) diff --git a/slirp/COPYRIGHT b/slirp/COPYRIGHT deleted file mode 100644 index 3927a5b5f..000000000 --- a/slirp/COPYRIGHT +++ /dev/null @@ -1,61 +0,0 @@ -Slirp was written by Danny Gasparovski. -Copyright (c), 1995,1996 All Rights Reserved. - -Slirp is maintained by Kelly Price - -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. - - 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.objs b/slirp/Makefile.objs deleted file mode 100644 index f9d40e3bb..000000000 --- a/slirp/Makefile.objs +++ /dev/null @@ -1,3 +0,0 @@ -common-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o dnssearch.o -common-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o -common-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o diff --git a/slirp/README b/slirp/README deleted file mode 100644 index 23be7e44a..000000000 --- a/slirp/README +++ /dev/null @@ -1,14 +0,0 @@ -October 6, 2015 - -This version of slirp is a fork from QEMU Version 2.4.0.1 slirp implementation -Taken from commit 83c92b45140be773f0c5545dddea35a89db1ad03 -in the qemu repository git://git.qemu.orgu/qemu.git - -The goal being to absolutely mininize changes from the base qemu provided code -so that the more active changes being done by the qemu folks can easily be -adopted in the future by directly replacing the revised modules. This is -achieved by careful manipulation of the include files provided in the -../slirp_glue directory so that things are stubbed out locally and the minimal -capabilities needed for sim_ether integration are provided. - -Thanks to Fabrice Bellard. diff --git a/slirp/arp_table.c b/slirp/arp_table.c deleted file mode 100644 index e7a18e937..000000000 --- a/slirp/arp_table.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * ARP table - * - * Copyright (c) 2011 AdaCore - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "slirp.h" - -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 = 0x%x", ip_addr); - DEBUG_ARGS(" hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n", - 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 = 0x%x", ip_addr); - - /* If broadcast address */ - if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) { - /* return Ethernet broadcast address */ - memset(out_ethaddr, 0xff, ETH_ALEN); - return 1; - } - - for (i = 0; i < ARP_TABLE_SIZE; i++) { - if (arptbl->table[i].ar_sip == ip_addr) { - memcpy(out_ethaddr, arptbl->table[i].ar_sha, ETH_ALEN); - DEBUG_ARGS(" found hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n", - out_ethaddr[0], out_ethaddr[1], out_ethaddr[2], - out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]); - return 1; - } - } - - return 0; -} diff --git a/slirp/bootp.c b/slirp/bootp.c deleted file mode 100644 index cb3279e1c..000000000 --- a/slirp/bootp.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * QEMU BOOTP/DHCP server - * - * Copyright (c) 2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include - -/* XXX: only DHCP is supported */ - -#define LEASE_TIME (24 * 3600) - -static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE }; - -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++; - 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 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=%08x\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)); - daddr.sin_addr.s_addr = 0xffffffffu; - - 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; - memcpy(q, rfc1533_cookie, 4); - q += 4; - - if (bc) { - DPRINTF("%s addr=%08x\n", - (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed", - ntohl(daddr.sin_addr.s_addr)); - - if (dhcp_msg_type == DHCPDISCOVER) { - *q++ = RFC2132_MSG_TYPE; - *q++ = 1; - *q++ = DHCPOFFER; - } else /* DHCPREQUEST */ { - *q++ = RFC2132_MSG_TYPE; - *q++ = 1; - *q++ = DHCPACK; - } - - if (slirp->bootp_filename) - snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s", - slirp->bootp_filename); - - *q++ = RFC2132_SRV_ID; - *q++ = 4; - memcpy(q, &saddr.sin_addr, 4); - q += 4; - - *q++ = RFC1533_NETMASK; - *q++ = 4; - memcpy(q, &slirp->vnetwork_mask, 4); - q += 4; - - if (!slirp->restricted) { - *q++ = RFC1533_GATEWAY; - *q++ = 4; - memcpy(q, &saddr.sin_addr, 4); - q += 4; - - *q++ = RFC1533_DNS; - *q++ = 4; - memcpy(q, &slirp->vnameserver_addr, 4); - q += 4; - } - - *q++ = RFC2132_LEASE_TIME; - *q++ = 4; - val = htonl(LEASE_TIME); - memcpy(q, &val, 4); - q += 4; - - if (*slirp->client_hostname) { - val = strlen(slirp->client_hostname); - *q++ = RFC1533_HOSTNAME; - *q++ = val; - memcpy(q, slirp->client_hostname, val); - q += val; - } - - if (slirp->vdnssearch) { - size_t spaceleft = sizeof(rbp->bp_vend) - (q - rbp->bp_vend); - val = slirp->vdnssearch_len; - if ((size_t)val + 1 > spaceleft) { - 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=%08x\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; - } - *q = RFC1533_END; - - m->m_len = sizeof(struct bootp_t) - - sizeof(struct ip) - sizeof(struct udphdr); - udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); -} - -void bootp_input(struct mbuf *m) -{ - struct bootp_t *bp = mtod(m, struct bootp_t *); - - if (bp->bp_op == BOOTP_REQUEST) { - bootp_reply(m->slirp, bp); - } -} diff --git a/slirp/bootp.h b/slirp/bootp.h deleted file mode 100644 index ece1a3035..000000000 --- a/slirp/bootp.h +++ /dev/null @@ -1,126 +0,0 @@ -/* bootp/dhcp defines */ -#ifndef SLIRP_BOOTP_H -#define SLIRP_BOOTP_H 1 - -#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 DHCPDISCOVER 1 -#define DHCPOFFER 2 -#define DHCPREQUEST 3 -#define DHCPACK 5 -#define DHCPNAK 6 - -#define RFC1533_VENDOR_MAJOR 0 -#define RFC1533_VENDOR_MINOR 0 - -#define RFC1533_VENDOR_MAGIC 128 -#define RFC1533_VENDOR_ADDPARM 129 -#define RFC1533_VENDOR_ETHDEV 130 -#define RFC1533_VENDOR_HOWTO 132 -#define RFC1533_VENDOR_MNUOPTS 160 -#define RFC1533_VENDOR_SELECTION 176 -#define RFC1533_VENDOR_MOTD 184 -#define RFC1533_VENDOR_NUMOFMOTD 8 -#define RFC1533_VENDOR_IMG 192 -#define RFC1533_VENDOR_NUMOFIMG 16 - -#define RFC1533_END 255 -#define BOOTP_VENDOR_LEN 64 -#define DHCP_OPT_LEN 312 - -struct bootp_t { - struct ip ip; - struct udphdr udp; - uint8_t bp_op; - uint8_t bp_htype; - uint8_t bp_hlen; - uint8_t bp_hops; - uint32_t bp_xid; - uint16_t bp_secs; - uint16_t unused; - struct in_addr bp_ciaddr; - struct in_addr bp_yiaddr; - struct in_addr bp_siaddr; - struct in_addr bp_giaddr; - uint8_t bp_hwaddr[16]; - uint8_t bp_sname[64]; - uint8_t bp_file[128]; - uint8_t bp_vend[DHCP_OPT_LEN]; -}; - -typedef struct { - uint16_t allocated; - uint8_t macaddr[6]; -} BOOTPClient; - -#define NB_BOOTP_CLIENTS 16 - -void bootp_input(struct mbuf *m); - -#endif diff --git a/slirp/cksum.c b/slirp/cksum.c deleted file mode 100644 index a95ac9403..000000000 --- a/slirp/cksum.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 1988, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 - * in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp - */ - -#include - -/* - * 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; -#ifdef DEBUG - len -= mlen; -#endif - /* - * 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: -#ifdef DEBUG - if (len) { - DEBUG_ERROR("cksum: out of data\n"); - DEBUG_ERROR(" len = %d\n", len); - } -#endif - 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); -} diff --git a/slirp/debug.h b/slirp/debug.h deleted file mode 100644 index aba02476c..000000000 --- a/slirp/debug.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef SLIRP_DEBUG_H -#define SLIRP_DEBUG_H - -/* - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#define DBG_CALL 0x1 -#define DBG_MISC 0x2 -#define DBG_ERROR 0x4 - -extern int slirp_debug; - -#ifndef USE_SIMH_SLIRP_DEBUG /* simh build indicator */ - -#ifdef DEBUG - -#define dfd stderr - -#define DEBUG_CALL(x) do {if (slirp_debug & DBG_CALL) { fprintf (dfd, "%s...\n", x); fflush(dfd); };} while (0) -#define DEBUG_ARG(x, y) do {if (slirp_debug & DBG_CALL) { fprintf (dfd, x, y); _sim_debug_device (slirp_dbit, slirp_dptr, "\n"); fflush(dfd); };} while (0) -#define DEBUG_ARGS(...) do {if (slirp_debug & DBG_CALL) { fprintf (dfd, ## __VA_ARGS__); fflush(dfd); };} while (0) -#define DEBUG_MISC(...) do {if (slirp_debug & DBG_MISC) { fprintf (dfd, ## __VA_ARGS__); fflush(dfd); };} while (0) -#define DEBUG_ERROR(...) do {if (slirp_debug & DBG_ERROR) { fprintf (dfd, ## __VA_ARGS__); fflush(dfd); };} while (0) -#define DPRINTF(fmt, ...) do {if (slirp_debug & DBG_CALL) { fprintf (dfd, fmt, ## __VA_ARGS__); fflush(dfd);} while (0) - -#else - -#define DEBUG_CALL(x) do {} while (0) -#define DEBUG_ARG(x, y) do {} while (0) -#define DEBUG_ARGS(...) do {} while (0) -#define DEBUG_MISC(...) do {} while (0) -#define DEBUG_ERROR(...) do {} while (0) -#define DPRINTF(fmt, ...) do {} while (0) - -#endif - -#else /* defined(USE_SIMH_SLIRP_DEBUG) */ - -#include -#define DEVICE void - -#if defined(__cplusplus) -extern "C" { -#endif -extern void *slirp_dptr; -extern unsigned int slirp_dbit; - -extern void _sim_debug_device (unsigned int dbits, DEVICE* dptr, const char* fmt, ...); - -#define DEBUG_CALL(x) do {if (slirp_debug & DBG_CALL) { _sim_debug_device (slirp_dbit, slirp_dptr, "%s...\n", x); };} while (0) -#define DEBUG_ARG(x, y) do {if (slirp_debug & DBG_CALL) {_sim_debug_device (slirp_dbit, slirp_dptr, x, y); _sim_debug_device (slirp_dbit, slirp_dptr, "\n"); };} while (0) -#define DEBUG_ARGS(...) do {if (slirp_debug & DBG_CALL) { _sim_debug_device (slirp_dbit, slirp_dptr, ## __VA_ARGS__); };} while (0) -#define DEBUG_MISC(...) do {if (slirp_debug & DBG_MISC) { _sim_debug_device (slirp_dbit, slirp_dptr, ## __VA_ARGS__); };} while (0) -#define DEBUG_ERROR(...) do {if (slirp_debug & DBG_ERROR) { _sim_debug_device (slirp_dbit, slirp_dptr, ## __VA_ARGS__); };} while (0) -#define DPRINTF(fmt, ...) do {if (slirp_debug & DBG_CALL) { _sim_debug_device (slirp_dbit, slirp_dptr, fmt, ## __VA_ARGS__); };} while (0) - -#if defined(__cplusplus) -} -#endif - -#endif - -#endif diff --git a/slirp/dnssearch.c b/slirp/dnssearch.c deleted file mode 100644 index 71d2f3827..000000000 --- a/slirp/dnssearch.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Domain search option for DHCP (RFC 3397) - * - * Copyright (c) 2012 Klaus Stengel - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include -#include -#include -#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 = (const CompactDomain *)cva, *b = (const CompactDomain *)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 = (uint8_t)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] = (uint8_t)(0xC0u | (moff >> 8)); - } - } - - if (cd->labels != outptr) { - memmove(outptr, cd->labels, cd->len); - cd->labels = outptr; - } - outptr += cd->len; - } - return outptr - start; -} - -int translate_dnssearch(Slirp *s, const char **names) -{ - size_t blocks, bsrc_start, bsrc_end, bdst_start; - size_t i, num_domains, memreq = 0; - uint8_t *result = NULL, *outptr; - CompactDomain *domains = NULL; - const char **nameptr = names; - - while (*nameptr != NULL) { - nameptr++; - } - - num_domains = nameptr - names; - if (num_domains == 0) { - return -2; - } - - domains = (CompactDomain *)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 += ((memreq + MAX_OPT_LEN - 1) / MAX_OPT_LEN) * OPT_HEADER_LEN; - result = (uint8_t *)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 = (memreq + MAX_OPT_LEN - 1) / 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] = (uint8_t)len; - bsrc_end = bsrc_start; - bsrc_start -= MAX_OPT_LEN; - bdst_start -= MAX_OPT_LEN + OPT_HEADER_LEN; - } - - g_free(domains); - s->vdnssearch = result; - s->vdnssearch_len = memreq; - return 0; -} diff --git a/slirp/if.c b/slirp/if.c deleted file mode 100644 index a7ecd8997..000000000 --- a/slirp/if.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#include -#include "qemu/timer.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.ifq_next = slirp->if_fastq.ifq_prev = &slirp->if_fastq; - slirp->if_batchq.ifq_next = slirp->if_batchq.ifq_prev = &slirp->if_batchq; - slirp->next_m = &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 = %lx", (long)so); - DEBUG_ARG("ifm = %lx", (long)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? - */ - for (ifq = slirp->if_batchq.ifq_prev; ifq && 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 = slirp->if_fastq.ifq_prev; - 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 = slirp->if_batchq.ifq_prev; - /* Set next_m if the queue was empty so far */ - if (slirp->next_m == &slirp->if_batchq) { - slirp->next_m = ifm; - } - } - - /* 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); - } - } - -#ifndef FULL_BOLT - /* - * This prevents us from malloc()ing too many mbufs - */ - if_start(ifm->slirp); -#endif -} - -/* - * Send a packet - * We choose a packet based on its position in the output queues; - * If there are packets on the fastq, they are sent FIFO, before - * everything else. Otherwise we choose the first packet from the - * batchq and send it. the next packet chosen will be from the session - * after this one, then the session after that one, and so on.. So, - * for example, if there are 3 ftp session's 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, then back - * to the first, etc. etc. - */ -void if_start(Slirp *slirp) -{ - uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); - bool from_batchq, next_from_batchq; - struct mbuf *ifm, *ifm_next, *ifqt; - - DEBUG_CALL("if_start"); - - if (slirp->if_start_busy) { - return; - } - slirp->if_start_busy = true; - - if (slirp->if_fastq.ifq_next != &slirp->if_fastq) { - ifm_next = slirp->if_fastq.ifq_next; - next_from_batchq = false; - } else if (slirp->next_m != &slirp->if_batchq) { - /* Nothing on fastq, pick up from batchq via next_m */ - ifm_next = slirp->next_m; - next_from_batchq = true; - } else { - ifm_next = NULL; - } - - while (ifm_next) { - ifm = ifm_next; - from_batchq = next_from_batchq; - - ifm_next = ifm->ifq_next; - if (ifm_next == &slirp->if_fastq) { - /* No more packets in fastq, switch to batchq */ - ifm_next = slirp->next_m; - next_from_batchq = true; - } - if (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 resolution */ - continue; - } - - if (ifm == slirp->next_m) { - /* Set which packet to send on next iteration */ - slirp->next_m = ifm->ifq_next; - } - - /* 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) { - /* Next packet in fastq is from the same session */ - ifm_next = next; - next_from_batchq = false; - } else if (slirp->next_m == &slirp->if_batchq) { - /* Set next_m and ifm_next if the session packet is now the - * only one on batchq */ - slirp->next_m = ifm_next = next; - } - } - - /* Update so_queued */ - if (ifm->ifq_so && --ifm->ifq_so->so_queued == 0) { - /* If there's no more queued, reset nqueued */ - ifm->ifq_so->so_nqueued = 0; - } - - m_free(ifm); - } - - slirp->if_start_busy = false; -} diff --git a/slirp/if.h b/slirp/if.h deleted file mode 100644 index d46cd23a0..000000000 --- a/slirp/if.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#ifndef _IF_H_ -#define _IF_H_ - -#define IF_COMPRESS 0x01 /* We want compression */ -#define IF_NOCOMPRESS 0x02 /* Do not do compression */ -#define IF_AUTOCOMP 0x04 /* Autodetect (default) */ -#define IF_NOCIDCOMP 0x08 /* CID compression */ - -#define IF_MTU 1500 -#define IF_MRU 1500 -#define IF_COMP IF_AUTOCOMP /* Flags for compression */ - -/* 2 for alignment, 14 for ethernet, 40 for TCP/IP */ -#define IF_MAXLINKHDR (2 + 14 + 40) - -#endif diff --git a/slirp/ip.h b/slirp/ip.h deleted file mode 100644 index 0edcd361b..000000000 --- a/slirp/ip.h +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ip.h 8.1 (Berkeley) 6/10/93 - * ip.h,v 1.3 1994/08/21 05:27:30 paul Exp - */ - -#ifndef _IP_H_ -#define _IP_H_ - -#ifdef HOST_WORDS_BIGENDIAN -# 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 */ - -#ifdef _MSC_VER -# define PACKED_BEGIN __pragma( pack(push, 1) ) -# define PACKED_END __pragma( pack(pop) ) -#else -# define PACKED_BEGIN -#if defined(_WIN32) -# define PACKED_END __attribute__((gcc_struct, packed)) -#else -# define PACKED_END __attribute__((packed)) -#endif -#endif - -/* - * Definitions for internet protocol version 4. - * Per RFC 791, September 1981. - */ -#define IPVERSION 4 - -/* - * Structure of an internet header, naked of options. - */ -PACKED_BEGIN -struct ip { -#ifdef HOST_WORDS_BIGENDIAN - 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 */ -} PACKED_END; - -#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. - */ -PACKED_BEGIN -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 */ -#ifdef HOST_WORDS_BIGENDIAN - 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; -} PACKED_END; - -/* 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 */ - -PACKED_BEGIN -#if SIZEOF_CHAR_P == 4 -struct mbuf_ptr { - struct mbuf *mptr; - uint32_t dummy; -} PACKED_END; -#else -struct mbuf_ptr { - struct mbuf *mptr; -} PACKED_END; -#endif - -struct qlink { - void *next, *prev; -}; - -/* - * Overlay for ip header used by other protocols (tcp, udp). - */ -PACKED_BEGIN -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 */ -} PACKED_END; - -/* - * 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 - */ -PACKED_BEGIN -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; -} PACKED_END; - -/* - * Ip header, when holding a fragment. - * - * Note: ipf_link must be at same offset as frag_link above - */ -PACKED_BEGIN -struct ipasfrag { - struct qlink ipf_link; - struct ip ipf_ip; -} PACKED_END; - -#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 - -/* - * Structure stored in mbuf in inpcb.ip_options - * and passed to ip_output when ip options are in use. - * The actual length of the options (including ipopt_dst) - * is in m_len. - */ -#define MAX_IPOPTLEN 40 - -PACKED_BEGIN -struct ipoption { - struct in_addr ipopt_dst; /* first-hop dst if source routed */ - int8_t ipopt_list[MAX_IPOPTLEN]; /* options proper */ -} PACKED_END; - -#endif diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c deleted file mode 100644 index be350e24b..000000000 --- a/slirp/ip_icmp.c +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 - * ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp - */ - -#include "slirp.h" -#include "ip_icmp.h" - -/* 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_error() on RX of an icmp message */ -static const int icmp_flush[19] = { -/* ECHO REPLY (0) */ 0, - 1, - 1, -/* DEST UNREACH (3) */ 1, -/* SOURCE QUENCH (4)*/ 1, -/* REDIRECT (5) */ 1, - 1, - 1, -/* ECHO (8) */ 0, -/* ROUTERADVERT (9) */ 1, -/* ROUTERSOLICIT (10) */ 1, -/* TIME EXCEEDED (11) */ 1, -/* PARAMETER PROBLEM (12) */ 1, -/* TIMESTAMP (13) */ 0, -/* TIMESTAMP REPLY (14) */ 0, -/* INFO (15) */ 0, -/* INFO REPLY (16) */ 0, -/* ADDR MASK (17) */ 0, -/* ADDR MASK REPLY (18) */ 0 -}; - -void icmp_init(Slirp *slirp) -{ - slirp->icmp.so_next = slirp->icmp.so_prev = &slirp->icmp; - slirp->icmp_last_so = &slirp->icmp; -} - -void icmp_cleanup(Slirp *slirp) -{ - while (slirp->icmp.so_next != &slirp->icmp) { - icmp_detach(slirp->icmp.so_next); - } -} - -static int icmp_send(struct socket *so, struct mbuf *m, int hlen) -{ - struct ip *ip = mtod(m, struct ip *); - struct sockaddr_in addr; - - so->s = qemu_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); - if (so->s == -1) { - return -1; - } - - so->so_m = m; - so->so_faddr = ip->ip_dst; - so->so_laddr = ip->ip_src; - so->so_iptos = ip->ip_tos; - so->so_type = IPPROTO_ICMP; - so->so_state = SS_ISFCONNECTED; - so->so_expire = curtime + SO_EXPIRE; - - addr.sin_family = AF_INET; - addr.sin_addr = so->so_faddr; - - insque(so, &so->slirp->icmp); - - if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0, - (struct sockaddr *)&addr, sizeof(addr)) == -1) { - DEBUG_MISC("icmp_input icmp sendto tx errno = %d-%s\n", - errno, strerror(errno)); - icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno)); - icmp_detach(so); - } - - return 0; -} - -void icmp_detach(struct socket *so) -{ - 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 = %lx", (long )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) { - icmp_reflect(m); - } else if (slirp->restricted) { - goto freeit; - } else { - struct socket *so; - struct sockaddr_in addr; - if ((so = socreate(slirp)) == NULL) goto freeit; - if (icmp_send(so, m, hlen) == 0) { - return; - } - if(udp_attach(so) == -1) { - DEBUG_MISC("icmp_input udp_attach errno = %d-%s\n", - errno,strerror(errno)); - sofree(so); - m_free(m); - goto end_error; - } - so->so_m = m; - so->so_faddr = ip->ip_dst; - so->so_fport = htons(7); - 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.sin_family = AF_INET; - if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == - slirp->vnetwork_addr.s_addr) { - /* It's an alias */ - if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) { - if (get_dns_addr(&addr.sin_addr) < 0) - addr.sin_addr = loopback_addr; - } else { - addr.sin_addr = loopback_addr; - } - } else { - addr.sin_addr = so->so_faddr; - } - addr.sin_port = so->so_fport; - if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0, - (struct sockaddr *)&addr, sizeof(addr)) == -1) { - DEBUG_MISC("icmp_input udp sendto tx errno = %d-%s\n", - errno,strerror(errno)); - icmp_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_error(struct mbuf *msrc, u_char type, u_char 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_error"); - DEBUG_ARG("msrc = %lx", (long )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 *); -#ifdef DEBUG - { char bufa[20], bufb[20]; - strcpy(bufa, inet_ntoa(ip->ip_src)); - strcpy(bufb, inet_ntoa(ip->ip_dst)); - DEBUG_MISC(" %.16s to %.16s\n", bufa, bufb); - } -#endif - 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); - -#ifdef DEBUG - if(message) { /* DEBUG : 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; - } -#endif - - 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((caddr_t)(ip + 1), (caddr_t)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; - u_char 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 = qemu_recv(so->s, icp, m->m_len, 0); - 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\n", errno, - strerror(errno)); - icmp_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno)); - } else { - icmp_reflect(so->so_m); - so->so_m = NULL; /* Don't m_free() it again! */ - } - icmp_detach(so); -} diff --git a/slirp/ip_icmp.h b/slirp/ip_icmp.h deleted file mode 100644 index 36fefa4b0..000000000 --- a/slirp/ip_icmp.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 - * ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp - */ - -#ifndef _NETINET_IP_ICMP_H_ -#define _NETINET_IP_ICMP_H_ - -/* - * Interface Control Message Protocol Definitions. - * Per RFC 792, September 1981. - */ - -typedef uint32_t n_time; - -/* - * Structure of an icmp header. - */ -struct icmp { - u_char icmp_type; /* type of message, see below */ - u_char icmp_code; /* type sub code */ - u_short icmp_cksum; /* ones complement cksum of struct */ - union { - u_char ih_pptr; /* ICMP_PARAMPROB */ - struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ - struct ih_idseq { - u_short icd_id; - u_short icd_seq; - } ih_idseq; - int ih_void; - - /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ - struct ih_pmtu { - u_short ipm_void; - u_short 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_error(struct mbuf *msrc, u_char type, u_char code, int minsize, - const char *message); -void icmp_reflect(struct mbuf *); -void icmp_receive(struct socket *so); -void icmp_detach(struct socket *so); - -#endif diff --git a/slirp/ip_input.c b/slirp/ip_input.c deleted file mode 100644 index bfce10dce..000000000 --- a/slirp/ip_input.c +++ /dev/null @@ -1,668 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 - * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp - */ - -/* - * Changes and additions relating to SLiRP are - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#include -#include -#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; - - DEBUG_CALL("ip_input"); - DEBUG_ARG("m = %lx", (long)m); - DEBUG_ARG("m_len = %d", m->m_len); - - if (m->m_len < sizeof (struct ip)) { - return; - } - - ip = mtod(m, struct ip *); - - if (ip->ip_v != IPVERSION) { - goto bad; - } - - hlen = ip->ip_hl << 2; - if (hlenm->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_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 = (struct qlink *)slirp->ipq.ip_link.next; l != &slirp->ipq.ip_link; - l = (struct qlink *)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); - 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 = %lx", (long)ip); - DEBUG_ARG("fp = %lx", (long)fp); - DEBUG_ARG("m = %lx", (long)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 = (struct ipasfrag *)fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link; - q = (struct ipasfrag *)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 = (struct ipasfrag *)q->ipf_prev; - i = pq->ipf_off + pq->ipf_len - ip->ip_off; - if (i > 0) { - if (i >= ip->ip_len) - goto dropfrag; - m_adj(dtom(slirp, ip), i); - ip->ip_off += i; - ip->ip_len -= i; - } - } - - /* - * While we overlap succeeding segments trim them or, - * if they are completely covered, dequeue them. - */ - while (q != (struct ipasfrag*)&fp->frag_link && - ip->ip_off + ip->ip_len > q->ipf_off) { - i = (ip->ip_off + ip->ip_len) - q->ipf_off; - if (i < q->ipf_len) { - q->ipf_len -= i; - q->ipf_off += i; - m_adj(dtom(slirp, q), i); - break; - } - q = (struct ipasfrag *)q->ipf_next; - m_free(dtom(slirp, q->ipf_prev)); - ip_deq((struct ipasfrag*)q->ipf_prev); - } - -insert: - /* - * Stick new segment in its place; - * check for complete reassembly. - */ - ip_enq(iptofrag(ip), (struct ipasfrag*)q->ipf_prev); - next = 0; - for (q = (struct ipasfrag*)fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link; - q = (struct ipasfrag*)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 = (struct ipasfrag*)fp->frag_link.next; - m = dtom(slirp, q); - - q = (struct ipasfrag *) q->ipf_next; - while (q != (struct ipasfrag*)&fp->frag_link) { - struct mbuf *t = dtom(slirp, q); - q = (struct ipasfrag *) q->ipf_next; - m_cat(m, t); - } - - /* - * Create header for new ip packet by - * modifying header of first packet; - * dequeue and discard fragment reassembly header. - * Make header visible. - */ - q = (struct ipasfrag*)fp->frag_link.next; - - /* - * If the fragments concatenated to an mbuf that's - * bigger than the total size of the fragment, then and - * m_ext buffer was alloced. But fp->ipq_next points to - * the old buffer (in the mbuf), so we must point ip - * into the new buffer. - */ - if (m->m_flags & M_EXT) { - int delta = (char *)q - m->m_dat; - q = (struct ipasfrag *)(m->m_ext + delta); - } - - ip = fragtoip(q); - ip->ip_len = next; - ip->ip_tos &= ~1; - ip->ip_src = fp->ipq_src; - ip->ip_dst = fp->ipq_dst; - remque(&fp->ip_link); - (void) m_free(dtom(slirp, fp)); - m->m_len += (ip->ip_hl << 2); - m->m_data -= (ip->ip_hl << 2); - - return ip; - -dropfrag: - m_free(m); - return NULL; -} - -/* - * Free a fragment reassembly header and all - * associated datagrams. - */ -static void -ip_freef(Slirp *slirp, struct ipq *fp) -{ - register struct ipasfrag *q, *p; - - for (q = (struct ipasfrag*)fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link; q = p) { - p = (struct ipasfrag*)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 = %lx", (long)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 = (struct qlink*)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 = (struct qlink*)l->next; - if (--fp->ipq_ttl == 0) { - ip_freef(slirp, fp); - } - } -} - -/* - * Do option processing on a datagram, - * possibly discarding it if bad options are encountered, - * or forwarding it if source-routed. - * Returns 1 if packet has been forwarded/freed, - * 0 if the packet should be processed further. - */ - -#ifdef notdef - -int -ip_dooptions(m) - struct mbuf *m; -{ - register struct ip *ip = mtod(m, struct ip *); - register u_char *cp; - register struct ip_timestamp *ipt; - register struct in_ifaddr *ia; - int opt, optlen, cnt, off, code, type, forward = 0; - struct in_addr *sin, dst; -typedef uint32_t n_time; - n_time ntime; - - dst = ip->ip_dst; - cp = (u_char *)(ip + 1); - cnt = (ip->ip_hl << 2) - sizeof (struct ip); - for (; cnt > 0; cnt -= optlen, cp += optlen) { - opt = cp[IPOPT_OPTVAL]; - if (opt == IPOPT_EOL) - break; - if (opt == IPOPT_NOP) - optlen = 1; - else { - optlen = cp[IPOPT_OLEN]; - if (optlen <= 0 || optlen > cnt) { - code = &cp[IPOPT_OLEN] - (u_char *)ip; - goto bad; - } - } - switch (opt) { - - default: - break; - - /* - * Source routing with record. - * Find interface with current destination address. - * If none on this machine then drop if strictly routed, - * or do nothing if loosely routed. - * Record interface address and bring up next address - * component. If strictly routed make sure next - * address is on directly accessible net. - */ - case IPOPT_LSRR: - case IPOPT_SSRR: - if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { - code = &cp[IPOPT_OFFSET] - (u_char *)ip; - goto bad; - } - ipaddr.sin_addr = ip->ip_dst; - ia = (struct in_ifaddr *) - ifa_ifwithaddr((struct sockaddr *)&ipaddr); - if (ia == 0) { - if (opt == IPOPT_SSRR) { - type = ICMP_UNREACH; - code = ICMP_UNREACH_SRCFAIL; - goto bad; - } - /* - * Loose routing, and not at next destination - * yet; nothing to do except forward. - */ - break; - } - off--; /* 0 origin */ - if (off > optlen - sizeof(struct in_addr)) { - /* - * End of source route. Should be for us. - */ - save_rte(cp, ip->ip_src); - break; - } - /* - * locate outgoing interface - */ - bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr, - sizeof(ipaddr.sin_addr)); - if (opt == IPOPT_SSRR) { -#define INA struct in_ifaddr * -#define SA struct sockaddr * - if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) - ia = (INA)ifa_ifwithnet((SA)&ipaddr); - } else - ia = ip_rtaddr(ipaddr.sin_addr); - if (ia == 0) { - type = ICMP_UNREACH; - code = ICMP_UNREACH_SRCFAIL; - goto bad; - } - ip->ip_dst = ipaddr.sin_addr; - bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), - (caddr_t)(cp + off), sizeof(struct in_addr)); - cp[IPOPT_OFFSET] += sizeof(struct in_addr); - /* - * Let ip_intr's mcast routing check handle mcast pkts - */ - forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); - break; - - case IPOPT_RR: - if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { - code = &cp[IPOPT_OFFSET] - (u_char *)ip; - goto bad; - } - /* - * If no space remains, ignore. - */ - off--; /* 0 origin */ - if (off > optlen - sizeof(struct in_addr)) - break; - bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr, - sizeof(ipaddr.sin_addr)); - /* - * locate outgoing interface; if we're the destination, - * use the incoming interface (should be same). - */ - if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && - (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { - type = ICMP_UNREACH; - code = ICMP_UNREACH_HOST; - goto bad; - } - bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), - (caddr_t)(cp + off), sizeof(struct in_addr)); - cp[IPOPT_OFFSET] += sizeof(struct in_addr); - break; - - case IPOPT_TS: - code = cp - (u_char *)ip; - ipt = (struct ip_timestamp *)cp; - if (ipt->ipt_len < 5) - goto bad; - if (ipt->ipt_ptr > ipt->ipt_len - sizeof (int32_t)) { - if (++ipt->ipt_oflw == 0) - goto bad; - break; - } - sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); - switch (ipt->ipt_flg) { - - case IPOPT_TS_TSONLY: - break; - - case IPOPT_TS_TSANDADDR: - if (ipt->ipt_ptr + sizeof(n_time) + - sizeof(struct in_addr) > ipt->ipt_len) - goto bad; - ipaddr.sin_addr = dst; - ia = (INA)ifaof_ i f p foraddr((SA)&ipaddr, - m->m_pkthdr.rcvif); - if (ia == 0) - continue; - bcopy((caddr_t)&IA_SIN(ia)->sin_addr, - (caddr_t)sin, sizeof(struct in_addr)); - ipt->ipt_ptr += sizeof(struct in_addr); - break; - - case IPOPT_TS_PRESPEC: - if (ipt->ipt_ptr + sizeof(n_time) + - sizeof(struct in_addr) > ipt->ipt_len) - goto bad; - bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr, - sizeof(struct in_addr)); - if (ifa_ifwithaddr((SA)&ipaddr) == 0) - continue; - ipt->ipt_ptr += sizeof(struct in_addr); - break; - - default: - goto bad; - } - ntime = iptime(); - bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1, - sizeof(n_time)); - ipt->ipt_ptr += sizeof(n_time); - } - } - if (forward) { - ip_forward(m, 1); - return (1); - } - return (0); -bad: - icmp_error(m, type, code, 0, 0); - - return (1); -} - -#endif /* notdef */ - -/* - * 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 caddr_t opts; - int olen; - - olen = (ip->ip_hl<<2) - sizeof (struct ip); - opts = (caddr_t)(ip + 1); - i = m->m_len - (sizeof (struct ip) + olen); - memcpy(opts, opts + olen, (unsigned)i); - m->m_len -= olen; - - ip->ip_hl = sizeof(struct ip) >> 2; -} diff --git a/slirp/ip_output.c b/slirp/ip_output.c deleted file mode 100644 index b45eaef5d..000000000 --- a/slirp/ip_output.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1988, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 - * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp - */ - -/* - * Changes and additions relating to SLiRP are - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#include - -/* 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 = %lx", (long)so); - DEBUG_ARG("m0 = %lx", (long)m0); - - ip = mtod(m, struct ip *); - /* - * Fill in IP header. - */ - ip->ip_v = IPVERSION; - ip->ip_off &= IP_DF; - ip->ip_id = htons(slirp->ip_id++); - ip->ip_hl = hlen >> 2; - - /* - * If small enough for interface, can just send directly. - */ - if ((uint16_t)ip->ip_len <= IF_MTU) { - ip->ip_len = htons((uint16_t)ip->ip_len); - ip->ip_off = htons((uint16_t)ip->ip_off); - ip->ip_sum = 0; - ip->ip_sum = cksum(m, hlen); - - if_output(so, m); - goto done; - } - - /* - * Too large for interface; fragment if possible. - * Must be able to put at least 8 bytes per fragment. - */ - if (ip->ip_off & IP_DF) { - error = -1; - goto bad; - } - - len = (IF_MTU - hlen) &~ 7; /* ip databytes per packet */ - if (len < 8) { - error = -1; - goto bad; - } - - { - int mhlen, firstlen = len; - struct mbuf **mnext = &m->m_nextpkt; - - /* - * Loop through length of segment after first fragment, - * make new header and copy data of each part and link onto chain. - */ - m0 = m; - mhlen = sizeof (struct ip); - for (off = hlen + len; off < (uint16_t)ip->ip_len; off += len) { - register struct ip *mhip; - m = m_get(slirp); - if (m == NULL) { - error = -1; - goto sendorfree; - } - m->m_data += IF_MAXLINKHDR; - mhip = mtod(m, struct ip *); - *mhip = *ip; - - m->m_len = mhlen; - mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); - if (ip->ip_off & IP_MF) - mhip->ip_off |= IP_MF; - if (off + len >= (uint16_t)ip->ip_len) - len = (uint16_t)ip->ip_len - off; - else - mhip->ip_off |= IP_MF; - mhip->ip_len = htons((uint16_t)(len + mhlen)); - - if (m_copy(m, m0, off, len) < 0) { - error = -1; - goto sendorfree; - } - - mhip->ip_off = htons((uint16_t)mhip->ip_off); - mhip->ip_sum = 0; - mhip->ip_sum = cksum(m, mhlen); - *mnext = m; - mnext = &m->m_nextpkt; - } - /* - * Update first fragment by trimming what's been copied out - * and updating header, then send each fragment (in order). - */ - m = m0; - m_adj(m, hlen + firstlen - (uint16_t)ip->ip_len); - ip->ip_len = htons((uint16_t)m->m_len); - ip->ip_off = htons((uint16_t)(ip->ip_off | IP_MF)); - ip->ip_sum = 0; - ip->ip_sum = cksum(m, hlen); -sendorfree: - for (m = m0; m; m = m0) { - m0 = m->m_nextpkt; - m->m_nextpkt = NULL; - if (error == 0) - if_output(so, m); - else - m_free(m); - } - } - -done: - return (error); - -bad: - m_free(m0); - goto done; -} diff --git a/slirp/libslirp.h b/slirp/libslirp.h deleted file mode 100644 index 9f633eae4..000000000 --- a/slirp/libslirp.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef _LIBSLIRP_H -#define _LIBSLIRP_H - -#include "qemu-common.h" - -struct Slirp; -typedef struct Slirp Slirp; - -int get_dns_addr(struct in_addr *pdns_addr); - -Slirp *slirp_init(int restricted, struct in_addr vnetwork, - struct in_addr vnetmask, struct in_addr vhost, - const char *vhostname, const char *tftp_path, - const char *bootfile, struct in_addr vdhcp_start, - struct in_addr vnameserver, const char **vdnssearch, - void *opaque); -void slirp_cleanup(Slirp *slirp); - -void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout); - -void slirp_pollfds_poll(GArray *pollfds, int select_error); - -void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len); - -/* you must provide the following functions: */ -void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len); - -int slirp_add_hostfwd(Slirp *slirp, int is_udp, - struct in_addr host_addr, int host_port, - struct in_addr guest_addr, int guest_port); -int slirp_remove_hostfwd(Slirp *slirp, int is_udp, - struct in_addr host_addr, int host_port); -int slirp_add_exec(Slirp *slirp, int do_pty, const void *args, - struct in_addr *guest_addr, int guest_port); - -void slirp_connection_info(Slirp *slirp, Monitor *mon); - -void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, - int guest_port, const uint8_t *buf, int size); -size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr, - int guest_port); - -#endif diff --git a/slirp/main.h b/slirp/main.h deleted file mode 100644 index 209e2456c..000000000 --- a/slirp/main.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ -#ifndef SLIRP_MAIN_H -#define SLIRP_MAIN_H 1 - -#ifdef HAVE_SYS_SELECT_H -#include -#endif - -#define TOWRITEMAX 512 - -extern int slirp_socket; -extern int slirp_socket_unit; -extern int slirp_socket_port; -extern uint32_t slirp_socket_addr; -extern char *slirp_socket_passwd; -extern int ctty_closed; - -/* - * Get the difference in 2 times from updtim() - * Allow for wraparound times, "just in case" - * x is the greater of the 2 (current time) and y is - * what it's being compared against. - */ -#define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y) - -extern char *slirp_tty; -extern char *exec_shell; -extern u_int curtime; -extern struct in_addr loopback_addr; -extern unsigned long loopback_mask; -extern char *username; -extern char *socket_path; -extern int towrite_max; -extern int ppp_exit; -extern int tcp_keepintvl; - -#define PROTO_SLIP 0x1 -#ifdef USE_PPP -#define PROTO_PPP 0x2 -#endif - -int if_encap(Slirp *slirp, struct mbuf *ifm); -ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags); - -#endif diff --git a/slirp/mbuf.c b/slirp/mbuf.c deleted file mode 100644 index b471067da..000000000 --- a/slirp/mbuf.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -/* - * mbuf's in SLiRP are much simpler than the real mbufs in - * FreeBSD. They are fixed size, determined by the MTU, - * so that one whole packet can fit. Mbuf's cannot be - * chained together. If there's more data than the mbuf - * could hold, an external malloced buffer is pointed to - * by m_ext (and the data pointers) and M_EXT is set in - * the flags - */ - -#include - -#define MBUF_THRESH 30 - -/* - * Find a nice value for msize - * XXX if_maxlinkhdr already in mtu - */ -#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + offsetof(struct mbuf, m_dat) + 6) - -void -m_init(Slirp *slirp) -{ - slirp->m_freelist.m_next = slirp->m_freelist.m_prev = &slirp->m_freelist; - slirp->m_usedlist.m_next = slirp->m_usedlist.m_prev = &slirp->m_usedlist; -} - -void m_cleanup(Slirp *slirp) -{ - struct mbuf *m, *next; - - m = slirp->m_usedlist.m_next; - while (m != &slirp->m_usedlist) { - next = m->m_next; - if (m->m_flags & M_EXT) { - free(m->m_ext); - } - free(m); - m = next; - } - m = slirp->m_freelist.m_next; - while (m != &slirp->m_freelist) { - next = m->m_next; - free(m); - m = next; - } -} - -/* - * Get an mbuf from the free list, if there are none - * malloc 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 free() it - */ -struct mbuf * -m_get(Slirp *slirp) -{ - register struct mbuf *m; - int flags = 0; - - DEBUG_CALL("m_get"); - - if (slirp->m_freelist.m_next == &slirp->m_freelist) { - m = (struct mbuf *)malloc(SLIRP_MSIZE); - if (m == NULL) goto end_error; - slirp->mbuf_alloced++; - if (slirp->mbuf_alloced > MBUF_THRESH) - flags = M_DOFREE; - m->slirp = slirp; - } else { - m = slirp->m_freelist.m_next; - remque(m); - } - - /* Insert it in the used list */ - insque(m,&slirp->m_usedlist); - m->m_flags = (flags | M_USEDLIST); - - /* Initialise it */ - m->m_size = SLIRP_MSIZE - offsetof(struct mbuf, m_dat); - m->m_data = m->m_dat; - m->m_len = 0; - m->m_nextpkt = NULL; - m->m_prevpkt = NULL; - m->arp_requested = false; - m->expiration_date = (uint64_t)-1; -end_error: - DEBUG_ARG("m = %lx", (long )m); - return m; -} - -void -m_free(struct mbuf *m) -{ - - DEBUG_CALL("m_free"); - DEBUG_ARG("m = %lx", (long )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) - free(m->m_ext); - - /* - * Either free() it or put it on the free list - */ - if (m->m_flags & M_DOFREE) { - m->slirp->mbuf_alloced--; - 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, malloc() - * 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_size+MINCSIZE); - - 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 */ -void -m_inc(struct mbuf *m, int size) -{ - int datasize; - - /* some compiles throw up on gotos. This one we can fake. */ - if(m->m_size>size) return; - - if (m->m_flags & M_EXT) { - datasize = m->m_data - m->m_ext; - m->m_ext = (char *)realloc(m->m_ext,size); - m->m_data = m->m_ext + datasize; - } else { - char *dat; - datasize = m->m_data - m->m_dat; - dat = (char *)malloc(size); - memcpy(dat, m->m_dat, m->m_size); - - m->m_ext = dat; - m->m_data = m->m_ext + datasize; - m->m_flags |= M_EXT; - } - - m->m_size = size; - -} - - - -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 = %lx", (long )dat); - - /* bug corrected for M_EXT buffers */ - for (m = slirp->m_usedlist.m_next; m != &slirp->m_usedlist; - m = m->m_next) { - if (m->m_flags & M_EXT) { - if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) ) - return m; - } else { - if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) ) - return m; - } - } - - DEBUG_ERROR("dtom failed"); - - return (struct mbuf *)0; -} diff --git a/slirp/mbuf.h b/slirp/mbuf.h deleted file mode 100644 index 6419f648f..000000000 --- a/slirp/mbuf.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)mbuf.h 8.3 (Berkeley) 1/21/94 - * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp - */ - -#ifndef _MBUF_H_ -#define _MBUF_H_ - -#define MINCSIZE 4096 /* Amount to increase mbuf if too small */ - -/* - * 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. - */ - -/* - * 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) -#define M_TRAILINGSPACE M_FREEROOM - -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 data */ - struct socket *m_so; - - caddr_t m_data; /* Location of data */ - int m_len; /* Amount of data in this mbuf */ - - Slirp *slirp; - bool arp_requested; - uint64_t expiration_date; - /* start of dynamic buffer area, must be last element */ - union { - char m_dat[1]; /* ANSI don't like 0 sized arrays */ - char *m_ext; - }; -}; - -#define ifq_prev m_prev -#define ifq_next m_next -#define ifs_prev m_prevpkt -#define ifs_next m_nextpkt -#define ifq_so m_so - -#define M_EXT 0x01 /* m_ext points to more (malloced) data */ -#define M_FREELIST 0x02 /* mbuf is on free list */ -#define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */ -#define M_DOFREE 0x08 /* when m_free is called on the mbuf, free() - * it rather than putting it on the free list */ - -void m_init(Slirp *); -void m_cleanup(Slirp *slirp); -struct mbuf * m_get(Slirp *); -void m_free(struct mbuf *); -void m_cat(register struct mbuf *, register struct mbuf *); -void m_inc(struct mbuf *, int); -void m_adj(struct mbuf *, int); -int m_copy(struct mbuf *, struct mbuf *, int, int); -struct mbuf * dtom(Slirp *, void *); - -static inline void ifs_init(struct mbuf *ifm) -{ - ifm->ifs_next = ifm->ifs_prev = ifm; -} - -#endif diff --git a/slirp/misc.c b/slirp/misc.c deleted file mode 100644 index 088918f6f..000000000 --- a/slirp/misc.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#include -#include - -#include "monitor/monitor.h" -#include "qemu/error-report.h" -#include "qemu/main-loop.h" - -int slirp_debug = -#ifdef DEBUG - DBG_CALL|DBG_MISC|DBG_ERROR; -#else - 0; -#endif - -struct quehead { - struct quehead *qh_link; - struct quehead *qh_rlink; -}; - -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; -} - -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; -} - -int add_exec(struct ex_list **ex_ptr, int do_pty, const char *exec, - struct in_addr addr, int port) -{ - struct ex_list *tmp_ptr; - - /* First, check if the port is "bound" */ - for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) { - if (port == tmp_ptr->ex_fport && - addr.s_addr == tmp_ptr->ex_addr.s_addr) - return -1; - } - - tmp_ptr = *ex_ptr; - *ex_ptr = (struct ex_list *)g_new(struct ex_list, 1); - (*ex_ptr)->ex_fport = port; - (*ex_ptr)->ex_addr = addr; - (*ex_ptr)->ex_pty = do_pty; - (*ex_ptr)->ex_exec = (do_pty == 3) ? exec : g_strdup(exec); - (*ex_ptr)->ex_next = tmp_ptr; - return 0; -} - -#ifndef HAVE_STRERROR - -/* - * For systems with no strerror - */ - -extern int sys_nerr; -extern char *sys_errlist[]; - -char * -strerror(error) - int error; -{ - if (error < sys_nerr) - return sys_errlist[error]; - else - return "Unknown error."; -} - -#endif - - -#ifdef _WIN32 - -int -fork_exec(struct socket *so, const char *ex, int do_pty) -{ - /* not implemented */ - return 0; -} - -#else - -/* - * XXX This is ugly - * We create and bind a socket, then fork off to another - * process, which connects to this socket, after which we - * exec the wanted program. If something (strange) happens, - * the accept() call could block us forever. - * - * do_pty = 0 Fork/exec inetd style - * do_pty = 1 Fork/exec using slirp.telnetd - * do_ptr = 2 Fork/exec using pty - */ -int -fork_exec(struct socket *so, const char *ex, int do_pty) -{ -#if defined(NEED_FORK_EXEC) - int s; - struct sockaddr_in addr; - socklen_t addrlen = sizeof(addr); - int opt; - const char *argv[256]; - /* don't want to clobber the original */ - char *bptr; - const char *curarg; - int c, i, ret; - pid_t pid; - - DEBUG_CALL("fork_exec"); - DEBUG_ARG("so = %lx", (long)so); - DEBUG_ARG("ex = %lx", (long)ex); - DEBUG_ARG("do_pty = %lx", (long)do_pty); - - if (do_pty == 2) { - return 0; - } else { - addr.sin_family = AF_INET; - addr.sin_port = 0; - addr.sin_addr.s_addr = INADDR_ANY; - - if ((s = qemu_socket(AF_INET, SOCK_STREAM, 0)) < 0 || - bind(s, (struct sockaddr *)&addr, addrlen) < 0 || - listen(s, 1) < 0) { - error_report("Error: inet socket: %s", strerror(errno)); - closesocket(s); - - return 0; - } - } - - pid = fork(); - switch(pid) { - case -1: - error_report("Error: fork failed: %s", strerror(errno)); - close(s); - return 0; - - case 0: - setsid(); - - /* Set the DISPLAY */ - getsockname(s, (struct sockaddr *)&addr, &addrlen); - close(s); - /* - * Connect to the socket - * XXX If any of these fail, we're in trouble! - */ - s = qemu_socket(AF_INET, SOCK_STREAM, 0); - addr.sin_addr = loopback_addr; - do { - ret = connect(s, (struct sockaddr *)&addr, addrlen); - } while (ret < 0 && errno == EINTR); - - dup2(s, 0); - dup2(s, 1); - dup2(s, 2); - for (s = getdtablesize() - 1; s >= 3; s--) - close(s); - - i = 0; - bptr = g_strdup(ex); /* No need to free() this */ - if (do_pty == 1) { - /* Setup "slirp.telnetd -x" */ - argv[i++] = "slirp.telnetd"; - argv[i++] = "-x"; - argv[i++] = bptr; - } else - do { - /* Change the string into argv[] */ - curarg = bptr; - while (*bptr != ' ' && *bptr != (char)0) - bptr++; - c = *bptr; - *bptr++ = (char)0; - argv[i++] = g_strdup(curarg); - } while (c); - - argv[i] = NULL; - execvp(argv[0], (char * const *)argv); - - /* Ooops, failed, let's tell the user why */ - fprintf(stderr, "Error: execvp of %s failed: %s\n", - argv[0], strerror(errno)); - close(0); close(1); close(2); /* XXX */ - exit(1); - - default: - qemu_add_child_watch(pid); - /* - * XXX this could block us... - * XXX Should set a timer here, and if accept() doesn't - * return after X seconds, declare it a failure - * The only reason this will block forever is if socket() - * of connect() fail in the child process - */ - do { - so->s = accept(s, (struct sockaddr *)&addr, &addrlen); - } while (so->s < 0 && errno == EINTR); - closesocket(s); - socket_set_fast_reuse(so->s); - opt = 1; - qemu_setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); - qemu_set_nonblock(so->s); - - /* Append the telnet options now */ - if (so->so_m != NULL && do_pty == 1) { - sbappend(so, so->so_m); - so->so_m = NULL; - } - - return 1; - } -#else - return 0; -#endif -} -#endif - -void slirp_connection_info(Slirp *slirp, Monitor *mon) -{ -#if (TCPS_CLOSED != 0) || (TCPS_TIME_WAIT != 10) -#error unexpected TCPS symbol values -#endif - 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]; - - monitor_printf(mon, " Protocol[State] FD Source Address Port " - "Dest. Address Port RecvQ SendQ\n"); - - for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) { - if (so->so_state & SS_HOSTFWD) { - state = "HOST_FORWARD"; - } else if (so->so_tcpcb) { - state = tcpstates[so->so_tcpcb->t_state]; - } else { - state = "NONE"; - } - if (so->so_state & (SS_HOSTFWD | SS_INCOMING)) { - src_len = sizeof(src); - getsockname(so->s, (struct sockaddr *)&src, &src_len); - dst_addr = so->so_laddr; - dst_port = so->so_lport; - } else { - src.sin_addr = so->so_laddr; - src.sin_port = so->so_lport; - dst_addr = so->so_faddr; - dst_port = so->so_fport; - } - snprintf(buf, sizeof(buf), " TCP[%s]", state); - monitor_printf(mon, "%-19s %3d %15s %5d ", buf, so->s, - src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*", - ntohs(src.sin_port)); - monitor_printf(mon, "%15s %5d %5d %5d\n", - inet_ntoa(dst_addr), ntohs(dst_port), - so->so_rcv.sb_cc, so->so_snd.sb_cc); - } - - for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) { - if (so->so_state & SS_HOSTFWD) { - snprintf(buf, sizeof(buf), " UDP[HOST_FORWARD]"); - src_len = sizeof(src); - (void)getsockname(so->s, (struct sockaddr *)&src, &src_len); - dst_addr = so->so_laddr; - dst_port = so->so_lport; - } else { - snprintf(buf, sizeof(buf), " UDP[%d sec]", - (so->so_expire - curtime) / 1000); - src.sin_addr = so->so_laddr; - src.sin_port = so->so_lport; - dst_addr = so->so_faddr; - dst_port = so->so_fport; - } - monitor_printf(mon, "%-19s %3d %15s %5d ", buf, so->s, - src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*", - ntohs(src.sin_port)); - monitor_printf(mon, "%15s %5d %5d %5d\n", - inet_ntoa(dst_addr), ntohs(dst_port), - so->so_rcv.sb_cc, so->so_snd.sb_cc); - } - - for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) { - snprintf(buf, sizeof(buf), " ICMP[%d sec]", - (so->so_expire - curtime) / 1000); - src.sin_addr = so->so_laddr; - dst_addr = so->so_faddr; - monitor_printf(mon, "%-19s %3d %15s - ", buf, so->s, - src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*"); - monitor_printf(mon, "%15s - %5d %5d\n", inet_ntoa(dst_addr), - so->so_rcv.sb_cc, so->so_snd.sb_cc); - } -} diff --git a/slirp/misc.h b/slirp/misc.h deleted file mode 100644 index 33e9369c8..000000000 --- a/slirp/misc.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#ifndef _MISC_H_ -#define _MISC_H_ - -#include "socket.h" - -struct ex_list { - int ex_pty; /* Do we want a pty? */ - struct in_addr ex_addr; /* Server address */ - int ex_fport; /* Port to telnet to */ - const char *ex_exec; /* Command line of what to exec */ - struct ex_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_RSH 0x8 - -#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; -}; - -void slirp_insque(void *, void *); -void slirp_remque(void *); -int add_exec(struct ex_list **, int, const char *, struct in_addr, int); -int fork_exec(struct socket *so, const char *ex, int do_pty); - -#endif diff --git a/slirp/sbuf.c b/slirp/sbuf.c deleted file mode 100644 index d0888d5c3..000000000 --- a/slirp/sbuf.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#include -#include - -static void sbappendsb(struct sbuf *sb, struct mbuf *m); - -void -sbfree(struct sbuf *sb) -{ - free(sb->sb_data); -} - -void -sbdrop(struct sbuf *sb, int num) -{ - u_int limit = sb->sb_datalen / 2; - - /* - * We can only drop how much we have - * This should never succeed - */ - if((u_int)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) { - qemu_notify_event(); - } -} - -void -sbreserve(struct sbuf *sb, int size) -{ - if (sb->sb_data) { - /* Already alloced, realloc if necessary */ - if (sb->sb_datalen != size) { - sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size); - sb->sb_cc = 0; - if (sb->sb_wptr) - sb->sb_datalen = size; - else - sb->sb_datalen = 0; - } - } else { - sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size); - sb->sb_cc = 0; - if (sb->sb_wptr) - sb->sb_datalen = size; - else - sb->sb_datalen = 0; - } -} - -/* - * Try and write() to the socket, whatever doesn't get written - * append to the buffer... for a host with a fast net connection, - * this prevents an unnecessary copy of the data - * (the socket is non-blocking, so we won't hang) - */ -void -sbappend(struct socket *so, struct mbuf *m) -{ - int ret = 0; - - DEBUG_CALL("sbappend"); - DEBUG_ARG("so = %lx", (long)so); - DEBUG_ARG("m = %lx", (long)m); - DEBUG_ARG("m->m_len = %d", m->m_len); - - /* Shouldn't happen, but... e.g. foreign host closes connection */ - if (m->m_len <= 0) { - m_free(m); - return; - } - - /* - * If there is urgent data, call sosendoob - * if not all was sent, sowrite will take care of the rest - * (The rest of this function is just an optimisation) - */ - if (so->so_urgc) { - sbappendsb(&so->so_rcv, m); - m_free(m); - (void)sosendoob(so); - return; - } - - /* - * We only write if there's nothing in the buffer, - * ottherwise it'll arrive out of order, and hence corrupt - */ - if (!so->so_rcv.sb_cc) - ret = slirp_send(so, m->m_data, m->m_len, 0); - - if (ret <= 0) { - /* - * Nothing was written - * It's possible that the socket has closed, but - * we don't need to check because if it has closed, - * it will be detected in the normal way by soread() - */ - sbappendsb(&so->so_rcv, m); - } else if (ret != m->m_len) { - /* - * Something was written, but not everything.. - * sbappendsb the rest - */ - m->m_len -= ret; - m->m_data += ret; - sbappendsb(&so->so_rcv, m); - } /* else */ - /* Whatever happened, we free the mbuf */ - m_free(m); -} - -/* - * Copy the data from m into sb - * The caller is responsible to make sure there's enough room - */ -static void -sbappendsb(struct sbuf *sb, struct mbuf *m) -{ - int len, n, nn; - - len = m->m_len; - - if (sb->sb_wptr < sb->sb_rptr) { - n = sb->sb_rptr - sb->sb_wptr; - if (n > len) n = len; - memcpy(sb->sb_wptr, m->m_data, n); - } else { - /* Do the right edge first */ - n = sb->sb_data + sb->sb_datalen - sb->sb_wptr; - if (n > len) n = len; - memcpy(sb->sb_wptr, m->m_data, n); - len -= n; - if (len) { - /* Now the left edge */ - nn = sb->sb_rptr - sb->sb_data; - if (nn > len) nn = len; - memcpy(sb->sb_data,m->m_data+n,nn); - n += nn; - } - } - - sb->sb_cc += n; - sb->sb_wptr += n; - if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen) - sb->sb_wptr -= sb->sb_datalen; -} - -/* - * Copy data from sbuf to a normal, straight buffer - * Don't update the sbuf rptr, this will be - * done in sbdrop when the data is acked - */ -void -sbcopy(struct sbuf *sb, int off, int len, char *to) -{ - char *from; - - from = sb->sb_rptr + off; - if (from >= sb->sb_data + sb->sb_datalen) - from -= sb->sb_datalen; - - if (from < sb->sb_wptr) { - if ((u_int)len > sb->sb_cc) len = sb->sb_cc; - memcpy(to,from,len); - } else { - /* re-use off */ - off = (sb->sb_data + sb->sb_datalen) - from; - if (off > len) off = len; - memcpy(to,from,off); - len -= off; - if (len) - memcpy(to+off,sb->sb_data,len); - } -} diff --git a/slirp/sbuf.h b/slirp/sbuf.h deleted file mode 100644 index 26e901cb8..000000000 --- a/slirp/sbuf.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#ifndef _SBUF_H_ -#define _SBUF_H_ - -#define sbflush(sb) sbdrop((sb),(sb)->sb_cc) -#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc) - -struct sbuf { - u_int sb_cc; /* actual chars in buffer */ - u_int 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 *); -void sbdrop(struct sbuf *, int); -void sbreserve(struct sbuf *, int); -void sbappend(struct socket *, struct mbuf *); -void sbcopy(struct sbuf *, int, int, char *); - -#endif diff --git a/slirp/slirp.c b/slirp/slirp.c deleted file mode 100644 index 1fa8654e7..000000000 --- a/slirp/slirp.c +++ /dev/null @@ -1,1202 +0,0 @@ -/* - * libslirp glue - * - * Copyright (c) 2004-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu-common.h" -#include "qemu/timer.h" -#include "sysemu/char.h" -#include "slirp.h" -#include "hw/hw.h" - -/* 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 -}; - -u_int curtime; - -static QTAILQ_HEAD(slirp_instances, Slirp) slirp_instances = - QTAILQ_HEAD_INITIALIZER(slirp_instances); - -static struct in_addr dns_addr; -static u_int dns_addr_time; - -#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 = (FIXED_INFO *)GlobalAlloc(GPTR, BufLen); - } - - if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) { - printf("GetNetworkParams failed. ret = %08x\n", (u_int)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; -} - -static void winsock_cleanup(void) -{ - WSACleanup(); -} - -#else - -static struct stat dns_addr_stat; - -int get_dns_addr(struct in_addr *pdns_addr) -{ - char buff[512]; - char buff2[257]; - FILE *f; - int found = 0; - struct in_addr tmp_addr; - - if (dns_addr.s_addr != 0) { - struct stat old_stat; - if ((curtime - dns_addr_time) < TIMEOUT_DEFAULT) { - *pdns_addr = dns_addr; - return 0; - } - old_stat = dns_addr_stat; - if (stat("/etc/resolv.conf", &dns_addr_stat) != 0) - return -1; - if ((dns_addr_stat.st_dev == old_stat.st_dev) - && (dns_addr_stat.st_ino == old_stat.st_ino) - && (dns_addr_stat.st_size == old_stat.st_size) - && (dns_addr_stat.st_mtime == old_stat.st_mtime)) { - *pdns_addr = dns_addr; - return 0; - } - } - - f = fopen("/etc/resolv.conf", "r"); - if (!f) - return -1; - -#ifdef DEBUG - fprintf(stderr, "IP address of your DNS(s): "); -#endif - while (fgets(buff, 512, f) != NULL) { - if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) { - if (!inet_aton(buff2, &tmp_addr)) - continue; - /* If it's the first one, set it to dns_addr */ - if (!found) { - *pdns_addr = tmp_addr; - dns_addr = tmp_addr; - dns_addr_time = curtime; - } -#ifdef DEBUG - else - fprintf(stderr, ", "); -#endif - if (++found > 3) { -#ifdef DEBUG - fprintf(stderr, "(more)"); -#endif - break; - } -#ifdef DEBUG - else - fprintf(stderr, "%s", inet_ntoa(tmp_addr)); -#endif - } - } - fclose(f); - if (!found) - return -1; - return 0; -} - -#endif - -static void slirp_init_once(void) -{ - static int initialized; -#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); -} - -static void slirp_state_save(QEMUFile *f, void *opaque); -static int slirp_state_load(QEMUFile *f, void *opaque, int version_id); - -Slirp *slirp_init(int restricted, struct in_addr vnetwork, - struct in_addr vnetmask, struct in_addr vhost, - const char *vhostname, const char *tftp_path, - const char *bootfile, struct in_addr vdhcp_start, - struct in_addr vnameserver, const char **vdnssearch, - void *opaque) -{ - Slirp *slirp = (Slirp *)g_malloc0(sizeof(Slirp)); - - slirp_init_once(); - - /* set debug flags (useful when compiled with DEBUG enabled)*/ - /* bitmask values (1 = CALL, 2 = MISC, 3 = ERROR) */ - if (getenv("SLIRP_DEBUG")) - slirp_debug = atoi(getenv("SLIRP_DEBUG")); - - slirp->restricted = restricted; - - if_init(slirp); - ip_init(slirp); - - /* Initialise mbufs *after* setting the MTU */ - m_init(slirp); - - slirp->vnetwork_addr = vnetwork; - slirp->vnetwork_mask = vnetmask; - slirp->vhost_addr = vhost; - if (vhostname) { - pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname), - vhostname); - } - slirp->tftp_prefix = g_strdup(tftp_path); - slirp->bootp_filename = g_strdup(bootfile); - slirp->vdhcp_startaddr = vdhcp_start; - slirp->vnameserver_addr = vnameserver; - - if (vdnssearch) { - translate_dnssearch(slirp, vdnssearch); - } - - slirp->opaque = opaque; - - register_savevm(NULL, "slirp", 0, 3, - slirp_state_save, slirp_state_load, slirp); - - QTAILQ_INSERT_TAIL(&slirp_instances, slirp, entry); - - return slirp; -} - -void slirp_cleanup(Slirp *slirp) -{ - QTAILQ_REMOVE(&slirp_instances, slirp, entry); - - unregister_savevm(NULL, "slirp", slirp); - - ip_cleanup(slirp); - m_cleanup(slirp); - - g_free(slirp->vdnssearch); - g_free(slirp->tftp_prefix); - g_free(slirp->bootp_filename); - 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(uint32_t *timeout) -{ - Slirp *slirp; - 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. - */ - QTAILQ_FOREACH(slirp, &slirp_instances, entry) { - if (slirp->time_fasttimo) { - *timeout = TIMEOUT_FAST; - return; - } - if (slirp->do_slowtimo) { - t = MIN(TIMEOUT_SLOW, t); - } - } - *timeout = t; -} - -void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout) -{ - Slirp *slirp; - struct socket *so, *so_next; - - if (QTAILQ_EMPTY(&slirp_instances)) { - return; - } - - /* - * First, TCP sockets - */ - - QTAILQ_FOREACH(slirp, &slirp_instances, entry) { - /* - * *_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) { - gushort 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) { - GPollFD pfd = { so->s, G_IO_IN | G_IO_HUP | G_IO_ERR, 0 }; - - so->pollfds_idx = pollfds->len; - g_array_append_val(pollfds, pfd); - continue; - } - - /* - * Set for writing sockets which are connecting - */ - if (so->so_state & SS_ISFCONNECTING) { - GPollFD pfd = { so->s, G_IO_OUT | G_IO_ERR, 0 }; - - so->pollfds_idx = pollfds->len; - g_array_append_val(pollfds, pfd); - 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 |= G_IO_OUT | G_IO_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 |= G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI; - } - - if (events) { - GPollFD pfd = { so->s, events, 0 }; - - so->pollfds_idx = pollfds->len; - g_array_append_val(pollfds, pfd); - } - } - - /* - * 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) { - GPollFD pfd = { so->s, G_IO_IN | G_IO_HUP | G_IO_ERR, 0 }; - - so->pollfds_idx = pollfds->len; - g_array_append_val(pollfds, pfd); - } - } - - /* - * 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) { - GPollFD pfd = { so->s, G_IO_IN | G_IO_HUP | G_IO_ERR, 0 }; - - so->pollfds_idx = pollfds->len; - g_array_append_val(pollfds, pfd); - } - } - } - slirp_update_timeout(timeout); -} - -void slirp_pollfds_poll(GArray *pollfds, int select_error) -{ - Slirp *slirp; - struct socket *so, *so_next; - int ret; - - if (QTAILQ_EMPTY(&slirp_instances)) { - return; - } - - curtime = (u_int)qemu_clock_get_ms(QEMU_CLOCK_REALTIME); - - QTAILQ_FOREACH(slirp, &slirp_instances, entry) { - /* - * 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 = g_array_index(pollfds, GPollFD, - so->pollfds_idx).revents; - } - - 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 G_IO_IN below if this succeeds - */ - if (revents & G_IO_PRI) { - sorecvoob(so); - } - /* - * Check sockets for reading - */ - else if (revents & (G_IO_IN | G_IO_HUP | G_IO_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)); - } - } - - /* - * Check sockets for writing - */ - if (!(so->so_state & SS_NOFDREF) && - (revents & (G_IO_OUT | G_IO_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 char *) &ret, 0, 0); - if (ret == SOCKET_ERROR) { - /* 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); - /* continue; */ - } else { - ret = sowrite(so); - } - /* - * XXXXX If we wrote something (a lot), there - * could be a need for a window update. - * In the worst case, the remote will send - * a window probe to get things going again - */ - } - - /* - * Probe a still-connecting, non-blocking socket - * to check if it's still alive - */ -#ifdef PROBE_CONN - if (so->so_state & SS_ISFCONNECTING) { - ret = qemu_recv(so->s, &ret, 0, 0); - - if (ret < 0) { - /* XXX */ - if (errno == EAGAIN || errno == EWOULDBLOCK || - errno == EINPROGRESS || errno == ENOTCONN) { - continue; /* Still connecting, continue */ - } - - /* else failed */ - so->so_state &= SS_PERSISTENT_MASK; - so->so_state |= SS_NOFDREF; - - /* tcp_input will take care of it */ - } else { - ret = send(so->s, &ret, 0, 0); - if (ret < 0) { - /* XXX */ - 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; - } - - } - tcp_input((struct mbuf *)NULL, sizeof(struct ip), so); - } /* SS_ISFCONNECTING */ -#endif - } - - /* - * 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 = g_array_index(pollfds, GPollFD, - so->pollfds_idx).revents; - } - - if (so->s != -1 && - (revents & (G_IO_IN | G_IO_HUP | G_IO_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 = g_array_index(pollfds, GPollFD, - so->pollfds_idx).revents; - } - - if (so->s != -1 && - (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) { - icmp_receive(so); - } - } - } - - if_start(slirp); - } -} - -static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) -{ - const struct arphdr *ah = (const struct arphdr *)(pkt + ETH_HLEN); - uint8_t arp_reply[max(ETH_HLEN + sizeof(struct arphdr), 64)]; - struct ethhdr *reh = (struct ethhdr *)arp_reply; - struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN); - int ar_op; - struct ex_list *ex_ptr; - - ar_op = ntohs(ah->ar_op); - switch(ar_op) { - case ARPOP_REQUEST: - if (ah->ar_tip == ah->ar_sip) { - /* Gratuitous ARP */ - arp_table_add(slirp, ah->ar_sip, ah->ar_sha); - return; - } - - if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) == - slirp->vnetwork_addr.s_addr) { - if (ah->ar_tip == slirp->vnameserver_addr.s_addr || - ah->ar_tip == slirp->vhost_addr.s_addr) - goto arp_ok; - for (ex_ptr = slirp->exec_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_output(slirp->opaque, 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 = ntohs(*(const uint16_t *)(pkt + 12)); - switch(proto) { - case ETH_P_ARP: - arp_input(slirp, pkt, pkt_len); - break; - case ETH_P_IP: - m = m_get(slirp); - if (!m) - return; - /* Note: we add to align the IP header */ - if (M_FREEROOM(m) < pkt_len + 2) { - m_inc(m, pkt_len + 2); - } - m->m_len = pkt_len + 2; - memcpy(m->m_data + 2, pkt, pkt_len); - - m->m_data += 2 + ETH_HLEN; - m->m_len -= 2 + ETH_HLEN; - - ip_input(m); - break; - default: - break; - } -} - -/* Output the IP packet to the ethernet device. Returns 0 if the packet must be - * re-queued. - */ -int if_encap(Slirp *slirp, struct mbuf *ifm) -{ - uint8_t buf[1600]; - struct ethhdr *eh = (struct ethhdr *)buf; - uint8_t ethaddr[ETH_ALEN]; - const struct ip *iph = (const struct ip *)ifm->m_data; - - if (ifm->m_len + ETH_HLEN > sizeof(buf)) { - return 1; - } - - if (iph->ip_dst.s_addr == 0) { - /* 0.0.0.0 can not be a destination address, something went wrong, - * avoid making it worse */ - return 1; - } - if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) { - uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)]; - struct ethhdr *reh = (struct ethhdr *)arp_req; - struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN); - - if (!ifm->arp_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_output(slirp->opaque, arp_req, sizeof(arp_req)); - ifm->arp_requested = true; - - /* Expire request and drop outgoing packet after 1 second */ - ifm->expiration_date = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL; - } - return 0; - } else { - memcpy(eh->h_dest, ethaddr, ETH_ALEN); - 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); - memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len); - slirp_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN); - return 1; - } -} - -/* Drop host forwarding rule, return 0 if found. */ -int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, - int host_port) -{ - struct socket *so; - struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb); - struct sockaddr_in addr; - int port = htons(host_port); - socklen_t addr_len; - - for (so = head->so_next; so != head; so = so->so_next) { - addr_len = sizeof(addr); - if ((so->so_state & SS_HOSTFWD) && - getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 && - addr.sin_addr.s_addr == host_addr.s_addr && - addr.sin_port == port) { - closesocket(so->s); - sofree(so); - return 0; - } - } - - return -1; -} - -int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, - int host_port, struct in_addr guest_addr, int guest_port) -{ - if (!guest_addr.s_addr) { - guest_addr = slirp->vdhcp_startaddr; - } - if (is_udp) { - if (!udp_listen(slirp, host_addr.s_addr, htons(host_port), - guest_addr.s_addr, htons(guest_port), SS_HOSTFWD)) - return -1; - } else { - if (!tcp_listen(slirp, host_addr.s_addr, htons(host_port), - guest_addr.s_addr, htons(guest_port), SS_HOSTFWD)) - return -1; - } - return 0; -} - -int slirp_add_exec(Slirp *slirp, int do_pty, const void *args, - struct in_addr *guest_addr, int guest_port) -{ - 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 -1; - } - return add_exec(&slirp->exec_list, do_pty, (char *)args, *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->extra) { - qemu_chr_fe_write((CharDriverState*)so->extra, (const uint8_t *)buf, len); - return len; - } - - return send(so->s, (const char *)buf, len, flags); -} - -static struct socket * -slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port) -{ - struct socket *so; - - for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) { - if (so->so_faddr.s_addr == guest_addr.s_addr && - htons(so->so_fport) == guest_port) { - return so; - } - } - return NULL; -} - -size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr, - int guest_port) -{ - struct iovec iov[2]; - struct socket *so; - - so = slirp_find_ctl_socket(slirp, guest_addr, guest_port); - - if (!so || so->so_state & SS_NOFDREF) { - return 0; - } - - if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2)) { - return 0; - } - - return sopreprbuf(so, iov, NULL); -} - -void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port, - const uint8_t *buf, int size) -{ - int ret; - struct socket *so = slirp_find_ctl_socket(slirp, guest_addr, guest_port); - - if (!so) - return; - - ret = soreadbuf(so, (const char *)buf, size); - - if (ret > 0) - tcp_output(sototcpcb(so)); -} - -static void slirp_tcp_save(QEMUFile *f, struct tcpcb *tp) -{ - int i; - - qemu_put_sbe16(f, tp->t_state); - for (i = 0; i < TCPT_NTIMERS; i++) - qemu_put_sbe16(f, tp->t_timer[i]); - qemu_put_sbe16(f, tp->t_rxtshift); - qemu_put_sbe16(f, tp->t_rxtcur); - qemu_put_sbe16(f, tp->t_dupacks); - qemu_put_be16(f, tp->t_maxseg); - qemu_put_sbyte(f, tp->t_force); - qemu_put_be16(f, tp->t_flags); - qemu_put_be32(f, tp->snd_una); - qemu_put_be32(f, tp->snd_nxt); - qemu_put_be32(f, tp->snd_up); - qemu_put_be32(f, tp->snd_wl1); - qemu_put_be32(f, tp->snd_wl2); - qemu_put_be32(f, tp->iss); - qemu_put_be32(f, tp->snd_wnd); - qemu_put_be32(f, tp->rcv_wnd); - qemu_put_be32(f, tp->rcv_nxt); - qemu_put_be32(f, tp->rcv_up); - qemu_put_be32(f, tp->irs); - qemu_put_be32(f, tp->rcv_adv); - qemu_put_be32(f, tp->snd_max); - qemu_put_be32(f, tp->snd_cwnd); - qemu_put_be32(f, tp->snd_ssthresh); - qemu_put_sbe16(f, tp->t_idle); - qemu_put_sbe16(f, tp->t_rtt); - qemu_put_be32(f, tp->t_rtseq); - qemu_put_sbe16(f, tp->t_srtt); - qemu_put_sbe16(f, tp->t_rttvar); - qemu_put_be16(f, tp->t_rttmin); - qemu_put_be32(f, tp->max_sndwnd); - qemu_put_byte(f, tp->t_oobflags); - qemu_put_byte(f, tp->t_iobc); - qemu_put_sbe16(f, tp->t_softerror); - qemu_put_byte(f, tp->snd_scale); - qemu_put_byte(f, tp->rcv_scale); - qemu_put_byte(f, tp->request_r_scale); - qemu_put_byte(f, tp->requested_s_scale); - qemu_put_be32(f, tp->ts_recent); - qemu_put_be32(f, tp->ts_recent_age); - qemu_put_be32(f, tp->last_ack_sent); -} - -static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf) -{ - uint32_t off; - - qemu_put_be32(f, sbuf->sb_cc); - qemu_put_be32(f, sbuf->sb_datalen); - off = (uint32_t)(sbuf->sb_wptr - sbuf->sb_data); - qemu_put_sbe32(f, off); - off = (uint32_t)(sbuf->sb_rptr - sbuf->sb_data); - qemu_put_sbe32(f, off); - qemu_put_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen); -} - -static void slirp_socket_save(QEMUFile *f, struct socket *so) -{ - qemu_put_be32(f, so->so_urgc); - qemu_put_be32(f, so->so_faddr.s_addr); - qemu_put_be32(f, so->so_laddr.s_addr); - qemu_put_be16(f, so->so_fport); - qemu_put_be16(f, so->so_lport); - qemu_put_byte(f, so->so_iptos); - qemu_put_byte(f, so->so_emu); - qemu_put_byte(f, so->so_type); - qemu_put_be32(f, so->so_state); - slirp_sbuf_save(f, &so->so_rcv); - slirp_sbuf_save(f, &so->so_snd); - slirp_tcp_save(f, so->so_tcpcb); -} - -static void slirp_bootp_save(QEMUFile *f, Slirp *slirp) -{ - int i; - - for (i = 0; i < NB_BOOTP_CLIENTS; i++) { - qemu_put_be16(f, slirp->bootp_clients[i].allocated); - qemu_put_buffer(f, slirp->bootp_clients[i].macaddr, 6); - } -} - -static void slirp_state_save(QEMUFile *f, void *opaque) -{ - Slirp *slirp = (Slirp *)opaque; - struct ex_list *ex_ptr; - - for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) - if (ex_ptr->ex_pty == 3) { - struct socket *so; - so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr, - ntohs(ex_ptr->ex_fport)); - if (!so) - continue; - - qemu_put_byte(f, 42); - slirp_socket_save(f, so); - } - qemu_put_byte(f, 0); - - qemu_put_be16(f, slirp->ip_id); - - slirp_bootp_save(f, slirp); -} - -static void slirp_tcp_load(QEMUFile *f, struct tcpcb *tp) -{ - int i; - - tp->t_state = qemu_get_sbe16(f); - for (i = 0; i < TCPT_NTIMERS; i++) - tp->t_timer[i] = qemu_get_sbe16(f); - tp->t_rxtshift = qemu_get_sbe16(f); - tp->t_rxtcur = qemu_get_sbe16(f); - tp->t_dupacks = qemu_get_sbe16(f); - tp->t_maxseg = qemu_get_be16(f); - tp->t_force = qemu_get_sbyte(f); - tp->t_flags = qemu_get_be16(f); - tp->snd_una = qemu_get_be32(f); - tp->snd_nxt = qemu_get_be32(f); - tp->snd_up = qemu_get_be32(f); - tp->snd_wl1 = qemu_get_be32(f); - tp->snd_wl2 = qemu_get_be32(f); - tp->iss = qemu_get_be32(f); - tp->snd_wnd = qemu_get_be32(f); - tp->rcv_wnd = qemu_get_be32(f); - tp->rcv_nxt = qemu_get_be32(f); - tp->rcv_up = qemu_get_be32(f); - tp->irs = qemu_get_be32(f); - tp->rcv_adv = qemu_get_be32(f); - tp->snd_max = qemu_get_be32(f); - tp->snd_cwnd = qemu_get_be32(f); - tp->snd_ssthresh = qemu_get_be32(f); - tp->t_idle = qemu_get_sbe16(f); - tp->t_rtt = qemu_get_sbe16(f); - tp->t_rtseq = qemu_get_be32(f); - tp->t_srtt = qemu_get_sbe16(f); - tp->t_rttvar = qemu_get_sbe16(f); - tp->t_rttmin = qemu_get_be16(f); - tp->max_sndwnd = qemu_get_be32(f); - tp->t_oobflags = qemu_get_byte(f); - tp->t_iobc = qemu_get_byte(f); - tp->t_softerror = qemu_get_sbe16(f); - tp->snd_scale = qemu_get_byte(f); - tp->rcv_scale = qemu_get_byte(f); - tp->request_r_scale = qemu_get_byte(f); - tp->requested_s_scale = qemu_get_byte(f); - tp->ts_recent = qemu_get_be32(f); - tp->ts_recent_age = qemu_get_be32(f); - tp->last_ack_sent = qemu_get_be32(f); - tcp_template(tp); -} - -static int slirp_sbuf_load(QEMUFile *f, struct sbuf *sbuf) -{ - uint32_t off, sb_cc, sb_datalen; - - sb_cc = qemu_get_be32(f); - sb_datalen = qemu_get_be32(f); - - sbreserve(sbuf, sb_datalen); - - if (sbuf->sb_datalen != sb_datalen) - return -ENOMEM; - - sbuf->sb_cc = sb_cc; - - off = qemu_get_sbe32(f); - sbuf->sb_wptr = sbuf->sb_data + off; - off = qemu_get_sbe32(f); - sbuf->sb_rptr = sbuf->sb_data + off; - qemu_get_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen); - - return 0; -} - -static int slirp_socket_load(QEMUFile *f, struct socket *so) -{ - if (tcp_attach(so) < 0) - return -ENOMEM; - - so->so_urgc = qemu_get_be32(f); - so->so_faddr.s_addr = qemu_get_be32(f); - so->so_laddr.s_addr = qemu_get_be32(f); - so->so_fport = qemu_get_be16(f); - so->so_lport = qemu_get_be16(f); - so->so_iptos = qemu_get_byte(f); - so->so_emu = qemu_get_byte(f); - so->so_type = qemu_get_byte(f); - so->so_state = qemu_get_be32(f); - if (slirp_sbuf_load(f, &so->so_rcv) < 0) - return -ENOMEM; - if (slirp_sbuf_load(f, &so->so_snd) < 0) - return -ENOMEM; - slirp_tcp_load(f, so->so_tcpcb); - - return 0; -} - -static void slirp_bootp_load(QEMUFile *f, Slirp *slirp) -{ - int i; - - for (i = 0; i < NB_BOOTP_CLIENTS; i++) { - slirp->bootp_clients[i].allocated = qemu_get_be16(f); - qemu_get_buffer(f, slirp->bootp_clients[i].macaddr, 6); - } -} - -static int slirp_state_load(QEMUFile *f, void *opaque, int version_id) -{ - Slirp *slirp = (Slirp *)opaque; - struct ex_list *ex_ptr; - - while (qemu_get_byte(f)) { - int ret; - struct socket *so = socreate(slirp); - - if (!so) - return -ENOMEM; - - ret = slirp_socket_load(f, so); - - 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->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { - if (ex_ptr->ex_pty == 3 && - 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->extra = (void *)ex_ptr->ex_exec; - } - - if (version_id >= 2) { - slirp->ip_id = qemu_get_be16(f); - } - - if (version_id >= 3) { - slirp_bootp_load(f, slirp); - } - - return 0; -} diff --git a/slirp/slirp.h b/slirp/slirp.h deleted file mode 100644 index 28c45f7ae..000000000 --- a/slirp/slirp.h +++ /dev/null @@ -1,366 +0,0 @@ -#ifndef __COMMON_H__ -#define __COMMON_H__ - -#include "config-host.h" -#include "slirp_config.h" - -#ifdef _WIN32 -#ifndef _MSC_VER -# include -#endif - -typedef char *caddr_t; - -# include -# include -# include -# include -# include -# include - -#else -# define ioctlsocket ioctl -# define closesocket(s) close(s) -# if !defined(__HAIKU__) -# define O_BINARY 0 -# endif -#endif - -#include -#ifdef HAVE_SYS_BITYPES_H -# include -#endif - -#include - -#ifdef HAVE_UNISTD_H -# include -#endif - -#ifdef HAVE_STDLIB_H -# include -#endif - -#include -#include - -#ifndef HAVE_MEMMOVE -#define memmove(x, y, z) bcopy(y, x, z) -#endif - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# ifdef HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif - -#ifdef HAVE_STRING_H -# include -#else -# include -#endif - -#ifndef _WIN32 -#include -#endif - -#ifndef _WIN32 -#include -#include -#endif - -/* Systems lacking strdup() definition in . */ -#if defined(ultrix) -char *strdup(const char *); -#endif - -/* Systems lacking malloc() definition in . */ -#if defined(ultrix) || defined(hcx) -void *malloc(size_t arg); -void free(void *ptr); -#endif - -#include -#ifndef NO_UNIX_SOCKETS -#include -#endif -#include -#ifdef HAVE_SYS_SIGNAL_H -# include -#endif -#ifndef _WIN32 -#include -#endif - -#if defined(HAVE_SYS_IOCTL_H) -# include -#endif - -#ifdef HAVE_SYS_SELECT_H -# include -#endif - -#ifdef HAVE_SYS_WAIT_H -# include -#endif - -#ifdef HAVE_SYS_FILIO_H -# include -#endif - -#ifdef USE_PPP -#include -#endif - -#ifdef __STDC__ -#include -#else -#include -#endif - -#include - -/* Avoid conflicting with the libc insque() and remque(), which - have different prototypes. */ -#define insque slirp_insque -#define remque slirp_remque - -#ifdef HAVE_SYS_STROPTS_H -#include -#endif - -#include "debug.h" - -#include "qemu/queue.h" -#include "qemu/sockets.h" - -#include "libslirp.h" -#include "ip.h" -#include "tcp.h" -#include "tcp_timer.h" -#include "tcp_var.h" -#include "tcpip.h" -#include "udp.h" -#include "ip_icmp.h" -#include "mbuf.h" -#include "sbuf.h" -#include "socket.h" -#include "if.h" -#include "main.h" -#include "misc.h" -#ifdef USE_PPP -#include "ppp/pppd.h" -#include "ppp/ppp.h" -#endif - -#include "bootp.h" -#include "tftp.h" - -#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 ARPOP_REQUEST 1 /* ARP request */ -#define ARPOP_REPLY 2 /* ARP reply */ - -PACKED_BEGIN -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 */ -} PACKED_END; - -PACKED_BEGIN -struct 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 */ -} PACKED_END; - -#define ARP_TABLE_SIZE 16 - -typedef struct ArpTable { - struct 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 Slirp { - QTAILQ_ENTRY(Slirp) entry; - u_int time_fasttimo; - u_int last_slowtimo; - bool do_slowtimo; - - /* virtual network configuration */ - struct in_addr vnetwork_addr; - struct in_addr vnetwork_mask; - struct in_addr vhost_addr; - struct in_addr vdhcp_startaddr; - struct in_addr vnameserver_addr; - - struct in_addr client_ipaddr; - char client_hostname[33]; - - int restricted; - struct ex_list *exec_list; - - /* mbuf states */ - struct mbuf m_freelist, m_usedlist; - int mbuf_alloced; - - /* if states */ - struct mbuf if_fastq; /* fast queue (for interactive data) */ - struct mbuf if_batchq; /* queue for non-interactive data */ - struct mbuf *next_m; /* pointer to next mbuf to output */ - 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; - - /* 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]; - - ArpTable arp_table; - - void *opaque; -}; - -extern Slirp *slirp_instance; - -#ifndef NULL -#define NULL (void *)0 -#endif - -#ifndef FULL_BOLT -void if_start(Slirp *); -#else -void if_start(struct ttys *); -#endif - -#ifndef HAVE_STRERROR - char *strerror(int error); -#endif - -#ifndef HAVE_INDEX - char *index(const char *, int); -#endif - -#ifndef HAVE_GETHOSTID - long gethostid(void); -#endif - -#ifndef _WIN32 -#include -#endif - -#define DEFAULT_BAUD 115200 - -#define SO_OPTIONS 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); - -/* 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 *); - -/* tcp_input.c */ -void tcp_input(register struct mbuf *, int, struct socket *); -int tcp_mss(register struct tcpcb *, u_int); - -/* 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); -struct tcpcb * tcp_newtcpcb(struct socket *); -struct tcpcb * tcp_close(register struct tcpcb *); -void tcp_sockclosed(struct tcpcb *); -int tcp_fconnect(struct socket *); -void tcp_connect(struct socket *); -int tcp_attach(struct socket *); -uint8_t tcp_tos(struct socket *); -int tcp_emu(struct socket *, struct mbuf *); -int tcp_ctl(struct socket *); -struct tcpcb *tcp_drop(struct tcpcb *tp, int err); - -#ifdef USE_PPP -#define MIN_MRU MINMRU -#define MAX_MRU MAXMRU -#else -#define MIN_MRU 128 -#define MAX_MRU 16384 -#endif - -#ifndef _WIN32 -#define min(x,y) ((x) < (y) ? (x) : (y)) -#define max(x,y) ((x) > (y) ? (x) : (y)) -#endif - -#ifdef _WIN32 -#undef errno -#define errno (WSAGetLastError()) -#endif - -#endif diff --git a/slirp/slirp_config.h b/slirp/slirp_config.h deleted file mode 100644 index c06f80bf8..000000000 --- a/slirp/slirp_config.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - * User definable configuration options - */ - -/* Define if you want the connection to be probed */ -/* XXX Not working yet, so ignore this for now */ -#undef PROBE_CONN - -/* Define to 1 if you want KEEPALIVE timers */ -#define DO_KEEPALIVE 0 - -/* Define to MAX interfaces you expect to use at once */ -/* MAX_INTERFACES determines the max. TOTAL number of interfaces (SLIP and PPP) */ -/* MAX_PPP_INTERFACES determines max. number of PPP interfaces */ -#define MAX_INTERFACES 1 -#define MAX_PPP_INTERFACES 1 - -/* Define if you want slirp's socket in /tmp */ -/* XXXXXX Do this in ./configure */ -#undef USE_TMPSOCKET - -/* Define if you want slirp to use cfsetXspeed() on the terminal */ -#undef DO_CFSETSPEED - -/* Define this if you want slirp to write to the tty as fast as it can */ -/* This should only be set if you are using load-balancing, slirp does a */ -/* pretty good job on single modems already, and seting this will make */ -/* interactive sessions less responsive */ -/* XXXXX Talk about having fast modem as unit 0 */ -#undef FULL_BOLT - -/* - * Define if you want slirp to use less CPU - * You will notice a small lag in interactive sessions, but it's not that bad - * Things like Netscape/ftp/etc. are completely unaffected - * This is mainly for sysadmins who have many slirp users - */ -#undef USE_LOWCPU - -/* Define this if your compiler doesn't like prototypes */ -#ifndef __STDC__ -#define NO_PROTOTYPES -#endif - -/*********************************************************/ -/* - * Autoconf defined configuration options - * You shouldn't need to touch any of these - */ - -/* Ignore this */ -#undef DUMMY_PPP - -/* Define if you have unistd.h */ -#ifndef _MSC_VER -#define HAVE_UNISTD_H -#endif - -/* Define if you have stdlib.h */ -#define HAVE_STDLIB_H - -/* Define if you have sys/ioctl.h */ -#undef HAVE_SYS_IOCTL_H -#ifndef _WIN32 -#define HAVE_SYS_IOCTL_H -#endif - -/* Define if you have sys/filio.h */ -#undef HAVE_SYS_FILIO_H -#ifdef __APPLE__ -#define HAVE_SYS_FILIO_H -#endif - -/* Define if you have strerror */ -#define HAVE_STRERROR - -/* Define according to how time.h should be included */ -#define TIME_WITH_SYS_TIME 0 -#undef HAVE_SYS_TIME_H - -/* Define if you have sys/bitypes.h */ -#undef HAVE_SYS_BITYPES_H - -/* Define if the machine is big endian */ -//#undef HOST_WORDS_BIGENDIAN - -/* Define if you have readv */ -#undef HAVE_READV - -/* Define if iovec needs to be declared */ -#undef DECLARE_IOVEC -#ifdef _WIN32 -#define DECLARE_IOVEC -#endif - -/* Define if you have a POSIX.1 sys/wait.h */ -#undef HAVE_SYS_WAIT_H - -/* Define if you have sys/select.h */ -#undef HAVE_SYS_SELECT_H -#ifndef _WIN32 -#define HAVE_SYS_SELECT_H -#endif - -/* Define if you have strings.h */ -#define HAVE_STRING_H - -/* Define if you have arpa/inet.h */ -#undef HAVE_ARPA_INET_H -#ifndef _WIN32 -#define HAVE_ARPA_INET_H -#endif - -/* Define if you have sys/signal.h */ -#undef HAVE_SYS_SIGNAL_H - -/* Define if you have sys/stropts.h */ -#undef HAVE_SYS_STROPTS_H - -/* Define to whatever your compiler thinks inline should be */ -//#define inline inline - -/* Define to whatever your compiler thinks const should be */ -//#define const const - -/* Define if your compiler doesn't like prototypes */ -#undef NO_PROTOTYPES - -/* Define to sizeof(char) */ -#define SIZEOF_CHAR 1 - -/* Define to sizeof(short) */ -#define SIZEOF_SHORT 2 - -/* Define to sizeof(int) */ -#define SIZEOF_INT 4 - -/* Define to sizeof(char *) */ -#define SIZEOF_CHAR_P (HOST_LONG_BITS / 8) - -/* Define if you have random() */ -#undef HAVE_RANDOM - -/* Define if you have srandom() */ -#undef HAVE_SRANDOM - -/* Define if you have inet_aton */ -#undef HAVE_INET_ATON -#ifndef _WIN32 -#define HAVE_INET_ATON -#endif - -/* Define if you have setenv */ -#undef HAVE_SETENV - -/* Define if you have index() */ -#define HAVE_INDEX - -/* Define if you have bcmp() */ -#undef HAVE_BCMP - -/* Define if you have drand48 */ -#undef HAVE_DRAND48 - -/* Define if you have memmove */ -#define HAVE_MEMMOVE - -/* Define if you have gethostid */ -#define HAVE_GETHOSTID - -/* Define if you DON'T have unix-domain sockets */ -#undef NO_UNIX_SOCKETS -#ifdef _WIN32 -#define NO_UNIX_SOCKETS -#endif - -/* Define if you have revoke() */ -#undef HAVE_REVOKE - -/* Define if you have the sysv method of opening pty's (/dev/ptmx, etc.) */ -#undef HAVE_GRANTPT - -/* Define if you have fchmod */ -#undef HAVE_FCHMOD - -/* Define if you have */ -#undef HAVE_SYS_TYPES32_H diff --git a/slirp/socket.c b/slirp/socket.c deleted file mode 100644 index eebe282ed..000000000 --- a/slirp/socket.c +++ /dev/null @@ -1,724 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#include "qemu-common.h" -#include -#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 *head, struct in_addr laddr, u_int lport, - struct in_addr faddr, u_int fport) -{ - struct socket *so; - - for (so = head->so_next; so != head; so = so->so_next) { - if (so->so_lport == lport && - so->so_laddr.s_addr == laddr.s_addr && - so->so_faddr.s_addr == faddr.s_addr && - so->so_fport == fport) - break; - } - - if (so == head) - return (struct socket *)NULL; - return so; - -} - -/* - * 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; - - so = (struct socket *)malloc(sizeof(struct socket)); - if(so) { - memset(so, 0, sizeof(struct socket)); - so->so_state = SS_NOFDREF; - so->s = -1; - so->slirp = slirp; - so->pollfds_idx = -1; - } - return(so); -} - -/* - * remque and free a socket, clobber cache - */ -void -sofree(struct socket *so) -{ - Slirp *slirp = so->slirp; - - if (so->so_emu==EMU_RSH && so->extra) { - sofree((struct socket *)so->extra); - so->extra=NULL; - } - 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 */ - - 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 = %lx", (long )so); - - iov[0].iov_base = sb->sb_wptr; - iov[1].iov_base = NULL; - iov[1].iov_len = 0; - if (np) - *np = 1; - if (len <= 0) - return 0; - - if (sb->sb_wptr < sb->sb_rptr) { - iov[0].iov_len = sb->sb_rptr - sb->sb_wptr; - /* Should never succeed, but... */ - if (iov[0].iov_len > len) - iov[0].iov_len = len; - if (iov[0].iov_len > mss) - iov[0].iov_len -= iov[0].iov_len%mss; - n = 1; - } else { - iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr; - /* Should never succeed, but... */ - if (iov[0].iov_len > len) iov[0].iov_len = len; - len -= iov[0].iov_len; - if (len) { - iov[1].iov_base = sb->sb_data; - iov[1].iov_len = sb->sb_rptr - sb->sb_data; - if(iov[1].iov_len > len) - iov[1].iov_len = len; - total = iov[0].iov_len + iov[1].iov_len; - if (total > mss) { - lss = total%mss; - if (iov[1].iov_len > lss) { - iov[1].iov_len -= lss; - n = 2; - } else { - lss -= iov[1].iov_len; - iov[0].iov_len -= lss; - n = 1; - } - } else - n = 2; - } else { - if (iov[0].iov_len > mss) - iov[0].iov_len -= iov[0].iov_len%mss; - n = 1; - } - } - if (np) - *np = n; - - return iov[0].iov_len + (n - 1) * iov[1].iov_len; -} - -/* - * Read from so's socket into sb_snd, updating all relevant sbuf fields - * NOTE: This will only be called if it is select()ed for reading, so - * a read() of 0 (or less) means it's disconnected - */ -int -soread(struct socket *so) -{ - int n, nn; - struct sbuf *sb = &so->so_snd; - struct iovec iov[2]; - - DEBUG_CALL("soread"); - DEBUG_ARG("so = %lx", (long )so); - - /* - * No need to check if there's enough room to read. - * soread wouldn't have been called if there weren't - */ - sopreprbuf(so, iov, &n); - -#ifdef HAVE_READV - nn = readv(so->s, (struct iovec *)iov, n); - DEBUG_MISC(" ... read nn = %d bytes\n", nn); -#else - nn = qemu_recv(so->s, iov[0].iov_base, iov[0].iov_len,0); -#endif - if (nn <= 0) { - if (nn < 0 && (errno == EINTR || errno == EAGAIN)) - return 0; - else { - DEBUG_MISC(" --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno)); - sofcantrcvmore(so); - tcp_sockclosed(sototcpcb(so)); - return -1; - } - } - -#ifndef HAVE_READV - /* - * 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 wont (shouldn't) happen, since it didn't happen above - */ - if (n == 2 && nn == iov[0].iov_len) { - int ret; - ret = qemu_recv(so->s, iov[1].iov_base, iov[1].iov_len,0); - if (ret > 0) - nn += ret; - } - - DEBUG_MISC(" ... read nn = %d bytes\n", nn); -#endif - - /* 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, size_t size) -{ - int n, nn, copy = size; - struct sbuf *sb = &so->so_snd; - struct iovec iov[2]; - - DEBUG_CALL("soreadbuf"); - DEBUG_ARG("so = %lx", (long )so); - - /* - * No need to check if there's enough room to read. - * soread wouldn't have been called if there weren't - */ - if (sopreprbuf(so, iov, &n) < size) - goto err; - - nn = MIN(iov[0].iov_len, copy); - memcpy(iov[0].iov_base, buf, nn); - - copy -= nn; - buf += nn; - - if (copy == 0) - goto done; - - memcpy(iov[1].iov_base, buf, copy); - -done: - /* Update fields */ - sb->sb_cc += size; - sb->sb_wptr += size; - if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) - sb->sb_wptr -= sb->sb_datalen; - return size; -err: - - sofcantrcvmore(so); - tcp_sockclosed(sototcpcb(so)); - fprintf(stderr, "soreadbuf buffer to 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 - */ -void -sorecvoob(struct socket *so) -{ - struct tcpcb *tp = sototcpcb(so); - - DEBUG_CALL("sorecvoob"); - DEBUG_ARG("so = %lx", (long)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. - */ - soread(so); - tp->snd_up = tp->snd_una + so->so_snd.sb_cc; - tp->t_force = 1; - tcp_output(tp); - tp->t_force = 0; -} - -/* - * 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, len; - - DEBUG_CALL("sosendoob"); - DEBUG_ARG("so = %lx", (long)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)); */ - so->so_urgc -= n; - - DEBUG_MISC(" --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc); - } else { - /* - * Since there's no sendv or sendtov like writev, - * we must copy all data to a linear buffer then - * send it all - */ - len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; - if (len > so->so_urgc) len = so->so_urgc; - memcpy(buff, sb->sb_rptr, len); - so->so_urgc -= len; - if (so->so_urgc) { - n = sb->sb_wptr - sb->sb_data; - if (n > so->so_urgc) n = so->so_urgc; - memcpy((buff + len), sb->sb_data, n); - so->so_urgc -= 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\n"); -#endif - DEBUG_MISC(" ---2 sent %d bytes urgent data, %d urgent bytes left\n", 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 = %lx", (long)so); - - if (so->so_urgc) { - (void)sosendoob(so); - 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 */ - -#ifdef HAVE_READV - nn = writev(so->s, (const struct iovec *)iov, n); - - DEBUG_MISC(" ... wrote nn = %d bytes\n", nn); -#else - nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0); -#endif - /* This should never happen, but people tell me it does *shrug* */ - if (nn < 0 && (errno == EAGAIN || errno == EINTR)) - return 0; - - if (nn <= 0) { - DEBUG_MISC(" --- sowrite disconnected, so->so_state = %x, errno = %d\n", - so->so_state, errno); - sofcantsendmore(so); - tcp_sockclosed(sototcpcb(so)); - return -1; - } - -#ifndef HAVE_READV - 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\n", nn); -#endif - - /* 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; -} - -/* - * recvfrom() a UDP socket - */ -void -sorecvfrom(struct socket *so) -{ - struct sockaddr_in addr; - socklen_t addrlen = sizeof(struct sockaddr_in); - - DEBUG_CALL("sorecvfrom"); - DEBUG_ARG("so = %lx", (long)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) { - u_char 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\n", - errno,strerror(errno)); - icmp_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; - u_int len; -#ifdef _WIN32 - unsigned long n; -#else - int n; -#endif - - m = m_get(so->slirp); - if (!m) { - return; - } - m->m_data += IF_MAXLINKHDR; - - /* - * XXX Shouldn't FIONREAD packets destined for port 53, - * but I don't know the max packet size for DNS lookups - */ - len = M_FREEROOM(m); - /* if (so->so_fport != htons(53)) { */ - ioctlsocket(so->s, FIONREAD, &n); - - if (n > len) { - n = (m->m_data - m->m_dat) + m->m_len + n + 1; - m_inc(m, n); - len = M_FREEROOM(m); - } - /* } */ - - m->m_len = recvfrom(so->s, m->m_data, len, 0, - (struct sockaddr *)&addr, &addrlen); - DEBUG_MISC(" did recvfrom %d, errno = %d-%s\n", - m->m_len, errno,strerror(errno)); - if(m->m_len<0) { - u_char 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\n", code); - icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); - 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, done by udp_output - */ - udp_output(so, m, &addr); - } /* rx error */ - } /* if ping packet */ -} - -/* - * sendto() a socket - */ -int -sosendto(struct socket *so, struct mbuf *m) -{ - Slirp *slirp = so->slirp; - int ret; - struct sockaddr_in addr; - - DEBUG_CALL("sosendto"); - DEBUG_ARG("so = %lx", (long)so); - DEBUG_ARG("m = %lx", (long)m); - - addr.sin_family = AF_INET; - if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == - slirp->vnetwork_addr.s_addr) { - /* It's an alias */ - if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) { - if (get_dns_addr(&addr.sin_addr) < 0) - addr.sin_addr = loopback_addr; - } else { - addr.sin_addr = loopback_addr; - } - } else - addr.sin_addr = so->so_faddr; - addr.sin_port = so->so_fport; - - DEBUG_MISC(" sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)); - - /* Don't care what port we get */ - ret = sendto(so->s, m->m_data, m->m_len, 0, - (struct sockaddr *)&addr, sizeof (struct sockaddr)); - 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, u_int hport, uint32_t laddr, - u_int lport, int flags) -{ - struct sockaddr_in addr; - struct socket *so; - int s, opt = 1; - socklen_t addrlen = sizeof(addr); - memset(&addr, 0, addrlen); - - DEBUG_CALL("tcp_listen"); - DEBUG_ARG("haddr = %x", haddr); - DEBUG_ARG("hport = %d", hport); - DEBUG_ARG("laddr = %x", laddr); - DEBUG_ARG("lport = %d", lport); - DEBUG_ARG("flags = %x", flags); - - so = socreate(slirp); - if (!so) { - return NULL; - } - - /* Don't tcp_attach... we don't need so_snd nor so_rcv */ - if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) { - 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_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 = qemu_socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR) || - (socket_set_fast_reuse(s) == SOCKET_ERROR) || - (bind(s,(struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) || - (listen(s,1) == SOCKET_ERROR)) { - int tmperrno = errno; /* Don't clobber the real reason we failed */ - - if (s != SOCKET_ERROR) - closesocket(s); - sofree(so); - fprintf (stderr, "Socket Error %d", tmperrno); - /* Restore the real errno */ -#ifdef _WIN32 - WSASetLastError(tmperrno); -#else - errno = tmperrno; -#endif - return NULL; - } - (void)qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); - - (void)getsockname(s,(struct sockaddr *)&addr,&addrlen); - 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); -} diff --git a/slirp/socket.h b/slirp/socket.h deleted file mode 100644 index e737bdc88..000000000 --- a/slirp/socket.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#ifndef _SLIRP_SOCKET_H_ -#define _SLIRP_SOCKET_H_ - -#define SO_EXPIRE 240000 -#define SO_EXPIREFAST 10000 - -/* - * Our socket structure - */ - -struct socket { - struct socket *so_next,*so_prev; /* For a linked list of sockets */ - - int s; /* The actual socket */ - - 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 */ - int so_urgc; - struct in_addr so_faddr; /* foreign host table entry */ - struct in_addr so_laddr; /* local host table entry */ - uint16_t so_fport; /* foreign port */ - uint16_t so_lport; /* local port */ - - uint8_t so_iptos; /* Type of service */ - uint8_t so_emu; /* Is the socket emulated? */ - - u_char so_type; /* Type of socket, UDP or TCP */ - int so_state; /* internal state flags SS_*, below */ - - struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */ - u_int 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 */ - void * extra; /* Extra pointer */ -}; - - -/* - * 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 */ - -struct socket * solookup(struct socket *, struct in_addr, u_int, struct in_addr, u_int); -struct socket * socreate(Slirp *); -void sofree(struct socket *); -int soread(struct socket *); -void 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, u_int, uint32_t, u_int, - 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, size_t size); - -#endif /* _SOCKET_H_ */ diff --git a/slirp/tcp.h b/slirp/tcp.h deleted file mode 100644 index 22f1c8a55..000000000 --- a/slirp/tcp.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcp.h 8.1 (Berkeley) 6/10/93 - * tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp - */ - -#ifndef _TCP_H_ -#define _TCP_H_ - -typedef uint32_t tcp_seq; - -#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */ -#define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */ - -#define TCP_SNDSPACE 8192 -#define TCP_RCVSPACE 8192 - -/* - * TCP header. - * Per RFC 793, September, 1981. - */ -#define tcphdr slirp_tcphdr -struct tcphdr { - uint16_t th_sport; /* source port */ - uint16_t th_dport; /* destination port */ - tcp_seq th_seq; /* sequence number */ - tcp_seq th_ack; /* acknowledgement number */ -#ifdef HOST_WORDS_BIGENDIAN - uint8_t th_off:4, /* data offset */ - th_x2:4; /* (unused) */ -#else - uint8_t th_x2:4, /* (unused) */ - th_off:4; /* data offset */ -#endif - uint8_t th_flags; - uint16_t th_win; /* window */ - uint16_t th_sum; /* checksum */ - uint16_t th_urp; /* urgent pointer */ -}; - -#include "tcp_var.h" - -#ifndef TH_FIN -#define TH_FIN 0x01 -#define TH_SYN 0x02 -#define TH_RST 0x04 -#define TH_PUSH 0x08 -#define TH_ACK 0x10 -#define TH_URG 0x20 -#endif - -#ifndef TCPOPT_EOL -#define TCPOPT_EOL 0 -#define TCPOPT_NOP 1 -#define TCPOPT_MAXSEG 2 -#define TCPOPT_WINDOW 3 -#define TCPOPT_SACK_PERMITTED 4 /* Experimental */ -#define TCPOPT_SACK 5 /* Experimental */ -#define TCPOPT_TIMESTAMP 8 - -#define TCPOPT_TSTAMP_HDR \ - (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) -#endif - -#ifndef TCPOLEN_MAXSEG -#define TCPOLEN_MAXSEG 4 -#define TCPOLEN_WINDOW 3 -#define TCPOLEN_SACK_PERMITTED 2 -#define TCPOLEN_TIMESTAMP 10 -#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ -#endif - -/* - * Default maximum segment size for TCP. - * With an IP MSS of 576, this is 536, - * but 512 is probably more convenient. - * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)). - * - * We make this 1460 because we only care about Ethernet in the qemu context. - */ -#undef TCP_MSS -#define TCP_MSS 1460 - -#undef TCP_MAXWIN -#define TCP_MAXWIN 65535u /* largest value for (unscaled) window */ - -#undef TCP_MAX_WINSHIFT -#define TCP_MAX_WINSHIFT 14 /* maximum window shift */ - -/* - * User-settable options (used with setsockopt). - * - * We don't use the system headers on unix because we have conflicting - * local structures. We can't avoid the system definitions on Windows, - * so we undefine them. - */ -#undef TCP_NODELAY -#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ -#undef TCP_MAXSEG - -/* - * TCP FSM state definitions. - * Per RFC793, September, 1981. - */ - -#define TCP_NSTATES 11 - -#define TCPS_CLOSED 0 /* closed */ -#define TCPS_LISTEN 1 /* listening for connection */ -#define TCPS_SYN_SENT 2 /* active, have sent syn */ -#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ -/* states < TCPS_ESTABLISHED are those where connections not established */ -#define TCPS_ESTABLISHED 4 /* established */ -#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ -/* states > TCPS_CLOSE_WAIT are those where user has closed */ -#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ -#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ -#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ -/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ -#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ -#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ - -#define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) -#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) -#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) - -/* - * TCP sequence numbers are 32 bit integers operated - * on with modular arithmetic. These macros can be - * used to compare such integers. - */ -#define SEQ_LT(a,b) ((int)((a)-(b)) < 0) -#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) -#define SEQ_GT(a,b) ((int)((a)-(b)) > 0) -#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) - -/* - * Macros to initialize tcp sequence numbers for - * send and receive from initial send and receive - * sequence numbers. - */ -#define tcp_rcvseqinit(tp) \ - (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1 - -#define tcp_sendseqinit(tp) \ - (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss - -#define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */ - -#endif diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c deleted file mode 100644 index 11abaf7ab..000000000 --- a/slirp/tcp_input.c +++ /dev/null @@ -1,1496 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcp_input.c 8.5 (Berkeley) 4/10/94 - * tcp_input.c,v 1.10 1994/10/13 18:36:32 wollman Exp - */ - -/* - * Changes and additions relating to SLiRP - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#include -#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). - */ -#ifdef TCP_ACK_HACK -#define TCP_REASS(tp, ti, m, so, flags) {\ - if ((ti)->ti_seq == (tp)->rcv_nxt && \ - tcpfrag_list_empty(tp) && \ - (tp)->t_state == TCPS_ESTABLISHED) {\ - if (ti->ti_flags & TH_PUSH) \ - tp->t_flags |= TF_ACKNOW; \ - else \ - 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; \ - } \ -} -#else -#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; \ - } \ -} -#endif -static void tcp_dooptions(struct tcpcb *tp, u_char *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) -{ - struct ip save_ip, *ip; - register struct tcpiphdr *ti; - caddr_t 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; - u_long tiwin; - int ret; - struct ex_list *ex_ptr; - Slirp *slirp; - - DEBUG_CALL("tcp_input"); - DEBUG_ARGS(" m = %8lx iphlen = %2d inso = %lx\n", - (long )m, iphlen, (long )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; - - /* - * Get IP and TCP header together in first mbuf. - * Note: IP leaves IP header in first mbuf. - */ - ti = mtod(m, struct tcpiphdr *); - 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. - */ - ip=mtod(m, struct ip *); - save_ip = *ip; - save_ip.ip_len+= iphlen; - - /* - * Checksum extended TCP header and data. - */ - tlen = ((struct ip *)ti)->ip_len; - tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL; - memset(&ti->ti_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr)); - ti->ti_x1 = 0; - ti->ti_len = htons((uint16_t)tlen); - len = sizeof(struct ip ) + 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, caddr_t) + 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: - so = slirp->tcp_last_so; - if (so->so_fport != ti->ti_dport || - so->so_lport != ti->ti_sport || - so->so_laddr.s_addr != ti->ti_src.s_addr || - so->so_faddr.s_addr != ti->ti_dst.s_addr) { - so = solookup(&slirp->tcb, ti->ti_src, ti->ti_sport, - ti->ti_dst, ti->ti_dport); - if (so) - slirp->tcp_last_so = so; - } - - /* - * If the state is CLOSED (i.e., TCB does not exist) then - * all data in the incoming segment is discarded. - * If the TCB exists but is in CLOSED state, it is embryonic, - * but should either do a listen or a connect soon. - * - * state == CLOSED means we've done socreate() but haven't - * attached it to a protocol yet... - * - * XXX If a TCB does not exist, and the TH_SYN flag is - * the only flag set, then create a session, mark it - * as if it was LISTENING, and continue... - */ - if (so == NULL) { - if (slirp->restricted) { - /* Any hostfwds will have an existing socket, so we only get here - * for non-hostfwd connections. These should be dropped, unless it - * happens to be a guestfwd. - */ - for (ex_ptr = slirp->exec_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; - - if ((so = socreate(slirp)) == NULL) - goto dropwithreset; - if (tcp_attach(so) < 0) { - free(so); /* Not sofree (if it failed, it's not insqued) */ - goto dropwithreset; - } - - sbreserve(&so->so_snd, TCP_SNDSPACE); - sbreserve(&so->so_rcv, TCP_RCVSPACE); - - so->so_laddr = ti->ti_src; - so->so_lport = ti->ti_sport; - so->so_faddr = ti->ti_dst; - so->so_fport = ti->ti_dport; - - if ((so->so_iptos = tcp_tos(so)) == 0) - so->so_iptos = ((struct ip *)ti)->ip_tos; - - 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 (SO_OPTIONS) - 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, (u_char *)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; - sbdrop(&so->so_snd, 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 - */ - if ((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->exec_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) == -1) && -#if defined(_WIN32) - socket_error() != WSAEINPROGRESS && socket_error() != WSAEWOULDBLOCK -#else - (errno != EINPROGRESS) && (errno != EWOULDBLOCK) -#endif - ) { - u_char code=ICMP_UNREACH_NET; - DEBUG_MISC(" tcp fconnect errno = %d-%s\n", - 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); - } else { - if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; - 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); - *ip=save_ip; - icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno)); - } - 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; - 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, (u_char *)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 = %lx so = %lx\n", - (long )m, (long )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; - u_int 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 u_int cw = tp->snd_cwnd; - register u_int incr = tp->t_maxseg; - - if (cw > tp->snd_ssthresh) - incr = incr * incr / cw; - tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<snd_scale); - } - if (acked > (int)so->so_snd.sb_cc) { - tp->snd_wnd -= so->so_snd.sb_cc; - sbdrop(&so->so_snd, (int )so->so_snd.sb_cc); - ourfinisacked = 1; - } else { - sbdrop(&so->so_snd, 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); - 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); - } - - return; - -drop: - /* - * Drop space held by incoming segment and return. - */ - m_free(m); -} - -static void -tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcpiphdr *ti) -{ - uint16_t mss; - int opt, optlen; - - DEBUG_CALL("tcp_dooptions"); - DEBUG_ARGS(" tp = %lx cnt=%i\n", (long)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; - } - } -} - - -/* - * Pull out of band byte out of a segment so - * it doesn't appear in the user's data queue. - * It is still reflected in the segment length for - * sequencing purposes. - */ - -#ifdef notdef - -void -tcp_pulloutofband(so, ti, m) - struct socket *so; - struct tcpiphdr *ti; - register struct mbuf *m; -{ - int cnt = ti->ti_urp - 1; - - while (cnt >= 0) { - if (m->m_len > cnt) { - char *cp = mtod(m, caddr_t) + cnt; - struct tcpcb *tp = sototcpcb(so); - - tp->t_iobc = *cp; - tp->t_oobflags |= TCPOOB_HAVEDATA; - memcpy(sp, cp+1, (unsigned)(m->m_len - cnt - 1)); - m->m_len--; - return; - } - cnt -= m->m_len; - m = m->m_next; /* XXX WRONG! Fix it! */ - if (m == 0) - break; - } - panic("tcp_pulloutofband"); -} - -#endif /* notdef */ - -/* - * 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 = %lx", (long)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, u_int offer) -{ - struct socket *so = tp->t_socket; - u_int mss; - - DEBUG_CALL("tcp_mss"); - DEBUG_ARG("tp = %lx", (long)tp); - DEBUG_ARG("offer = %d", offer); - - mss = min(IF_MTU, IF_MRU) - sizeof(struct tcpiphdr); - if (offer) - mss = min(mss, offer); - mss = max(mss, 32); - if (mss < tp->t_maxseg || offer != 0) - tp->t_maxseg = mss; - - tp->snd_cwnd = mss; - - sbreserve(&so->so_snd, TCP_SNDSPACE + ((TCP_SNDSPACE % mss) ? - (mss - (TCP_SNDSPACE % mss)) : - 0)); - sbreserve(&so->so_rcv, TCP_RCVSPACE + ((TCP_RCVSPACE % mss) ? - (mss - (TCP_RCVSPACE % mss)) : - 0)); - - DEBUG_MISC(" returning mss = %d\n", mss); - - return mss; -} diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c deleted file mode 100644 index 3c20b8b90..000000000 --- a/slirp/tcp_output.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1988, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcp_output.c 8.3 (Berkeley) 12/30/93 - * tcp_output.c,v 1.3 1994/09/15 10:36:55 davidg Exp - */ - -/* - * Changes and additions relating to SLiRP - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#include - -static const u_char 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; - u_char opt[MAX_TCPOPTLEN]; - unsigned optlen, hdrlen; - int idle, sendalot; - - DEBUG_CALL("tcp_output"); - DEBUG_ARG("tp = %lx", (long )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\n",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 < (int)so->so_snd.sb_cc) - flags &= ~TH_FIN; - win = 1; - } else { - tp->t_timer[TCPT_PERSIST] = 0; - tp->t_rxtshift = 0; - } - } - - len = min((long)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) >= (long)so->so_snd.sb_cc)) - goto send; - if (tp->t_force) - goto send; - if ((len >= (long)(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((caddr_t)(opt + 2), (caddr_t)&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 > (long)(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, caddr_t) + 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((caddr_t)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((caddr_t)(ti + 1), (caddr_t)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 */ - - { - - ((struct ip *)ti)->ip_len = m->m_len; - - ((struct ip *)ti)->ip_ttl = IPDEFTTL; - ((struct ip *)ti)->ip_tos = so->so_iptos; - - error = ip_output(so, m); - } - if (error) { -out: - return (error); - } - - /* - * Data sent (as far as we can tell). - * If this advertises a larger window than any other segment, - * then remember the size of the advertised window. - * Any pending ACK has now been sent. - */ - if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) - tp->rcv_adv = tp->rcv_nxt + win; - tp->last_ack_sent = tp->rcv_nxt; - tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); - if (sendalot) - goto again; - - return (0); -} - -void -tcp_setpersist(struct tcpcb *tp) -{ - int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; - - /* - * Start/restart persistence timer. - */ - TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], - t * tcp_backoff[tp->t_rxtshift], - TCPTV_PERSMIN, TCPTV_PERSMAX); - if (tp->t_rxtshift < TCP_MAXRXTSHIFT) - tp->t_rxtshift++; -} diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c deleted file mode 100644 index 8d25af8fa..000000000 --- a/slirp/tcp_subr.c +++ /dev/null @@ -1,926 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1988, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93 - * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp - */ - -/* - * Changes and additions relating to SLiRP - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#include - -/* 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; - n->ti_x1 = 0; - n->ti_pr = IPPROTO_TCP; - n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); - n->ti_src = so->so_faddr; - n->ti_dst = so->so_laddr; - n->ti_sport = so->so_fport; - n->ti_dport = so->so_lport; - - 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) -{ - 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 *); - flags = TH_ACK; - } else { - /* - * ti points into m so the next line is just making - * the mbuf point to ti - */ - m->m_data = (caddr_t)ti; - - m->m_len = sizeof (struct tcpiphdr); - tlen = 0; -#define xchg(a,b,type) { type t; t=a; a=b; b=t; } - xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32_t); - xchg(ti->ti_dport, ti->ti_sport, uint16_t); -#undef xchg - } - ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); - tlen += sizeof (struct tcpiphdr); - m->m_len = tlen; - - ti->ti_mbuf = NULL; - ti->ti_x1 = 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 ip *)ti)->ip_len = tlen; - - if(flags & TH_RST) - ((struct ip *)ti)->ip_ttl = MAXTTL; - else - ((struct ip *)ti)->ip_ttl = IPDEFTTL; - - (void) ip_output((struct socket *)0, m); -} - -/* - * Create a new TCP control block, making an - * empty reassembly queue and hooking it to the argument - * protocol control block. - */ -struct tcpcb * -tcp_newtcpcb(struct socket *so) -{ - register struct tcpcb *tp; - - tp = (struct tcpcb *)malloc(sizeof(*tp)); - if (tp == NULL) - return ((struct tcpcb *)0); - - memset((char *) tp, 0, sizeof(struct tcpcb)); - tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp; - tp->t_maxseg = TCP_MSS; - - tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; - tp->t_socket = so; - - /* - * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no - * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives - * reasonable initial retransmit time. - */ - tp->t_srtt = TCPTV_SRTTBASE; - tp->t_rttvar = TCPTV_SRTTDFLT << 2; - tp->t_rttmin = TCPTV_MIN; - - TCPT_RANGESET(tp->t_rxtcur, - ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, - TCPTV_MIN, TCPTV_REXMTMAX); - - tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; - tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; - tp->t_state = TCPS_CLOSED; - - so->so_tcpcb = tp; - - return (tp); -} - -/* - * Drop a TCP connection, reporting - * the specified error. If connection is synchronized, - * then send a RST to peer. - */ -struct tcpcb *tcp_drop(struct tcpcb *tp, int err) -{ - DEBUG_CALL("tcp_drop"); - DEBUG_ARG("tp = %lx", (long)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 = %lx", (long )tp); - - /* free the reassembly queue, if any */ - t = tcpfrag_list_first(tp); - while (!tcpfrag_list_end(t, tp)) { - t = tcpiphdr_next(t); - m = tcpiphdr_prev(t)->ti_mbuf; - remque(tcpiphdr2qlink(tcpiphdr_prev(t))); - m_free(m); - } - free(tp); - so->so_tcpcb = NULL; - /* clobber input socket cache if we're closing the cached connection */ - if (so == slirp->tcp_last_so) - slirp->tcp_last_so = &slirp->tcb; - 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 = %lx", (long)tp); - - switch (tp->t_state) { - - case TCPS_CLOSED: - case TCPS_LISTEN: - case TCPS_SYN_SENT: - tp->t_state = TCPS_CLOSED; - tp = tcp_close(tp); - break; - - case TCPS_SYN_RECEIVED: - case TCPS_ESTABLISHED: - tp->t_state = TCPS_FIN_WAIT_1; - break; - - case TCPS_CLOSE_WAIT: - tp->t_state = TCPS_LAST_ACK; - break; - } - if (tp) - 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) -{ - Slirp *slirp = so->slirp; - int ret=0; - - DEBUG_CALL("tcp_fconnect"); - DEBUG_ARG("so = %lx", (long )so); - - if( (ret = so->s = qemu_socket(AF_INET,SOCK_STREAM,0)) >= 0) { - int opt, s=so->s; - struct sockaddr_in addr; - - (void)qemu_set_nonblock(s); - socket_set_fast_reuse(s); - opt = 1; - (void)qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt)); - - addr.sin_family = AF_INET; - if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == - slirp->vnetwork_addr.s_addr) { - /* It's an alias */ - if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) { - if (get_dns_addr(&addr.sin_addr) < 0) - addr.sin_addr = loopback_addr; - } else { - addr.sin_addr = loopback_addr; - } - } else - addr.sin_addr = so->so_faddr; - addr.sin_port = so->so_fport; - - DEBUG_MISC(" connect()ing, addr.sin_port=%d, " - "addr.sin_addr.s_addr=%.16s\n", - ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)); - /* We don't care what port we get */ - ret = connect(s,(struct sockaddr *)&addr,sizeof (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_in addr; - socklen_t addrlen = sizeof(struct sockaddr_in); - struct tcpcb *tp; - int s, opt; - - DEBUG_CALL("tcp_connect"); - DEBUG_ARG("inso = %lx", (long)inso); - - /* - * If it's an SS_ACCEPTONCE socket, no need to socreate() - * another socket, just use the accept() socket. - */ - if (inso->so_state & SS_FACCEPTONCE) { - /* FACCEPTONCE already have a tcpcb */ - so = inso; - } else { - so = socreate(slirp); - if (so == NULL) { - /* If it failed, get rid of the pending connection */ - closesocket(accept(inso->s, (struct sockaddr *)&addr, &addrlen)); - return; - } - if (tcp_attach(so) < 0) { - free(so); /* NOT sofree */ - return; - } - so->so_laddr = inso->so_laddr; - so->so_lport = inso->so_lport; - } - - 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; - } - qemu_set_nonblock(s); - (void)socket_set_fast_reuse(s); - opt = 1; - (void)qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); - (void)socket_set_nodelay(s); - - so->so_fport = addr.sin_port; - so->so_faddr = addr.sin_addr; - /* Translate connections from localhost to the real hostname */ - if (so->so_faddr.s_addr == 0 || - (so->so_faddr.s_addr & loopback_mask) == - (loopback_addr.s_addr & loopback_mask)) { - so->so_faddr = slirp->vhost_addr; - } - - /* Close the accept() socket, set right state */ - if (inso->so_state & SS_FACCEPTONCE) { - /* If we only accept once, close the accept() socket */ - closesocket(so->s); - - /* Don't select it yet, even though we have an FD */ - /* if it's not FACCEPTONCE, it's already NOFDREF */ - so->so_state = SS_NOFDREF; - } - so->s = s; - so->so_state |= SS_INCOMING; - - so->so_iptos = tcp_tos(so); - tp = sototcpcb(so); - - tcp_template(tp); - - tp->t_state = TCPS_SYN_SENT; - tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; - tp->iss = slirp->tcp_iss; - slirp->tcp_iss += TCP_ISSINCR/2; - tcp_sendseqinit(tp); - tcp_output(tp); -} - -/* - * Attach a TCPCB to a socket. - */ -int -tcp_attach(struct socket *so) -{ - if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) - return -1; - - insque(so, &so->slirp->tcb); - - return 0; -} - -/* - * Set the socket's type of service field - */ -static const struct tos_t tcptos[] = { - {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */ - {21, 21, IPTOS_LOWDELAY, EMU_FTP}, /* ftp control */ - {0, 23, IPTOS_LOWDELAY, 0}, /* telnet */ - {0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */ - {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT}, /* rlogin */ - {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT}, /* shell */ - {0, 544, IPTOS_LOWDELAY, EMU_KSH}, /* kshell */ - {0, 543, IPTOS_LOWDELAY, 0}, /* klogin */ - {0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */ - {0, 6668, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC undernet */ - {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */ - {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */ - {0, 0, 0, 0} -}; - -static struct emu_t *tcpemu = NULL; - -/* - * Return TOS according to the above table - */ -uint8_t -tcp_tos(struct socket *so) -{ - int i = 0; - struct emu_t *emup; - - while(tcptos[i].tos) { - if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) || - (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) { - so->so_emu = tcptos[i].emu; - return tcptos[i].tos; - } - i++; - } - - /* Nope, lets see if there's a user-added one */ - for (emup = tcpemu; emup; emup = emup->next) { - if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) || - (emup->lport && (ntohs(so->so_lport) == emup->lport))) { - so->so_emu = emup->emu; - return emup->tos; - } - } - - return 0; -} - -/* - * Emulate programs that try and connect to us - * This includes ftp (the data connection is - * initiated by the server) and IRC (DCC CHAT and - * DCC SEND) for now - * - * NOTE: It's possible to crash SLiRP by sending it - * unstandard strings to emulate... if this is a problem, - * more checks are needed here - * - * XXX Assumes the whole command came in one packet - * - * XXX Some ftp clients will have their TOS set to - * LOWDELAY and so Nagel will kick in. Because of this, - * we'll get the first letter, followed by the rest, so - * we simply scan for ORT instead of PORT... - * DCC doesn't have this problem because there's other stuff - * in the packet before the DCC command. - * - * Return 1 if the mbuf m is still valid and should be - * sbappend()ed - * - * NOTE: if you return 0 you MUST m_free() the mbuf! - */ -int -tcp_emu(struct socket *so, struct mbuf *m) -{ - Slirp *slirp = so->slirp; - u_int n1, n2, n3, n4, n5, n6; - char buff[257]; - uint32_t laddr; - u_int lport; - char *bptr; - - DEBUG_CALL("tcp_emu"); - DEBUG_ARG("so = %lx", (long)so); - DEBUG_ARG("m = %lx", (long)m); - - switch(so->so_emu) { - int x, i; - - case EMU_IDENT: - /* - * Identification protocol as per rfc-1413 - */ - - { - struct socket *tmpso; - struct sockaddr_in addr; - socklen_t addrlen = sizeof(struct sockaddr_in); - struct sbuf *so_rcv = &so->so_rcv; - - memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); - so_rcv->sb_wptr += m->m_len; - so_rcv->sb_rptr += m->m_len; - m->m_data[m->m_len] = 0; /* NULL terminate */ - if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) { - if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) { - HTONS(n1); - HTONS(n2); - /* n2 is the one on our host */ - for (tmpso = slirp->tcb.so_next; - tmpso != &slirp->tcb; - tmpso = tmpso->so_next) { - if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr && - tmpso->so_lport == n2 && - tmpso->so_faddr.s_addr == so->so_faddr.s_addr && - tmpso->so_fport == n1) { - if (getsockname(tmpso->s, - (struct sockaddr *)&addr, &addrlen) == 0) - n2 = ntohs(addr.sin_port); - break; - } - } - } - so_rcv->sb_cc = snprintf(so_rcv->sb_data, - so_rcv->sb_datalen, - "%d,%d\r\n", n1, n2); - so_rcv->sb_rptr = so_rcv->sb_data; - so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; - } - m_free(m); - return 0; - } - - case EMU_FTP: /* ftp */ - *(m->m_data+m->m_len) = 0; /* NUL terminate for strstr */ - if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) { - /* - * Need to emulate the PORT command - */ - x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]", - &n1, &n2, &n3, &n4, &n5, &n6, buff); - if (x < 6) - return 1; - - laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); - lport = htons((n5 << 8) | (n6)); - - if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr, - lport, SS_FACCEPTONCE)) == NULL) { - return 1; - } - n6 = ntohs(so->so_fport); - - n5 = (n6 >> 8) & 0xff; - n6 &= 0xff; - - laddr = ntohl(so->so_faddr.s_addr); - - n1 = ((laddr >> 24) & 0xff); - n2 = ((laddr >> 16) & 0xff); - n3 = ((laddr >> 8) & 0xff); - n4 = (laddr & 0xff); - - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += snprintf(bptr, m->m_size - m->m_len, - "ORT %d,%d,%d,%d,%d,%d\r\n%s", - n1, n2, n3, n4, n5, n6, x==7?buff:""); - return 1; - } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) { - /* - * Need to emulate the PASV response - */ - x = sscanf(bptr, "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]", - &n1, &n2, &n3, &n4, &n5, &n6, buff); - if (x < 6) - return 1; - - laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); - lport = htons((n5 << 8) | (n6)); - - if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr, - lport, SS_FACCEPTONCE)) == NULL) { - return 1; - } - n6 = ntohs(so->so_fport); - - n5 = (n6 >> 8) & 0xff; - n6 &= 0xff; - - laddr = ntohl(so->so_faddr.s_addr); - - n1 = ((laddr >> 24) & 0xff); - n2 = ((laddr >> 16) & 0xff); - n3 = ((laddr >> 8) & 0xff); - n4 = (laddr & 0xff); - - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += snprintf(bptr, m->m_size - m->m_len, - "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", - n1, n2, n3, n4, n5, n6, x==7?buff:""); - - return 1; - } - - return 1; - - case EMU_KSH: - /* - * The kshell (Kerberos rsh) and shell services both pass - * a local port port number to carry signals to the server - * and stderr to the client. It is passed at the beginning - * of the connection as a NUL-terminated decimal ASCII string. - */ - so->so_emu = 0; - for (lport = 0, i = 0; i < m->m_len-1; ++i) { - if (m->m_data[i] < '0' || m->m_data[i] > '9') - return 1; /* invalid number */ - lport *= 10; - lport += m->m_data[i] - '0'; - } - if (m->m_data[m->m_len-1] == '\0' && lport != 0 && - (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr, - htons(lport), SS_FACCEPTONCE)) != NULL) - m->m_len = snprintf(m->m_data, m->m_size, "%d", - ntohs(so->so_fport)) + 1; - return 1; - - case EMU_IRC: - /* - * Need to emulate DCC CHAT, DCC SEND and DCC MOVE - */ - *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */ - if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL) - return 1; - - /* The %256s is for the broken mIRC */ - if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) { - if ((so = tcp_listen(slirp, INADDR_ANY, 0, - htonl(laddr), htons(lport), - SS_FACCEPTONCE)) == NULL) { - return 1; - } - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += snprintf(bptr, m->m_size, - "DCC CHAT chat %lu %u%c\n", - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), 1); - } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { - if ((so = tcp_listen(slirp, INADDR_ANY, 0, - htonl(laddr), htons(lport), - SS_FACCEPTONCE)) == NULL) { - return 1; - } - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += snprintf(bptr, m->m_size, - "DCC SEND %s %lu %u %u%c\n", buff, - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); - } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { - if ((so = tcp_listen(slirp, INADDR_ANY, 0, - htonl(laddr), htons(lport), - SS_FACCEPTONCE)) == NULL) { - return 1; - } - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += snprintf(bptr, m->m_size, - "DCC MOVE %s %lu %u %u%c\n", buff, - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); - } - return 1; - - case EMU_REALAUDIO: - /* - * RealAudio emulation - JP. We must try to parse the incoming - * data and try to find the two characters that contain the - * port number. Then we redirect an udp port and replace the - * number with the real port we got. - * - * The 1.0 beta versions of the player are not supported - * any more. - * - * A typical packet for player version 1.0 (release version): - * - * 0000:50 4E 41 00 05 - * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 ........g.l.c..P - * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH - * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v - * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB - * - * Now the port number 0x1BD7 is found at offset 0x04 of the - * Now the port number 0x1BD7 is found at offset 0x04 of the - * second packet. This time we received five bytes first and - * then the rest. You never know how many bytes you get. - * - * A typical packet for player version 2.0 (beta): - * - * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA............. - * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .gux.c..Win2.0.0 - * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/ - * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas - * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B - * - * Port number 0x1BC1 is found at offset 0x0d. - * - * This is just a horrible switch statement. Variable ra tells - * us where we're going. - */ - - bptr = m->m_data; - while (bptr < m->m_data + m->m_len) { - u_short p; - static int ra = 0; - char ra_tbl[4]; - - ra_tbl[0] = 0x50; - ra_tbl[1] = 0x4e; - ra_tbl[2] = 0x41; - ra_tbl[3] = 0; - - switch (ra) { - case 0: - case 2: - case 3: - if (*bptr++ != ra_tbl[ra]) { - ra = 0; - continue; - } - break; - - case 1: - /* - * We may get 0x50 several times, ignore them - */ - if (*bptr == 0x50) { - ra = 1; - bptr++; - continue; - } else if (*bptr++ != ra_tbl[ra]) { - ra = 0; - continue; - } - break; - - case 4: - /* - * skip version number - */ - bptr++; - break; - - case 5: - /* - * The difference between versions 1.0 and - * 2.0 is here. For future versions of - * the player this may need to be modified. - */ - if (*(bptr + 1) == 0x02) - bptr += 8; - else - bptr += 4; - break; - - case 6: - /* This is the field containing the port - * number that RA-player is listening to. - */ - lport = (((u_char*)bptr)[0] << 8) - + ((u_char *)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; - *(u_char *)bptr++ = (p >> 8) & 0xff; - *(u_char *)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 ex_list *ex_ptr; - int do_pty; - - DEBUG_CALL("tcp_ctl"); - DEBUG_ARG("so = %lx", (long )so); - - if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr) { - /* Check if it's pty_exec */ - for (ex_ptr = slirp->exec_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->ex_pty == 3) { - so->s = -1; - so->extra = (void *)ex_ptr->ex_exec; - return 1; - } - do_pty = ex_ptr->ex_pty; - DEBUG_MISC(" executing %s\n", ex_ptr->ex_exec); - return fork_exec(so, ex_ptr->ex_exec, do_pty); - } - } - } - sb->sb_cc = - snprintf(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data), - "Error: No application configured.\r\n"); - sb->sb_wptr += sb->sb_cc; - return 0; -} diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c deleted file mode 100644 index 9917b5043..000000000 --- a/slirp/tcp_timer.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1988, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcp_timer.c 8.1 (Berkeley) 6/10/93 - * tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp - */ - -#include - -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.) - */ - { - u_int 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 ((SO_OPTIONS) && 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_timer[TCPT_KEEP] = TCPTV_KEEPINTVL; - } else - tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE; - break; - - dropit: - tp = tcp_drop(tp, 0); - break; - } - - return (tp); -} diff --git a/slirp/tcp_timer.h b/slirp/tcp_timer.h deleted file mode 100644 index 7b155ef9b..000000000 --- a/slirp/tcp_timer.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93 - * tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp - */ - -#ifndef _TCP_TIMER_H_ -#define _TCP_TIMER_H_ - -/* - * Definitions of the TCP timers. These timers are counted - * down PR_SLOWHZ times a second. - */ -#define TCPT_NTIMERS 4 - -#define TCPT_REXMT 0 /* retransmit */ -#define TCPT_PERSIST 1 /* retransmit persistence */ -#define TCPT_KEEP 2 /* keep alive */ -#define TCPT_2MSL 3 /* 2*msl quiet time timer */ - -/* - * The TCPT_REXMT timer is used to force retransmissions. - * The TCP has the TCPT_REXMT timer set whenever segments - * have been sent for which ACKs are expected but not yet - * received. If an ACK is received which advances tp->snd_una, - * then the retransmit timer is cleared (if there are no more - * outstanding segments) or reset to the base value (if there - * are more ACKs expected). Whenever the retransmit timer goes off, - * we retransmit one unacknowledged segment, and do a backoff - * on the retransmit timer. - * - * The TCPT_PERSIST timer is used to keep window size information - * flowing even if the window goes shut. If all previous transmissions - * have been acknowledged (so that there are no retransmissions in progress), - * and the window is too small to bother sending anything, then we start - * the TCPT_PERSIST timer. When it expires, if the window is nonzero, - * we go to transmit state. Otherwise, at intervals send a single byte - * into the peer's window to force him to update our window information. - * We do this at most as often as TCPT_PERSMIN time intervals, - * but no more frequently than the current estimate of round-trip - * packet time. The TCPT_PERSIST timer is cleared whenever we receive - * a window update from the peer. - * - * The TCPT_KEEP timer is used to keep connections alive. If an - * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time, - * but not yet established, then we drop the connection. Once the connection - * is established, if the connection is idle for TCPTV_KEEP_IDLE time - * (and keepalives have been enabled on the socket), we begin to probe - * the connection. We force the peer to send us a segment by sending: - * - * This segment is (deliberately) outside the window, and should elicit - * an ack segment in response from the peer. If, despite the TCPT_KEEP - * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE - * amount of time probing, then we drop the connection. - */ - -/* - * Time constants. - */ -#define TCPTV_MSL ( 5*PR_SLOWHZ) /* max seg lifetime (hah!) */ - -#define TCPTV_SRTTBASE 0 /* base roundtrip time; - if 0, no idea yet */ -#define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */ - -#define TCPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistence */ -#define TCPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */ - -#define TCPTV_KEEP_INIT ( 75*PR_SLOWHZ) /* initial connect keep alive */ -#define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */ -#define TCPTV_KEEPINTVL ( 75*PR_SLOWHZ) /* default probe interval */ -#define TCPTV_KEEPCNT 8 /* max probes before drop */ - -#define TCPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */ -#define TCPTV_REXMTMAX ( 12*PR_SLOWHZ) /* max allowable REXMT value */ - -#define TCP_LINGERTIME 120 /* linger at most 2 minutes */ - -#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ - - -/* - * Force a time value to be in a certain range. - */ -#define TCPT_RANGESET(tv, value, tvmin, tvmax) { \ - (tv) = (value); \ - if ((tv) < (tvmin)) \ - (tv) = (tvmin); \ - else if ((tv) > (tvmax)) \ - (tv) = (tvmax); \ -} - -extern const int tcp_backoff[]; - -struct tcpcb; - -void tcp_fasttimo(Slirp *); -void tcp_slowtimo(Slirp *); -void tcp_canceltimers(struct tcpcb *); - -#endif diff --git a/slirp/tcp_var.h b/slirp/tcp_var.h deleted file mode 100644 index ab3459fbc..000000000 --- a/slirp/tcp_var.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcp_var.h 8.3 (Berkeley) 4/10/94 - * tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp - */ - -#ifndef _TCP_VAR_H_ -#define _TCP_VAR_H_ - -#include "tcpip.h" -#include "tcp_timer.h" - -/* - * Tcp control block, one per tcp; fields: - */ -struct tcpcb { - struct tcpiphdr *seg_next; /* sequencing queue */ - struct tcpiphdr *seg_prev; - short t_state; /* state of this connection */ - short t_timer[TCPT_NTIMERS]; /* tcp timers */ - short t_rxtshift; /* log(2) of rexmt exp. backoff */ - short t_rxtcur; /* current retransmit value */ - short t_dupacks; /* consecutive dup acks recd */ - u_short t_maxseg; /* maximum segment size */ - char t_force; /* 1 if forcing out a byte */ - u_short 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 */ - u_short t_rttmin; /* minimum rtt allowed */ - uint32_t max_sndwnd; /* largest window peer has offered */ - -/* out-of-band data */ - char t_oobflags; /* have some */ - char t_iobc; /* input character */ -#define TCPOOB_HAVEDATA 0x01 -#define TCPOOB_HADDATA 0x02 - short t_softerror; /* possible error not yet reported */ - -/* RFC 1323 variables */ - u_char snd_scale; /* window scaling for send window */ - u_char rcv_scale; /* window scaling for recv window */ - u_char request_r_scale; /* pending window scaling */ - u_char requested_s_scale; - uint32_t ts_recent; /* timestamp echo data */ - uint32_t ts_recent_age; /* when last updated */ - tcp_seq last_ack_sent; - -}; - -#define sototcpcb(so) ((so)->so_tcpcb) - -/* - * The smoothed round-trip time and estimated variance - * are stored as fixed point numbers scaled by the values below. - * For convenience, these scales are also used in smoothing the average - * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed). - * With these scales, srtt has 3 bits to the right of the binary point, - * and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the - * binary point, and is smoothed with an ALPHA of 0.75. - */ -#define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */ -#define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */ -#define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */ -#define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */ - -/* - * The initial retransmission should happen at rtt + 4 * rttvar. - * Because of the way we do the smoothing, srtt and rttvar - * will each average +1/2 tick of bias. When we compute - * the retransmit timer, we want 1/2 tick of rounding and - * 1 extra tick because of +-1/2 tick uncertainty in the - * firing of the timer. The bias will give us exactly the - * 1.5 tick we need. But, because the bias is - * statistical, we have to test that we don't drop below - * the minimum feasible timer (which is 2 ticks). - * This macro assumes that the value of TCP_RTTVAR_SCALE - * is the same as the multiplier for rttvar. - */ -#define TCP_REXMTVAL(tp) \ - (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar) - -#endif diff --git a/slirp/tcpip.h b/slirp/tcpip.h deleted file mode 100644 index eb31a6acc..000000000 --- a/slirp/tcpip.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcpip.h 8.1 (Berkeley) 6/10/93 - * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp - */ - -#ifndef _TCPIP_H_ -#define _TCPIP_H_ - -/* - * Tcp+ip header, after ip options removed. - */ -struct tcpiphdr { - struct ipovly ti_i; /* overlaid ip structure */ - struct tcphdr ti_t; /* tcp header */ -}; -#define ti_mbuf ti_i.ih_mbuf.mptr -#define ti_x1 ti_i.ih_x1 -#define ti_pr ti_i.ih_pr -#define ti_len ti_i.ih_len -#define ti_src ti_i.ih_src -#define ti_dst ti_i.ih_dst -#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)) - -/* - * Just a clean way to get to the first byte - * of the packet - */ -struct tcpiphdr_2 { - struct tcpiphdr dummy; - char first_char; -}; - -#endif diff --git a/slirp/tftp.c b/slirp/tftp.c deleted file mode 100644 index 2d7d5a3d1..000000000 --- a/slirp/tftp.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - * 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 -#include "qemu-common.h" - -static inline int tftp_session_in_use(struct tftp_session *spt) -{ - return (spt->slirp != NULL); -} - -static inline void tftp_session_update(struct tftp_session *spt) -{ - spt->timestamp = curtime; -} - -static void tftp_session_terminate(struct tftp_session *spt) -{ - if (spt->f != NULL) { - fclose(spt->f); - spt->f = NULL; - } - g_free(spt->filename); - spt->slirp = NULL; -} - -static int tftp_session_allocate(Slirp *slirp, 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_ip, &tp->ip.ip_src, sizeof(spt->client_ip)); - spt->f = NULL; - spt->client_port = tp->udp.uh_sport; - spt->slirp = slirp; - - tftp_session_update(spt); - - return k; -} - -static int tftp_session_find(Slirp *slirp, 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 (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) { - 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->f == NULL) { - spt->f = fopen(spt->filename, "rb"); - } - - if (spt->f == NULL) { - return -1; - } - - if (len) { - (void)fseek(spt->f, block_nr * 512, SEEK_SET); - - bytes_read = fread(buf, 1, len, spt->f); - } - - return bytes_read; -} - -static int tftp_send_oack(struct tftp_session *spt, - const char *keys[], uint32_t values[], int nb, - struct tftp_t *recv_tp) -{ - struct sockaddr_in saddr, daddr; - struct mbuf *m; - struct tftp_t *tp; - int i, n = 0; - - m = m_get(spt->slirp); - - if (!m) - return -1; - - memset(m->m_data, 0, m->m_size); - - m->m_data += IF_MAXLINKHDR; - tp = (struct tftp_t *)m->m_data; - m->m_data += sizeof(struct udpiphdr); - - tp->tp_op = htons(TFTP_OACK); - for (i = 0; i < nb; i++) { - n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s", - keys[i]) + 1; - n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u", - values[i]) + 1; - } - - saddr.sin_addr = recv_tp->ip.ip_dst; - saddr.sin_port = recv_tp->udp.uh_dport; - - daddr.sin_addr = spt->client_ip; - daddr.sin_port = spt->client_port; - - m->m_len = sizeof(struct tftp_t) - 514 + n - - sizeof(struct ip) - sizeof(struct udphdr); - udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); - - return 0; -} - -static void tftp_send_error(struct tftp_session *spt, - uint16_t errorcode, const char *msg, - struct tftp_t *recv_tp) -{ - struct sockaddr_in saddr, daddr; - struct mbuf *m; - struct tftp_t *tp; - - m = m_get(spt->slirp); - - if (!m) { - goto out; - } - - memset(m->m_data, 0, m->m_size); - - m->m_data += IF_MAXLINKHDR; - tp = (struct tftp_t *)m->m_data; - m->m_data += sizeof(struct udpiphdr); - - tp->tp_op = htons(TFTP_ERROR); - tp->x.tp_error.tp_error_code = htons(errorcode); - pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg); - - saddr.sin_addr = recv_tp->ip.ip_dst; - saddr.sin_port = recv_tp->udp.uh_dport; - - daddr.sin_addr = spt->client_ip; - daddr.sin_port = spt->client_port; - - m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) - - sizeof(struct ip) - sizeof(struct udphdr); - - udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); - -out: - tftp_session_terminate(spt); -} - -static void tftp_send_next_block(struct tftp_session *spt, - struct tftp_t *recv_tp) -{ - struct sockaddr_in saddr, daddr; - struct mbuf *m; - struct tftp_t *tp; - int nobytes; - - m = m_get(spt->slirp); - - if (!m) { - return; - } - - memset(m->m_data, 0, m->m_size); - - m->m_data += IF_MAXLINKHDR; - tp = (struct tftp_t *)m->m_data; - m->m_data += sizeof(struct udpiphdr); - - tp->tp_op = htons(TFTP_DATA); - tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff); - - saddr.sin_addr = recv_tp->ip.ip_dst; - saddr.sin_port = recv_tp->udp.uh_dport; - - daddr.sin_addr = spt->client_ip; - daddr.sin_port = spt->client_port; - - nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf, 512); - - 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) - (512 - nobytes) - - sizeof(struct ip) - sizeof(struct udphdr); - - udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); - - if (nobytes == 512) { - tftp_session_update(spt); - } - else { - tftp_session_terminate(spt); - } - - spt->block_nr++; -} - -static void tftp_handle_rrq(Slirp *slirp, 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, tp); - if (s >= 0) { - tftp_session_terminate(&slirp->tftp_sessions[s]); - } - - s = tftp_session_allocate(slirp, 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 = (char *)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; - } - } - - /* check mode */ - if ((pktlen - k) < 6) { - tftp_send_error(spt, 2, "Access violation", tp); - return; - } - - if (strcasecmp(&tp->x.tp_buf[k], "octet") != 0) { - tftp_send_error(spt, 4, "Unsupported transfer mode", tp); - return; - } - - k += 6; /* skipping octet */ - - /* do sanity checks on the filename */ - if (!strncmp(req_fname, "../", 3) || - req_fname[strlen(req_fname) - 1] == '/' || - strstr(req_fname, "/../")) { - tftp_send_error(spt, 2, "Access violation", tp); - return; - } - - /* check if the file exists */ - if (tftp_read_data(spt, 0, NULL, 0) < 0) { - tftp_send_error(spt, 1, "File not found", tp); - return; - } - - if (tp->x.tp_buf[pktlen - 1] != 0) { - tftp_send_error(spt, 2, "Access violation", tp); - return; - } - - while (k < pktlen && nb_options < ARRAY_SIZE(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); - - /* If blksize option is bigger than what we will - * emit, accept the option with our packet size. - * Otherwise, simply do as we didn't see the option. - */ - if (blksize >= 512) { - option_name[nb_options] = "blksize"; - option_value[nb_options] = 512; - nb_options++; - } - } - } - - if (nb_options > 0) { - assert(nb_options <= ARRAY_SIZE(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 tftp_t *tp, int pktlen) -{ - int s; - - s = tftp_session_find(slirp, tp); - - if (s < 0) { - return; - } - - tftp_send_next_block(&slirp->tftp_sessions[s], tp); -} - -static void tftp_handle_error(Slirp *slirp, struct tftp_t *tp, int pktlen) -{ - int s; - - s = tftp_session_find(slirp, tp); - - if (s < 0) { - return; - } - - tftp_session_terminate(&slirp->tftp_sessions[s]); -} - -void tftp_input(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, tp, m->m_len); - break; - - case TFTP_ACK: - tftp_handle_ack(m->slirp, tp, m->m_len); - break; - - case TFTP_ERROR: - tftp_handle_error(m->slirp, tp, m->m_len); - break; - } -} diff --git a/slirp/tftp.h b/slirp/tftp.h deleted file mode 100644 index 8af289ee6..000000000 --- a/slirp/tftp.h +++ /dev/null @@ -1,49 +0,0 @@ -/* tftp defines */ -#ifndef SLIRP_TFTP_H -#define SLIRP_TFTP_H 1 - -#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 - -struct tftp_t { - struct ip ip; - struct udphdr udp; - uint16_t tp_op; - union { - struct { - uint16_t tp_block_nr; - uint8_t tp_buf[512]; - } tp_data; - struct { - uint16_t tp_error_code; - uint8_t tp_msg[512]; - } tp_error; - char tp_buf[512 + 2]; - } x; -}; - -struct tftp_session { - Slirp *slirp; - char *filename; - FILE *f; - - struct in_addr client_ip; - uint16_t client_port; - uint32_t block_nr; - - int timestamp; -}; - -void tftp_input(struct mbuf *m); - -#endif diff --git a/slirp/udp.c b/slirp/udp.c deleted file mode 100644 index 72580b4c4..000000000 --- a/slirp/udp.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1988, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94 - * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp - */ - -/* - * Changes and additions relating to SLiRP - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#include -#include "ip_icmp.h" - -static uint8_t udp_tos(struct socket *so); - -void -udp_init(Slirp *slirp) -{ - slirp->udb.so_next = slirp->udb.so_prev = &slirp->udb; - slirp->udp_last_so = &slirp->udb; -} - -void udp_cleanup(Slirp *slirp) -{ - while (slirp->udb.so_next != &slirp->udb) { - udp_detach(slirp->udb.so_next); - } -} - -/* m->m_data points at ip packet header - * m->m_len length ip packet - * ip->ip_len length data (IPDU) - */ -void -udp_input(register struct mbuf *m, int iphlen) -{ - Slirp *slirp = m->slirp; - register struct ip *ip; - register struct udphdr *uh; - int len; - struct ip save_ip; - struct socket *so; - - DEBUG_CALL("udp_input"); - DEBUG_ARG("m = %lx", (long)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 *)((caddr_t)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; - } - } - - /* - * 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) { - tftp_input(m); - goto bad; - } - - if (slirp->restricted) { - goto bad; - } - - /* - * Locate pcb for datagram. - */ - so = slirp->udp_last_so; - if (so == &slirp->udb || so->so_lport != uh->uh_sport || - so->so_laddr.s_addr != ip->ip_src.s_addr) { - struct socket *tmp; - - for (tmp = slirp->udb.so_next; tmp != &slirp->udb; - tmp = tmp->so_next) { - if (tmp->so_lport == uh->uh_sport && - tmp->so_laddr.s_addr == ip->ip_src.s_addr) { - so = tmp; - break; - } - } - if (tmp == &slirp->udb) { - so = NULL; - } else { - slirp->udp_last_so = so; - } - } - - if (so == NULL) { - /* - * If there's no socket for this packet, - * create one - */ - so = socreate(slirp); - if (!so) { - goto bad; - } - if(udp_attach(so) == -1) { - DEBUG_MISC(" udp_attach errno = %d-%s\n", - errno,strerror(errno)); - sofree(so); - goto bad; - } - - /* - * Setup fields - */ - 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_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\n",errno,strerror(errno)); - icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); - } - - 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_output2(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 = %lx", (long)so); - DEBUG_ARG("m = %lx", (long)m); - DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr); - DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_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_output(struct socket *so, struct mbuf *m, - struct sockaddr_in *addr) - -{ - Slirp *slirp = so->slirp; - struct sockaddr_in saddr, daddr; - - saddr = *addr; - 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) { - saddr.sin_addr = slirp->vhost_addr; - } else if (addr->sin_addr.s_addr == loopback_addr.s_addr || - so->so_faddr.s_addr != slirp->vhost_addr.s_addr) { - saddr.sin_addr = so->so_faddr; - } - } - daddr.sin_addr = so->so_laddr; - daddr.sin_port = so->so_lport; - - return udp_output2(so, m, &saddr, &daddr, so->so_iptos); -} - -int -udp_attach(struct socket *so) -{ - if((so->s = qemu_socket(AF_INET,SOCK_DGRAM,0)) != -1) { - so->so_expire = curtime + SO_EXPIRE; - insque(so, &so->slirp->udb); - } - return(so->s); -} - -void -udp_detach(struct socket *so) -{ - closesocket(so->s); - sofree(so); -} - -static const struct tos_t udptos[] = { - {0, 53, IPTOS_LOWDELAY, 0}, /* DNS */ - {0, 0, 0, 0} -}; - -static uint8_t -udp_tos(struct socket *so) -{ - int i = 0; - - while(udptos[i].tos) { - if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) || - (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) { - so->so_emu = udptos[i].emu; - return udptos[i].tos; - } - i++; - } - - return 0; -} - -struct socket * -udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr, - u_int lport, int flags) -{ - struct sockaddr_in addr; - struct socket *so; - socklen_t addrlen = sizeof(struct sockaddr_in); - - so = socreate(slirp); - if (!so) { - return NULL; - } - so->s = qemu_socket(AF_INET,SOCK_DGRAM,0); - 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) == SOCKET_ERROR) { - udp_detach(so); - return NULL; - } - (void)socket_set_fast_reuse(so->s); - - (void)getsockname(so->s,(struct sockaddr *)&addr,&addrlen); - 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->so_lport = lport; - so->so_laddr.s_addr = laddr; - if (flags != SS_FACCEPTONCE) - so->so_expire = 0; - - so->so_state &= SS_PERSISTENT_MASK; - so->so_state |= SS_ISFCONNECTED | flags; - - return so; -} diff --git a/slirp/udp.h b/slirp/udp.h deleted file mode 100644 index 3f90af620..000000000 --- a/slirp/udp.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)udp.h 8.1 (Berkeley) 6/10/93 - * udp.h,v 1.3 1994/08/21 05:27:41 paul Exp - */ - -#ifndef _UDP_H_ -#define _UDP_H_ - -#define UDP_TTL 0x60 -#define UDP_UDPDATALEN 16192 - -/* - * Udp protocol header. - * Per RFC 768, September, 1981. - */ -struct udphdr { - uint16_t uh_sport; /* source port */ - uint16_t uh_dport; /* destination port */ - int16_t uh_ulen; /* udp length */ - uint16_t uh_sum; /* udp checksum */ -}; - -/* - * UDP kernel structures and variables. - */ -struct udpiphdr { - struct ipovly ui_i; /* overlaid ip structure */ - struct udphdr ui_u; /* udp header */ -}; -#define ui_mbuf ui_i.ih_mbuf.mptr -#define ui_x1 ui_i.ih_x1 -#define ui_pr ui_i.ih_pr -#define ui_len ui_i.ih_len -#define ui_src ui_i.ih_src -#define ui_dst ui_i.ih_dst -#define ui_sport ui_u.uh_sport -#define ui_dport ui_u.uh_dport -#define ui_ulen ui_u.uh_ulen -#define ui_sum ui_u.uh_sum - -/* - * Names for UDP sysctl objects - */ -#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ -#define UDPCTL_MAXID 2 - -struct mbuf; - -void udp_init(Slirp *); -void udp_cleanup(Slirp *); -void udp_input(register struct mbuf *, int); -int udp_output(struct socket *, struct mbuf *, struct sockaddr_in *); -int udp_attach(struct socket *); -void udp_detach(struct socket *); -struct socket * udp_listen(Slirp *, uint32_t, u_int, uint32_t, u_int, - int); -int udp_output2(struct socket *so, struct mbuf *m, - struct sockaddr_in *saddr, struct sockaddr_in *daddr, - int iptos); -#endif diff --git a/slirp_glue/README b/slirp_glue/README deleted file mode 100644 index 3a4842300..000000000 --- a/slirp_glue/README +++ /dev/null @@ -1,16 +0,0 @@ -The files in and below this directory are the necessary glue and stubs -to allow the effectively unmodified qemu slirp code to be used in simh -as a network connection mechanism. - -Most of the include files here started from related files in the qemu -include directories and have been chopped up and tweaked as necessary -so that the slirp code can be used outside of qemu. - -Slirp depends on a small set of capabilities from glib (GArrays mostly). - -All of the other include files exist so that the references in the -slirp code don't have to be modified. - -- Mark Pizzolato - - diff --git a/slirp_glue/config-host.h b/slirp_glue/config-host.h deleted file mode 100644 index 9bb557ce4..000000000 --- a/slirp_glue/config-host.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef CONFIG_HOST_H -#define CONFIG_HOST_H - -#include -#include -#include -#ifdef _WIN32 -#include -#else -typedef int SOCKET; -#define SOCKET_ERROR (-1) -#endif - -#ifndef __cplusplus -typedef int bool; -#endif -#ifdef _MSC_VER -#include -#else -#include -#endif -#include -#define qemu_add_child_watch(pid) -int qemu_setsockopt (int s, int level, int optname, void *optval, int optlen); -int qemu_recv (int s, void *buf, size_t len, int flags); -#ifdef _MSC_VER -#define snprintf _snprintf -#ifndef strcasecmp -#define strcasecmp stricmp -#endif -#define inline -#else -#ifndef _WIN32 -#define CONFIG_IOVEC 1 -#endif -#endif -#define register_savevm(p1, p2, p3, p4, p5, p6, p7) -#define unregister_savevm(p1, p2, p3) -#define qemu_put_be16(p1, p2) -#define qemu_put_sbe16(p1, p2) -#define qemu_put_be32(p1, p2) -#define qemu_put_sbe32(p1, p2) -#define qemu_put_byte(p1, p2) -#define qemu_put_sbyte(p1, p2) -#define qemu_put_buffer(p1, p2, p3) - -#define qemu_get_be16(p1) 0 -#define qemu_get_sbe16(p1) 0 -#define qemu_get_be32(p1) 0 -#define qemu_get_sbe32(p1) 0 -#define qemu_get_byte(p1) 0 -#define qemu_get_sbyte(p1) 0 -#define qemu_get_buffer(p1, p2, p3) -#define error_report(...) fprintf(stderr, __VA_ARGS__) - -#endif diff --git a/slirp_glue/glib.h b/slirp_glue/glib.h deleted file mode 100644 index 714681aa8..000000000 --- a/slirp_glue/glib.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef GLIB_H -#define GLIB_H - -#include -#if defined(_WIN32) -#include -#endif - -typedef char gchar; -typedef unsigned int guint; -typedef unsigned short gushort; -typedef void* gpointer; -typedef unsigned long gsize; -typedef const void *gconstpointer; -typedef int gint; -typedef gint gboolean; -typedef struct _GSource {int dummy;} GSource; -typedef struct GPollFD { -#if defined(_WIN32) - SOCKET fd; -#else - gint fd; -#endif - gushort events; - gushort revents; -} GPollFD; -typedef struct _GArray { - gchar *data; - guint len; -} GArray; - -gpointer g_malloc (gsize n_bytes); -gpointer g_malloc0 (gsize n_bytes); -gpointer g_realloc (gpointer mem, gsize n_bytes); -void g_free (gpointer mem); -gchar *g_strdup (const gchar *str); - -typedef enum { - /* Flags */ - G_LOG_FLAG_RECURSION = 1 << 0, - G_LOG_FLAG_FATAL = 1 << 1, - /* Levels */ - G_LOG_LEVEL_ERROR = 1 << 2, - G_LOG_LEVEL_CRITICAL = 1 << 3, - G_LOG_LEVEL_WARNING = 1 << 4, - G_LOG_LEVEL_MESSAGE = 1 << 5, - G_LOG_LEVEL_INFO = 1 << 6, - G_LOG_LEVEL_DEBUG = 1 << 7, - G_LOG_LEVEL_MASK = ~(G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL) - } GLogLevelFlags; - -#define GLIB_SYSDEF_POLLIN =1 -#define GLIB_SYSDEF_POLLOUT =4 -#define GLIB_SYSDEF_POLLPRI =2 -#define GLIB_SYSDEF_POLLHUP =16 -#define GLIB_SYSDEF_POLLERR =8 -#define GLIB_SYSDEF_POLLNVAL =32 - -typedef enum { - G_IO_IN GLIB_SYSDEF_POLLIN, /* There is data to read. */ - G_IO_OUT GLIB_SYSDEF_POLLOUT, /* Data can be written (without blocking). */ - G_IO_PRI GLIB_SYSDEF_POLLPRI, /* There is urgent data to read. */ - G_IO_ERR GLIB_SYSDEF_POLLERR, /* Error condition. */ - G_IO_HUP GLIB_SYSDEF_POLLHUP, /* Hung up (the connection has been broken, usually for pipes and sockets). */ - G_IO_NVAL GLIB_SYSDEF_POLLNVAL /* Invalid request. The file descriptor is not open. */ - } GIOCondition; -void g_log (const gchar *log_domain, GLogLevelFlags log_level, const gchar *format, ...); -#if !defined(G_LOG_DOMAIN) -#define G_LOG_DOMAIN ((gchar *)NULL) -#endif -#define g_warning(...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, __VA_ARGS__) - -#define g_new(struct_type, n_structs) g_malloc (sizeof(struct_type) * n_structs) - - -#define g_array_append_val(array, data) g_array_append_vals (array, &data, 1) -#define g_array_new(zero_terminated, clear, element_size) g_array_sized_new(zero_terminated, clear, element_size, 0) - -GArray * -g_array_sized_new (gboolean zero_terminated, - gboolean clear, - guint element_size, - guint reserved_size); -gchar * -g_array_free (GArray *array, - gboolean free_segment); - -#define g_array_index(array, type, index) (((type *)(void *)((array)->data)))[index] - -GArray * -g_array_set_size (GArray *array, - guint length); -GArray * -g_array_append_vals (GArray *array, - gconstpointer data, - guint len); -guint -g_array_get_element_size (GArray *array); - - -#endif diff --git a/slirp_glue/glib_qemu_stubs.c b/slirp_glue/glib_qemu_stubs.c deleted file mode 100644 index 99f062455..000000000 --- a/slirp_glue/glib_qemu_stubs.c +++ /dev/null @@ -1,346 +0,0 @@ -/* glib_qemu_stubs.c: - ------------------------------------------------------------------------------ - Copyright (c) 2015, Mark Pizzolato - - 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 AUTHOR 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. - - Except as contained in this notice, the name of the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - ------------------------------------------------------------------------------ - - This module provides the minimal aspects of glib and qemu which are referenced - by the current qemu SLiRP code and are needed to get SLiRP functionality for - the simh network code. - -*/ - -#include -#include -#include -#include -#ifdef _WIN32 -#include -#include -#endif -#include "qemu/compiler.h" -#include "qemu/typedefs.h" -#include -#include -#include "glib.h" - -gpointer -g_malloc (gsize n_bytes) -{ -gpointer ret = (gpointer)malloc (n_bytes); - -if (!ret) - exit (errno); -return ret; -} - -gpointer -g_malloc0 (gsize n_bytes) -{ -gpointer ret = (gpointer)calloc (1, n_bytes); - -if (!ret) - exit (errno); -return ret; -} - -gpointer -g_realloc (gpointer mem, gsize n_bytes) -{ -gpointer ret = (gpointer)realloc (mem, n_bytes); - -if (!ret) - exit (errno); -return ret; -} - -void -g_free (gpointer mem) -{ -free (mem); -} - -gchar * -g_strdup (const gchar *str) -{ -gchar *nstr = NULL; - -if (str) { - nstr = (gchar *)malloc (strlen(str)+1); - if (!nstr) - exit (errno); - strcpy (nstr, str); - } -return nstr; -} - -void 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'; -} - -int qemu_socket(int domain, int type, int protocol) -{ -return socket (domain, type, protocol); -} - -int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen) -{ -return accept (s, addr, addrlen); -} - -int qemu_setsockopt (int s, int level, int optname, void *optval, int optlen) -{ -return setsockopt ((SOCKET)s, level, optname, (char *)optval, optlen); -} - -int qemu_recv (int s, void *buf, size_t len, int flags) -{ -return recv ((SOCKET)s, (char *)buf, len, flags); -} - -int socket_set_nodelay(int fd) -{ - int v = 1; - return setsockopt((SOCKET)fd, IPPROTO_TCP, TCP_NODELAY, (char *)&v, sizeof(v)); -} - -#ifdef _WIN32 - -void qemu_set_nonblock(int fd) -{ -unsigned long non_block = 1; - - (void)ioctlsocket ((SOCKET)fd, FIONBIO, &non_block); /* set nonblocking */ -} -#else -#include -void qemu_set_nonblock(int fd) -{ - int f; - - f = fcntl(fd, F_GETFL); - if (f != -1) - (void)fcntl(fd, F_SETFL, f | O_NONBLOCK); -} -#endif - -int socket_set_fast_reuse(int fd) -{ - int val = 1, ret; - - ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - (const char *)&val, sizeof(val)); - return ret; -} - -#if defined(__cplusplus) -extern "C" { -#endif -#include -#ifdef _WIN32 -int64_t qemu_clock_get_ns(int type) -{ -uint64_t now, unixbase; - -unixbase = 116444736; -unixbase *= 1000000000; -GetSystemTimeAsFileTime((FILETIME*)&now); -now -= unixbase; -return now*100; -} - -#else - -#if !defined(CLOCK_REALTIME) && !defined(__hpux) -#define CLOCK_REALTIME 1 -int clock_gettime(int clk_id, struct timespec *tp); -#endif - -int64_t qemu_clock_get_ns(int type) -{ - struct timespec tv; - - clock_gettime(CLOCK_REALTIME, &tv); - return tv.tv_sec * 1000000000LL + tv.tv_nsec; -} -#endif -#if defined(__cplusplus) -} -#endif - -void monitor_printf(Monitor *mon, const char *fmt, ...) -{ -va_list arglist; - - va_start (arglist, fmt); - vfprintf ((FILE *)mon, fmt, arglist); - va_end (arglist); -} - -void g_log (const gchar *log_domain, - GLogLevelFlags log_level, - const gchar *format, - ...) -{ -va_list arglist; - - fprintf (stderr, "%s(%X): ", log_domain ? log_domain : "", log_level); - va_start (arglist, format); - vfprintf (stderr, format, arglist); - va_end (arglist); -} - -int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len) -{ -fprintf (stderr, "qemu_chr_fe_write() called\n"); -return 0; -} - -void qemu_notify_event(void) -{ -} - -#if defined(_WIN32) -int -inet_aton(const char *arg, struct in_addr *addr) -{ -(*addr).s_addr = inet_addr (arg); -return (*addr).s_addr != INADDR_BROADCAST; -} - -#endif - -/* glib GArray functionality is needed */ - -typedef struct { - gchar *data; - guint len; - guint _element_size; /* element size */ - guint _size; /* allocated element count size */ - gboolean _zero_terminated; - gboolean _clear; -} GArrayInternal; - -GArray * -g_array_sized_new (gboolean zero_terminated, - gboolean clear, - guint element_size, - guint reserved_size) -{ -GArrayInternal *ar = (GArrayInternal *)g_malloc (sizeof (*ar)); - -ar->_zero_terminated = zero_terminated ? 1 : 0; -ar->_clear = clear ? 1 : 0; -ar->_element_size = element_size; -ar->_size = reserved_size; -ar->len = 0; -ar->data = clear ? (gchar *)g_malloc0 (element_size*(reserved_size + zero_terminated)) : - (gchar *)g_malloc (element_size*(reserved_size + zero_terminated)); -if (ar->_zero_terminated && !ar->_clear) - memset (ar->data + (ar->len * ar->_element_size), 0, ar->_element_size); -return (GArray *)ar; -} - -gchar * -g_array_free (GArray *array, - gboolean free_segment) -{ -gchar *result = ((array == NULL) || free_segment) ? NULL : array->data; - -if (array != NULL) { - if (free_segment) - free (array->data); - free (array); - } -return result; -} - -GArray * -g_array_set_size (GArray *array, - guint length) -{ -GArrayInternal *ar = (GArrayInternal *)array; - -if (length > ar->_size) { - ar->data = (gchar *)g_realloc (ar->data, (length + ar->_zero_terminated) * ar->_element_size); - if (ar->_clear) - memset (ar->data + (ar->len * ar->_element_size), 0, (length + ar->_zero_terminated - ar->len) * ar->_element_size); - ar->_size = length; - } -ar->len = length; -if (ar->_zero_terminated) - memset (ar->data + (ar->len * ar->_element_size), 0, ar->_element_size); -return array; -} - -GArray * -g_array_append_vals (GArray *array, - gconstpointer data, - guint len) -{ -GArrayInternal *ar = (GArrayInternal *)array; - -if ((ar->len + len) > ar->_size) { - ar->data = (gchar *)g_realloc (ar->data, (ar->len + len + ar->_zero_terminated) * ar->_element_size); - ar->_size = ar->len + len; - } -memcpy (ar->data + (ar->len * ar->_element_size), data, len * ar->_element_size); -ar->len += len; -if (ar->_zero_terminated) - memset (ar->data + (ar->len * ar->_element_size), 0, ar->_element_size); -return array; -} - -guint -g_array_get_element_size (GArray *array) -{ -GArrayInternal *ar = (GArrayInternal *)array; - -return ar->_element_size; -} - -#if defined(_WIN32) -char *socket_strerror(int errnum) -{ -static char buf[512]; - -if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)buf, sizeof(buf), NULL)) - sprintf(buf, "Error Code: %d", errno); -return buf; -} -#endif diff --git a/slirp_glue/qemu/compiler.h b/slirp_glue/qemu/compiler.h deleted file mode 100644 index a8a2cde00..000000000 --- a/slirp_glue/qemu/compiler.h +++ /dev/null @@ -1,64 +0,0 @@ -/* public domain */ - -#ifndef COMPILER_H -#define COMPILER_H - -#include "config-host.h" - -/*---------------------------------------------------------------------------- -| The macro QEMU_GNUC_PREREQ tests for minimum version of the GNU C compiler. -| The code is a copy of SOFTFLOAT_GNUC_PREREQ, see softfloat-macros.h. -*----------------------------------------------------------------------------*/ -#if defined(__GNUC__) && defined(__GNUC_MINOR__) -# define QEMU_GNUC_PREREQ(maj, min) \ - ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) -#else -# define QEMU_GNUC_PREREQ(maj, min) 0 -#endif - -#ifndef container_of -#define container_of(ptr, type, member) \ - ((type *) ((char *)(ptr) - offsetof(type, member))) -#endif - -#ifndef always_inline -#if !((__GNUC__ < 3) || defined(__APPLE__)) -#ifdef __OPTIMIZE__ -#undef inline -#define inline __attribute__ (( always_inline )) __inline__ -#endif -#endif -#else -#undef inline -#define inline always_inline -#endif -#ifdef _MSC_VER -#undef inline -#define inline __inline -#endif - -#define register - -#if defined __GNUC__ -# if !QEMU_GNUC_PREREQ(4, 4) - /* gcc versions before 4.4.x don't support gnu_printf, so use printf. */ -# define GCC_FMT_ATTR(n, m) __attribute__((format(printf, n, m))) -# else - /* Use gnu_printf when supported (qemu uses standard format strings). */ -# define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m))) -# if defined(_WIN32) - /* Map __printf__ to __gnu_printf__ because we want standard format strings - * even when MinGW or GLib include files use __printf__. */ -# define __printf__ __gnu_printf__ -# endif -# endif -#else -#define GCC_FMT_ATTR(n, m) -#endif - -#if defined (__clang__) - #pragma clang diagnostic ignored "-Wunknown-pragmas" - #pragma clang diagnostic ignored "-Waddress-of-packed-member" -#endif - -#endif /* COMPILER_H */ diff --git a/slirp_glue/qemu/error-report.h b/slirp_glue/qemu/error-report.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/slirp_glue/qemu/hw/hw.h b/slirp_glue/qemu/hw/hw.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/slirp_glue/qemu/main-loop.h b/slirp_glue/qemu/main-loop.h deleted file mode 100644 index 3cce36943..000000000 --- a/slirp_glue/qemu/main-loop.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-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. - */ - -#ifndef QEMU_MAIN_LOOP_H -#define QEMU_MAIN_LOOP_H 1 - - -/** - * qemu_notify_event: Force processing of pending events. - * - * Similar to signaling a condition variable, qemu_notify_event forces - * main_loop_wait to look at pending events and exit. The caller of - * main_loop_wait will usually call it again very soon, so qemu_notify_event - * also has the side effect of recalculating the sets of file descriptors - * that the main loop waits for. - * - * Calling qemu_notify_event is rarely necessary, because main loop - * services (bottom halves and timers) call it themselves. - */ -void qemu_notify_event(void); - -#endif diff --git a/slirp_glue/qemu/monitor/monitor.h b/slirp_glue/qemu/monitor/monitor.h deleted file mode 100644 index e088c1626..000000000 --- a/slirp_glue/qemu/monitor/monitor.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef MONITOR_H -#define MONITOR_H - -#include "qemu-common.h" - -void monitor_printf(Monitor *mon, const char *fmt, ...) GCC_FMT_ATTR(2, 3); - -#endif /* !MONITOR_H */ diff --git a/slirp_glue/qemu/osdep.h b/slirp_glue/qemu/osdep.h deleted file mode 100644 index c3d333941..000000000 --- a/slirp_glue/qemu/osdep.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * OS includes and handling of OS dependencies - * - * This header exists to pull in some common system headers that - * most code in QEMU will want, and to fix up some possible issues with - * it (missing defines, Windows weirdness, and so on). - * - * To avoid getting into possible circular include dependencies, this - * file should not include any other QEMU headers, with the exceptions - * of config-host.h, compiler.h, os-posix.h and os-win32.h, all of which - * are doing a similar job to this file and are under similar constraints. - * - * This header also contains prototypes for functions defined in - * os-*.c and util/oslib-*.c; those would probably be better split - * out into separate header files. - * - * In an ideal world this header would contain only: - * (1) things which everybody needs - * (2) things without which code would work on most platforms but - * fail to compile or misbehave on a minority of host OSes - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ -#ifndef QEMU_OSDEP_H -#define QEMU_OSDEP_H - -#include "config-host.h" -#include "qemu/compiler.h" -#include -#include -#ifdef _MSC_VER -#include -#include -#include -#else -#include -#include -#include -#endif -#include -#include -#include -#include -#ifndef _MSC_VER -#include -#endif -#include -/* Put unistd.h before time.h as that triggers localtime_r/gmtime_r - * function availability on recentish Mingw-w64 platforms. */ -#ifdef HAVE_UNISTD_H -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __OpenBSD__ -#include -#endif - -#ifndef _WIN32 -#include -#else -#define WIFEXITED(x) 1 -#define WEXITSTATUS(x) (x) -#endif - -#ifdef _WIN32 -#include "sysemu/os-win32.h" -#endif - -#ifdef CONFIG_POSIX -#include "sysemu/os-posix.h" -#endif - -#if defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10 -/* [u]int_fast*_t not in */ -typedef unsigned char uint_fast8_t; -typedef unsigned int uint_fast16_t; -typedef signed int int_fast16_t; -#endif - -#ifndef O_LARGEFILE -#define O_LARGEFILE 0 -#endif -#ifndef O_BINARY -#define O_BINARY 0 -#endif -#ifndef MAP_ANONYMOUS -#define MAP_ANONYMOUS MAP_ANON -#endif -#ifndef ENOMEDIUM -#define ENOMEDIUM ENODEV -#endif -#if !defined(ENOTSUP) -#define ENOTSUP 4096 -#endif -#if !defined(ECANCELED) -#define ECANCELED 4097 -#endif -#if !defined(EMEDIUMTYPE) -#define EMEDIUMTYPE 4098 -#endif -#ifndef TIME_MAX -#define TIME_MAX LONG_MAX -#endif - -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif - -/* Minimum function that returns zero only iff both values are zero. - * Intended for use with unsigned values only. */ -#ifndef MIN_NON_ZERO -#define MIN_NON_ZERO(a, b) (((a) != 0 && (a) < (b)) ? (a) : (b)) -#endif - -#ifndef ROUND_UP -#define ROUND_UP(n,d) (((n) + (d) - 1) & -(d)) -#endif - -#ifndef DIV_ROUND_UP -#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) -#endif - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif - -#ifndef CONFIG_IOVEC -struct iovec { - void *iov_base; - int iov_len; -}; -/* - * Use the same value as Linux for now. - */ -#define IOV_MAX 1024 - -ssize_t readv(int fd, const struct iovec *iov, int iov_cnt); -ssize_t writev(int fd, const struct iovec *iov, int iov_cnt); -#else -#include -#endif - -#ifdef _WIN32 -static inline void qemu_timersub(const struct timeval *val1, - const struct timeval *val2, - struct timeval *res) -{ - res->tv_sec = val1->tv_sec - val2->tv_sec; - if (val1->tv_usec < val2->tv_usec) { - res->tv_sec--; - res->tv_usec = val1->tv_usec - val2->tv_usec + 1000 * 1000; - } else { - res->tv_usec = val1->tv_usec - val2->tv_usec; - } -} -#else -#define qemu_timersub timersub -#endif - -#endif diff --git a/slirp_glue/qemu/qemu-common.h b/slirp_glue/qemu/qemu-common.h deleted file mode 100644 index b4158e994..000000000 --- a/slirp_glue/qemu/qemu-common.h +++ /dev/null @@ -1,54 +0,0 @@ - -/* Common header file that is included by all of QEMU. - * - * This file is supposed to be included only by .c files. No header file should - * depend on qemu-common.h, as this would easily lead to circular header - * dependencies. - * - * If a header file uses a definition from qemu-common.h, that definition - * must be moved to a separate header file, and the header that uses it - * must include that header. - */ -#ifndef QEMU_COMMON_H -#define QEMU_COMMON_H - -#include "qemu/osdep.h" -#include "qemu/typedefs.h" - -#include "glib.h" -#include "config-host.h" - -#if defined(O_BINARY) /* O_BINARY isn't used in slirp */ -#undef O_BINARY /* Avoid potential redefinition elsewhere */ -#endif - -/* HOST_LONG_BITS is the size of a native pointer in bits. */ -#if UINTPTR_MAX == UINT32_MAX -# define HOST_LONG_BITS 32 -#elif UINTPTR_MAX == UINT64_MAX -# define HOST_LONG_BITS 64 -#else -# error Unknown pointer size -#endif - -/* util/cutils.c */ -/** - * pstrcpy: - * @buf: buffer to copy string into - * @buf_size: size of @buf in bytes - * @str: string to copy - * - * Copy @str into @buf, including the trailing NUL, but do not - * write more than @buf_size bytes. The resulting buffer is - * always NUL terminated (even if the source string was too long). - * If @buf_size is zero or negative then no bytes are copied. - * - * This function is similar to strncpy(), but avoids two of that - * function's problems: - * * if @str fits in the buffer, pstrcpy() does not zero-fill the - * remaining space at the end of @buf - * * if @str is too long, pstrcpy() will copy the first @buf_size-1 - * bytes and then add a NUL - */ -void pstrcpy(char *buf, int buf_size, const char *str); -#endif diff --git a/slirp_glue/qemu/queue.h b/slirp_glue/qemu/queue.h deleted file mode 100644 index 3126c9e6d..000000000 --- a/slirp_glue/qemu/queue.h +++ /dev/null @@ -1,431 +0,0 @@ -/* $NetBSD: queue.h,v 1.52 2009/04/20 09:56:08 mschuett Exp $ */ - -/* - * QEMU version: Copy from netbsd, removed debug code, removed some of - * the implementations. Left in singly-linked lists, lists, simple - * queues, and tail queues. - */ - -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - */ - -#ifndef QEMU_SYS_QUEUE_H_ -#define QEMU_SYS_QUEUE_H_ - -/* - * This file defines four types of data structures: singly-linked lists, - * lists, simple queues, and tail queues. - * - * A singly-linked list is headed by a single forward pointer. The - * elements are singly linked for minimum space and pointer manipulation - * overhead at the expense of O(n) removal for arbitrary elements. New - * elements can be added to the list after an existing element or at the - * head of the list. Elements being removed from the head of the list - * should use the explicit macro for this purpose for optimum - * efficiency. A singly-linked list may only be traversed in the forward - * direction. Singly-linked lists are ideal for applications with large - * datasets and few or no removals or for implementing a LIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. - * - * A simple queue is headed by a pair of pointers, one the head of the - * list and the other to the tail of the list. The elements are singly - * linked to save space, so elements can only be removed from the - * head of the list. New elements can be added to the list after - * an existing element, at the head of the list, or at the end of the - * list. A simple queue may only be traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * For details on the use of these macros, see the queue(3) manual page. - */ - -/* - * List definitions. - */ -#define QLIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define QLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define QLIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * List functions. - */ -#define QLIST_INIT(head) do { \ - (head)->lh_first = NULL; \ -} while (/*CONSTCOND*/0) - -#define QLIST_SWAP(dstlist, srclist, field) do { \ - void *tmplist; \ - tmplist = (srclist)->lh_first; \ - (srclist)->lh_first = (dstlist)->lh_first; \ - if ((srclist)->lh_first != NULL) { \ - (srclist)->lh_first->field.le_prev = &(srclist)->lh_first; \ - } \ - (dstlist)->lh_first = tmplist; \ - if ((dstlist)->lh_first != NULL) { \ - (dstlist)->lh_first->field.le_prev = &(dstlist)->lh_first; \ - } \ -} while (/*CONSTCOND*/0) - -#define QLIST_FIX_HEAD_PTR(head, field) do { \ - if ((head)->lh_first != NULL) { \ - (head)->lh_first->field.le_prev = &(head)->lh_first; \ - } \ -} while (/*CONSTCOND*/0) - -#define QLIST_INSERT_AFTER(listelm, elm, field) do { \ - if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ - (listelm)->field.le_next->field.le_prev = \ - &(elm)->field.le_next; \ - (listelm)->field.le_next = (elm); \ - (elm)->field.le_prev = &(listelm)->field.le_next; \ -} while (/*CONSTCOND*/0) - -#define QLIST_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - (elm)->field.le_next = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &(elm)->field.le_next; \ -} while (/*CONSTCOND*/0) - -#define QLIST_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.le_next = (head)->lh_first) != NULL) \ - (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ - (head)->lh_first = (elm); \ - (elm)->field.le_prev = &(head)->lh_first; \ -} while (/*CONSTCOND*/0) - -#define QLIST_REMOVE(elm, field) do { \ - if ((elm)->field.le_next != NULL) \ - (elm)->field.le_next->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = (elm)->field.le_next; \ -} while (/*CONSTCOND*/0) - -#define QLIST_FOREACH(var, head, field) \ - for ((var) = ((head)->lh_first); \ - (var); \ - (var) = ((var)->field.le_next)) - -#define QLIST_FOREACH_SAFE(var, head, field, next_var) \ - for ((var) = ((head)->lh_first); \ - (var) && ((next_var) = ((var)->field.le_next), 1); \ - (var) = (next_var)) - -/* - * List access methods. - */ -#define QLIST_EMPTY(head) ((head)->lh_first == NULL) -#define QLIST_FIRST(head) ((head)->lh_first) -#define QLIST_NEXT(elm, field) ((elm)->field.le_next) - - -/* - * Singly-linked List definitions. - */ -#define QSLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define QSLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define QSLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} - -/* - * Singly-linked List functions. - */ -#define QSLIST_INIT(head) do { \ - (head)->slh_first = NULL; \ -} while (/*CONSTCOND*/0) - -#define QSLIST_INSERT_AFTER(slistelm, elm, field) do { \ - (elm)->field.sle_next = (slistelm)->field.sle_next; \ - (slistelm)->field.sle_next = (elm); \ -} while (/*CONSTCOND*/0) - -#define QSLIST_INSERT_HEAD(head, elm, field) do { \ - (elm)->field.sle_next = (head)->slh_first; \ - (head)->slh_first = (elm); \ -} while (/*CONSTCOND*/0) - -#define QSLIST_REMOVE_HEAD(head, field) do { \ - (head)->slh_first = (head)->slh_first->field.sle_next; \ -} while (/*CONSTCOND*/0) - -#define QSLIST_REMOVE_AFTER(slistelm, field) do { \ - (slistelm)->field.sle_next = \ - QSLIST_NEXT(QSLIST_NEXT((slistelm), field), field); \ -} while (/*CONSTCOND*/0) - -#define QSLIST_FOREACH(var, head, field) \ - for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) - -#define QSLIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = QSLIST_FIRST((head)); \ - (var) && ((tvar) = QSLIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -/* - * Singly-linked List access methods. - */ -#define QSLIST_EMPTY(head) ((head)->slh_first == NULL) -#define QSLIST_FIRST(head) ((head)->slh_first) -#define QSLIST_NEXT(elm, field) ((elm)->field.sle_next) - - -/* - * Simple queue definitions. - */ -#define QSIMPLEQ_HEAD(name, type) \ -struct name { \ - struct type *sqh_first; /* first element */ \ - struct type **sqh_last; /* addr of last next element */ \ -} - -#define QSIMPLEQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).sqh_first } - -#define QSIMPLEQ_ENTRY(type) \ -struct { \ - struct type *sqe_next; /* next element */ \ -} - -/* - * Simple queue functions. - */ -#define QSIMPLEQ_INIT(head) do { \ - (head)->sqh_first = NULL; \ - (head)->sqh_last = &(head)->sqh_first; \ -} while (/*CONSTCOND*/0) - -#define QSIMPLEQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (head)->sqh_first = (elm); \ -} while (/*CONSTCOND*/0) - -#define QSIMPLEQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.sqe_next = NULL; \ - *(head)->sqh_last = (elm); \ - (head)->sqh_last = &(elm)->field.sqe_next; \ -} while (/*CONSTCOND*/0) - -#define QSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL) \ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (listelm)->field.sqe_next = (elm); \ -} while (/*CONSTCOND*/0) - -#define QSIMPLEQ_REMOVE_HEAD(head, field) do { \ - if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL)\ - (head)->sqh_last = &(head)->sqh_first; \ -} while (/*CONSTCOND*/0) - -#define QSIMPLEQ_SPLIT_AFTER(head, elm, field, removed) do { \ - QSIMPLEQ_INIT(removed); \ - if (((removed)->sqh_first = (head)->sqh_first) != NULL) { \ - if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) { \ - (head)->sqh_last = &(head)->sqh_first; \ - } \ - (removed)->sqh_last = &(elm)->field.sqe_next; \ - (elm)->field.sqe_next = NULL; \ - } \ -} while (/*CONSTCOND*/0) - -#define QSIMPLEQ_REMOVE(head, elm, type, field) do { \ - if ((head)->sqh_first == (elm)) { \ - QSIMPLEQ_REMOVE_HEAD((head), field); \ - } else { \ - struct type *curelm = (head)->sqh_first; \ - while (curelm->field.sqe_next != (elm)) \ - curelm = curelm->field.sqe_next; \ - if ((curelm->field.sqe_next = \ - curelm->field.sqe_next->field.sqe_next) == NULL) \ - (head)->sqh_last = &(curelm)->field.sqe_next; \ - } \ -} while (/*CONSTCOND*/0) - -#define QSIMPLEQ_FOREACH(var, head, field) \ - for ((var) = ((head)->sqh_first); \ - (var); \ - (var) = ((var)->field.sqe_next)) - -#define QSIMPLEQ_FOREACH_SAFE(var, head, field, next) \ - for ((var) = ((head)->sqh_first); \ - (var) && ((next = ((var)->field.sqe_next)), 1); \ - (var) = (next)) - -#define QSIMPLEQ_CONCAT(head1, head2) do { \ - if (!QSIMPLEQ_EMPTY((head2))) { \ - *(head1)->sqh_last = (head2)->sqh_first; \ - (head1)->sqh_last = (head2)->sqh_last; \ - QSIMPLEQ_INIT((head2)); \ - } \ -} while (/*CONSTCOND*/0) - -#define QSIMPLEQ_LAST(head, type, field) \ - (QSIMPLEQ_EMPTY((head)) ? \ - NULL : \ - ((struct type *)(void *) \ - ((char *)((head)->sqh_last) - offsetof(struct type, field)))) - -/* - * Simple queue access methods. - */ -#define QSIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) -#define QSIMPLEQ_FIRST(head) ((head)->sqh_first) -#define QSIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) - - -/* - * Tail queue definitions. - */ -#define Q_TAILQ_HEAD(name, type, qual) \ -struct name { \ - qual type *tqh_first; /* first element */ \ - qual type *qual *tqh_last; /* addr of last next element */ \ -} -#define QTAILQ_HEAD(name, type) Q_TAILQ_HEAD(name, struct type,) - -#define QTAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first } - -#define Q_TAILQ_ENTRY(type, qual) \ -struct { \ - qual type *tqe_next; /* next element */ \ - qual type *qual *tqe_prev; /* address of previous next element */\ -} -#define QTAILQ_ENTRY(type) Q_TAILQ_ENTRY(struct type,) - -/* - * Tail queue functions. - */ -#define QTAILQ_INIT(head) do { \ - (head)->tqh_first = NULL; \ - (head)->tqh_last = &(head)->tqh_first; \ -} while (/*CONSTCOND*/0) - -#define QTAILQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ - (head)->tqh_first->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (head)->tqh_first = (elm); \ - (elm)->field.tqe_prev = &(head)->tqh_first; \ -} while (/*CONSTCOND*/0) - -#define QTAILQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.tqe_next = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &(elm)->field.tqe_next; \ -} while (/*CONSTCOND*/0) - -#define QTAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ - (elm)->field.tqe_next->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (listelm)->field.tqe_next = (elm); \ - (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ -} while (/*CONSTCOND*/0) - -#define QTAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - (elm)->field.tqe_next = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ -} while (/*CONSTCOND*/0) - -#define QTAILQ_REMOVE(head, elm, field) do { \ - if (((elm)->field.tqe_next) != NULL) \ - (elm)->field.tqe_next->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ -} while (/*CONSTCOND*/0) - -#define QTAILQ_FOREACH(var, head, field) \ - for ((var) = ((head)->tqh_first); \ - (var); \ - (var) = ((var)->field.tqe_next)) - -#define QTAILQ_FOREACH_SAFE(var, head, field, next_var) \ - for ((var) = ((head)->tqh_first); \ - (var) && ((next_var) = ((var)->field.tqe_next), 1); \ - (var) = (next_var)) - -#define QTAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ - (var); \ - (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) - -/* - * Tail queue access methods. - */ -#define QTAILQ_EMPTY(head) ((head)->tqh_first == NULL) -#define QTAILQ_FIRST(head) ((head)->tqh_first) -#define QTAILQ_NEXT(elm, field) ((elm)->field.tqe_next) - -#define QTAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) -#define QTAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) - -#endif /* !QEMU_SYS_QUEUE_H_ */ diff --git a/slirp_glue/qemu/sockets.h b/slirp_glue/qemu/sockets.h deleted file mode 100644 index 14ad2989f..000000000 --- a/slirp_glue/qemu/sockets.h +++ /dev/null @@ -1,52 +0,0 @@ -/* headers to use the BSD sockets */ -#ifndef QEMU_SOCKET_H -#define QEMU_SOCKET_H - -#ifdef _WIN32 -#include -#include -#include - -#define socket_error() WSAGetLastError() - -extern char *socket_strerror(int errcode); -#define strerror socket_strerror - -int inet_aton(const char *cp, struct in_addr *ia); - -#else - -#include -#include -#include -#include -#include -#include -#include - -#define socket_error() errno - -#endif /* !_WIN32 */ - -/* misc helpers */ -int qemu_socket(int domain, int type, int protocol); -int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); -int socket_set_cork(int fd, int v); -int socket_set_nodelay(int fd); -void qemu_set_block(int fd); -void qemu_set_nonblock(int fd); -int socket_set_fast_reuse(int fd); - -#ifdef _WIN32 -/* MinGW needs type casts for the 'buf' and 'optval' arguments. */ -#define qemu_sendto(sockfd, buf, len, flags, destaddr, addrlen) \ - sendto(sockfd, (const void *)buf, len, flags, destaddr, addrlen) - -/* Windows has different names for the same constants with the same values */ -#define SHUT_RD 0 -#define SHUT_WR 1 -#define SHUT_RDWR 2 -#endif - - -#endif /* QEMU_SOCKET_H */ diff --git a/slirp_glue/qemu/sysemu/char.h b/slirp_glue/qemu/sysemu/char.h deleted file mode 100644 index 339a254fd..000000000 --- a/slirp_glue/qemu/sysemu/char.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef QEMU_CHAR_H -#define QEMU_CHAR_H - -#include "qemu-common.h" - -/** - * @qemu_chr_fe_write: - * - * Write data to a character backend from the front end. This function - * will send data from the front end to the back end. This function - * is thread-safe. - * - * @buf the data - * @len the number of bytes to send - * - * Returns: the number of bytes consumed - */ -int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len); - - -#endif diff --git a/slirp_glue/qemu/sysemu/os-win32.h b/slirp_glue/qemu/sysemu/os-win32.h deleted file mode 100644 index fff060a9d..000000000 --- a/slirp_glue/qemu/sysemu/os-win32.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * win32 specific declarations - * - * Copyright (c) 2003-2008 Fabrice Bellard - * Copyright (c) 2010 Jes Sorensen - * - * 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 QEMU_OS_WIN32_H -#define QEMU_OS_WIN32_H - -#include -#include - -#if defined(_WIN64) -/* MinGW-w64 has a 32 bit off_t, but we want 64 bit off_t. */ -# define off_t off64_t - -/* MinGW-w64 stdio.h defines SYS_OPEN. Allow a redefinition in arm-semi.c. */ -# undef SYS_OPEN -#endif - -/* Workaround for older versions of MinGW. */ -#ifndef ECONNREFUSED -# define ECONNREFUSED WSAECONNREFUSED -#endif -#ifndef EINPROGRESS -# define EINPROGRESS WSAEINPROGRESS -#endif -#ifndef EHOSTUNREACH -# define EHOSTUNREACH WSAEHOSTUNREACH -#endif -#ifndef EINTR -# define EINTR WSAEINTR -#endif -#ifndef EINPROGRESS -# define EINPROGRESS WSAEINPROGRESS -#endif -#ifndef ENETUNREACH -# define ENETUNREACH WSAENETUNREACH -#endif -#ifndef ENOTCONN -# define ENOTCONN WSAENOTCONN -#endif -#ifndef EWOULDBLOCK -# define EWOULDBLOCK WSAEWOULDBLOCK -#endif - -#if defined(_WIN64) -/* On w64, setjmp is implemented by _setjmp which needs a second parameter. - * If this parameter is NULL, longjump does no stack unwinding. - * That is what we need for QEMU. Passing the value of register rsp (default) - * lets longjmp try a stack unwinding which will crash with generated code. */ -# undef setjmp -# define setjmp(env) _setjmp(env, NULL) -#endif -/* QEMU uses sigsetjmp()/siglongjmp() as the portable way to specify - * "longjmp and don't touch the signal masks". Since we know that the - * savemask parameter will always be zero we can safely define these - * in terms of setjmp/longjmp on Win32. - */ -#define sigjmp_buf jmp_buf -#define sigsetjmp(env, savemask) setjmp(env) -#define siglongjmp(env, val) longjmp(env, val) - -/* Missing POSIX functions. Don't use MinGW-w64 macros. */ -#ifndef CONFIG_LOCALTIME_R -#undef gmtime_r -struct tm *gmtime_r(const time_t *timep, struct tm *result); -#undef localtime_r -struct tm *localtime_r(const time_t *timep, struct tm *result); -#endif /* CONFIG_LOCALTIME_R */ - - -static inline void os_setup_signal_handling(void) {} -static inline void os_daemonize(void) {} -static inline void os_setup_post(void) {} -void os_set_line_buffering(void); -static inline void os_set_proc_name(const char *dummy) {} - -size_t getpagesize(void); - -#if !defined(EPROTONOSUPPORT) -# define EPROTONOSUPPORT EINVAL -#endif - -int setenv(const char *name, const char *value, int overwrite); - -typedef struct { - long tv_sec; - long tv_usec; -} qemu_timeval; -int qemu_gettimeofday(qemu_timeval *tp); - -#endif diff --git a/slirp_glue/qemu/timer.h b/slirp_glue/qemu/timer.h deleted file mode 100644 index ba7918b2e..000000000 --- a/slirp_glue/qemu/timer.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef QEMU_TIMER_H -#define QEMU_TIMER_H - -#include "qemu/typedefs.h" -#include "qemu-common.h" - -#define NANOSECONDS_PER_SECOND 1000000000LL - -/* timers */ - -#define SCALE_MS 1000000 -#define SCALE_US 1000 -#define SCALE_NS 1 - -/** - * QEMUClockType: - * - * The following clock types are available: - * - * @QEMU_CLOCK_REALTIME: Real time clock - * - * The real time clock should be used only for stuff which does not - * change the virtual machine state, as it is run even if the virtual - * machine is stopped. The real time clock has a frequency of 1000 - * Hz. - * - * @QEMU_CLOCK_VIRTUAL: virtual clock - * - * The virtual clock is only run during the emulation. It is stopped - * when the virtual machine is stopped. Virtual timers use a high - * precision clock, usually cpu cycles (use ticks_per_sec). - * - * @QEMU_CLOCK_HOST: host clock - * - * The host clock should be use for device models that emulate accurate - * real time sources. It will continue to run when the virtual machine - * is suspended, and it will reflect system time changes the host may - * undergo (e.g. due to NTP). The host clock has the same precision as - * the virtual clock. - * - * @QEMU_CLOCK_VIRTUAL_RT: realtime clock used for icount warp - * - * Outside icount mode, this clock is the same as @QEMU_CLOCK_VIRTUAL. - * In icount mode, this clock counts nanoseconds while the virtual - * machine is running. It is used to increase @QEMU_CLOCK_VIRTUAL - * while the CPUs are sleeping and thus not executing instructions. - */ - -typedef enum { - QEMU_CLOCK_REALTIME = 0, - QEMU_CLOCK_VIRTUAL = 1, - QEMU_CLOCK_HOST = 2, - QEMU_CLOCK_VIRTUAL_RT = 3, - QEMU_CLOCK_MAX -} QEMUClockType; - - - - -/* - * QEMUClockType - */ - -/* - * qemu_clock_get_ns; - * @type: the clock type - * - * Get the nanosecond value of a clock with - * type @type - * - * Returns: the clock value in nanoseconds - */ -#if defined(__cplusplus) -extern "C" { -#endif -int64_t qemu_clock_get_ns(QEMUClockType type); -#if defined(__cplusplus) -} -#endif - -/** - * qemu_clock_get_ms; - * @type: the clock type - * - * Get the millisecond value of a clock with - * type @type - * - * Returns: the clock value in milliseconds - */ -static inline int64_t qemu_clock_get_ms(QEMUClockType type) -{ - return qemu_clock_get_ns(type) / SCALE_MS; -} - -#endif diff --git a/slirp_glue/qemu/typedefs.h b/slirp_glue/qemu/typedefs.h deleted file mode 100644 index 404ce2220..000000000 --- a/slirp_glue/qemu/typedefs.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef QEMU_TYPEDEFS_H -#define QEMU_TYPEDEFS_H - -/* A load of opaque types so that device init declarations don't have to - pull in all the real definitions. */ -struct Monitor; -typedef struct Monitor Monitor; -typedef struct CharDriverState CharDriverState; -typedef struct QEMUFile QEMUFile; - -#endif /* QEMU_TYPEDEFS_H */ diff --git a/slirp_glue/qemu/win32/include/sys/time.h b/slirp_glue/qemu/win32/include/sys/time.h deleted file mode 100644 index b2956a56c..000000000 --- a/slirp_glue/qemu/win32/include/sys/time.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef SYS_TIME_H -#define SYS_TIME_H - -#include - -#endif diff --git a/slirp_glue/qemu/win32/inttypes.h b/slirp_glue/qemu/win32/inttypes.h deleted file mode 100644 index 5e81fb225..000000000 --- a/slirp_glue/qemu/win32/inttypes.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef INTTYPES_H -#define INTTYPES_H - -#include - -#ifdef _WIN64 -typedef __int64 ssize_t; -#else -typedef __int32 ssize_t; -#endif -#endif diff --git a/slirp_glue/qemu/win32/stdbool.h b/slirp_glue/qemu/win32/stdbool.h deleted file mode 100644 index f4f253088..000000000 --- a/slirp_glue/qemu/win32/stdbool.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef STDBOOL_H -#define STDBOOL_H - -#define true 1 -#define false 0 -#define __bool_true_false_are_defined 1 - -#endif diff --git a/slirp_glue/qemu/win32/stdint.h b/slirp_glue/qemu/win32/stdint.h deleted file mode 100644 index ec384da2e..000000000 --- a/slirp_glue/qemu/win32/stdint.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef STDINT_H -#define STDINT_H - -typedef char int8_t; -typedef short int16_t; -typedef int int32_t; -typedef long long int64_t; -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef unsigned int u_int32_t; -typedef unsigned long long uint64_t; - -#endif diff --git a/slirp_glue/sim_slirp.c b/slirp_glue/sim_slirp.c deleted file mode 100644 index 9971d2a67..000000000 --- a/slirp_glue/sim_slirp.c +++ /dev/null @@ -1,665 +0,0 @@ -/* sim_slirp.c: - ------------------------------------------------------------------------------ - Copyright (c) 2015, Mark Pizzolato - - 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 AUTHOR 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. - - Except as contained in this notice, the name of the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - ------------------------------------------------------------------------------ - - This module provides the interface needed between sim_ether and SLiRP to - provide NAT network functionality. - -*/ - -/* Actual slirp API interface support, some code taken from slirpvde.c */ - -#define DEFAULT_IP_ADDR "10.0.2.2" - -#include "glib.h" -#include "qemu/timer.h" -#include "libslirp.h" -#include "sim_defs.h" -#include "sim_slirp.h" -#include "sim_sock.h" -#include "libslirp.h" - -#if !defined (USE_READER_THREAD) -#define pthread_mutex_init(mtx, val) -#define pthread_mutex_destroy(mtx) -#define pthread_mutex_lock(mtx) -#define pthread_mutex_unlock(mtx) -#define pthread_mutex_t int -#endif - -#define IS_TCP 0 -#define IS_UDP 1 -static const char *tcpudp[] = { - "TCP", - "UDP" - }; - -struct redir_tcp_udp { - struct in_addr inaddr; - int is_udp; - int port; - int lport; - struct redir_tcp_udp *next; - }; - -static int -_parse_redirect_port (struct redir_tcp_udp **head, const char *buff, int is_udp) -{ -char gbuf[4*CBUFSIZE]; -uint32 inaddr = 0; -int port = 0; -int lport = 0; -char *ipaddrstr = NULL; -char *portstr = NULL; -struct redir_tcp_udp *newp; - -gbuf[sizeof(gbuf)-1] = '\0'; -strncpy (gbuf, buff, sizeof(gbuf)-1); -if (((ipaddrstr = strchr(gbuf, ':')) == NULL) || (*(ipaddrstr+1) == 0)) { - sim_printf ("redir %s syntax error\n", tcpudp[is_udp]); - return -1; - } -*ipaddrstr++ = 0; - -if ((ipaddrstr) && - (((portstr = strchr (ipaddrstr, ':')) == NULL) || (*(portstr+1) == 0))) { - sim_printf ("redir %s syntax error\n", tcpudp[is_udp]); - return -1; - } -*portstr++ = 0; - -sscanf (gbuf, "%d", &lport); -sscanf (portstr, "%d", &port); -if (ipaddrstr) - inaddr = inet_addr (ipaddrstr); - -if (!inaddr) { - sim_printf ("%s redirection error: an IP address must be specified\n", tcpudp[is_udp]); - return -1; - } - -if ((newp = (struct redir_tcp_udp *)g_malloc (sizeof(struct redir_tcp_udp))) == NULL) - return -1; -else { - inet_aton (ipaddrstr, &newp->inaddr); - newp->is_udp = is_udp; - newp->port = port; - newp->lport = lport; - newp->next = *head; - *head = newp; - return 0; - } -} - -static int _do_redirects (Slirp *slirp, struct redir_tcp_udp *head) -{ -struct in_addr host_addr; -int ret = 0; - -host_addr.s_addr = htonl(INADDR_ANY); -if (head) { - ret = _do_redirects (slirp, head->next); - if (slirp_add_hostfwd (slirp, head->is_udp, host_addr, head->lport, head->inaddr, head->port) < 0) { - sim_printf("Can't establish redirector for: redir %s =%d:%s:%d\n", - tcpudp[head->is_udp], head->lport, inet_ntoa(head->inaddr), head->port); - ++ret; - } - } -return ret; -} - -struct slirp_write_request { - struct slirp_write_request *next; - char msg[1518]; - size_t len; - }; - -struct sim_slirp { - Slirp *slirp; - char *args; - struct in_addr vnetwork; - struct in_addr vnetmask; - int maskbits; - struct in_addr vgateway; - int dhcpmgmt; - struct in_addr vdhcp_start; - struct in_addr vnameserver; - char *boot_file; - char *tftp_path; - char *dns_search; - char **dns_search_domains; - struct redir_tcp_udp *rtcp; - GArray *gpollfds; - SOCKET db_chime; /* write packet doorbell */ - struct slirp_write_request *write_requests; - struct slirp_write_request *write_buffers; - pthread_mutex_t write_buffer_lock; - void *opaque; /* opaque value passed during packet delivery */ - packet_callback callback; /* slirp arriving packet delivery callback */ - DEVICE *dptr; - uint32 dbit; - }; - -#if defined(__cplusplus) -extern "C" { -#endif -DEVICE *slirp_dptr; -uint32 slirp_dbit; -#if defined(__cplusplus) -} -#endif - -SLIRP *sim_slirp_open (const char *args, void *opaque, packet_callback callback, DEVICE *dptr, uint32 dbit, char *errbuf, size_t errbuf_size) -{ -SLIRP *slirp = (SLIRP *)g_malloc0(sizeof(*slirp)); -char *targs = g_strdup (args); -const char *tptr = targs; -const char *cptr; -char tbuf[CBUFSIZE], gbuf[CBUFSIZE], abuf[CBUFSIZE]; -int err; - -slirp_dptr = dptr; -slirp_dbit = dbit; -slirp->args = (char *)g_malloc0(1 + strlen(args)); -strcpy (slirp->args, args); -slirp->opaque = opaque; -slirp->callback = callback; -slirp->maskbits = 24; -slirp->dhcpmgmt = 1; -slirp->db_chime = INVALID_SOCKET; -inet_aton(DEFAULT_IP_ADDR,&slirp->vgateway); -pthread_mutex_init (&slirp->write_buffer_lock, NULL); - -err = 0; -while (*tptr && !err) { - tptr = get_glyph_nc (tptr, tbuf, ','); - if (!tbuf[0]) - break; - cptr = tbuf; - cptr = get_glyph (cptr, gbuf, '='); - if (0 == MATCH_CMD (gbuf, "DHCP")) { - slirp->dhcpmgmt = 1; - if (cptr && *cptr) - inet_aton (cptr, &slirp->vdhcp_start); - continue; - } - if (0 == MATCH_CMD (gbuf, "TFTP")) { - if (cptr && *cptr) - slirp->tftp_path = g_strdup (cptr); - else { - strlcpy (errbuf, "Missing TFTP Path", errbuf_size); - err = 1; - } - continue; - } - if (0 == MATCH_CMD (gbuf, "BOOTFILE")) { - if (cptr && *cptr) - slirp->boot_file = g_strdup (cptr); - else { - strlcpy (errbuf, "Missing DHCP Boot file name", errbuf_size); - err = 1; - } - continue; - } - if ((0 == MATCH_CMD (gbuf, "NAMESERVER")) || - (0 == MATCH_CMD (gbuf, "DNS"))) { - if (cptr && *cptr) - inet_aton (cptr, &slirp->vnameserver); - else { - strlcpy (errbuf, "Missing nameserver", errbuf_size); - err = 1; - } - continue; - } - if (0 == MATCH_CMD (gbuf, "DNSSEARCH")) { - if (cptr && *cptr) { - int count = 0; - char *name; - - slirp->dns_search = g_strdup (cptr); - name = slirp->dns_search; - do { - ++count; - slirp->dns_search_domains = (char **)realloc (slirp->dns_search_domains, (count + 1)*sizeof(char *)); - slirp->dns_search_domains[count] = NULL; - slirp->dns_search_domains[count-1] = name; - name = strchr (name, ':'); - if (name) { - *name = '\0'; - ++name; - } - } while (name && *name); - } - else { - strlcpy (errbuf, "Missing DNS search list", errbuf_size); - err = 1; - } - continue; - } - if (0 == MATCH_CMD (gbuf, "GATEWAY")) { - if (cptr && *cptr) { - cptr = get_glyph (cptr, abuf, '/'); - if (cptr && *cptr) - slirp->maskbits = atoi (cptr); - inet_aton (abuf, &slirp->vgateway); - } - else { - strlcpy (errbuf, "Missing host", errbuf_size); - err = 1; - } - continue; - } - if (0 == MATCH_CMD (gbuf, "NETWORK")) { - if (cptr && *cptr) { - cptr = get_glyph (cptr, abuf, '/'); - if (cptr && *cptr) - slirp->maskbits = atoi (cptr); - inet_aton (abuf, &slirp->vnetwork); - } - else { - strlcpy (errbuf, "Missing network", errbuf_size); - err = 1; - } - continue; - } - if (0 == MATCH_CMD (gbuf, "NODHCP")) { - slirp->dhcpmgmt = 0; - continue; - } - if (0 == MATCH_CMD (gbuf, "UDP")) { - if (cptr && *cptr) - err = _parse_redirect_port (&slirp->rtcp, cptr, IS_UDP); - else { - strlcpy (errbuf, "Missing UDP port mapping", errbuf_size); - err = 1; - } - continue; - } - if (0 == MATCH_CMD (gbuf, "TCP")) { - if (cptr && *cptr) - err = _parse_redirect_port (&slirp->rtcp, cptr, IS_TCP); - else { - strlcpy (errbuf, "Missing TCP port mapping", errbuf_size); - err = 1; - } - continue; - } - snprintf (errbuf, errbuf_size - 1, "Unexpected NAT argument: %s", gbuf); - err = 1; - } -if (err) { - sim_slirp_close (slirp); - g_free (targs); - return NULL; - } - -slirp->vnetmask.s_addr = slirp->maskbits ? htonl(~((1 << (32-slirp->maskbits)) - 1)) : 0xFFFFFFFF; -slirp->vnetwork.s_addr = slirp->vgateway.s_addr & slirp->vnetmask.s_addr; -if ((slirp->vgateway.s_addr & ~slirp->vnetmask.s_addr) == 0) - slirp->vgateway.s_addr = htonl(ntohl(slirp->vnetwork.s_addr) | 2); -if ((slirp->vdhcp_start.s_addr == 0) && slirp->dhcpmgmt) - slirp->vdhcp_start.s_addr = htonl(ntohl(slirp->vnetwork.s_addr) | 15); -if (slirp->vnameserver.s_addr == 0) - slirp->vnameserver.s_addr = htonl(ntohl(slirp->vnetwork.s_addr) | 3); -slirp->slirp = slirp_init (0, slirp->vnetwork, slirp->vnetmask, slirp->vgateway, - NULL, slirp->tftp_path, slirp->boot_file, - slirp->vdhcp_start, slirp->vnameserver, - (const char **)(slirp->dns_search_domains), (void *)slirp); - -if (_do_redirects (slirp->slirp, slirp->rtcp)) { - sim_slirp_close (slirp); - slirp = NULL; - } -else { - char db_host[32]; - GPollFD pfd; - int64_t rnd_val = qemu_clock_get_ns ((QEMUClockType)0) / 1000000; - - slirp->gpollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD)); - /* setup transmit packet wakeup doorbell */ - do { - if ((rnd_val & 0xFFFF) == 0) - ++rnd_val; - sprintf (db_host, "localhost:%d", (int)(rnd_val & 0xFFFF)); - slirp->db_chime = sim_connect_sock_ex (db_host, db_host, NULL, NULL, SIM_SOCK_OPT_DATAGRAM | SIM_SOCK_OPT_BLOCKING); - } while (slirp->db_chime == INVALID_SOCKET); - memset (&pfd, 0, sizeof (pfd)); - pfd.fd = slirp->db_chime; - pfd.events = G_IO_IN; - g_array_append_val(slirp->gpollfds, pfd); - slirp->dbit = dbit; - slirp->dptr = dptr; - - sim_slirp_show(slirp, stdout); - if (sim_log && (sim_log != stdout)) - sim_slirp_show(slirp, sim_log); - if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log)) - sim_slirp_show(slirp, sim_deb); - } -g_free (targs); -return slirp; -} - -void sim_slirp_close (SLIRP *slirp) -{ -struct redir_tcp_udp *rtmp; - -if (slirp) { - g_free (slirp->args); - g_free (slirp->tftp_path); - g_free (slirp->boot_file); - g_free (slirp->dns_search); - g_free (slirp->dns_search_domains); - while ((rtmp = slirp->rtcp)) { - slirp_remove_hostfwd(slirp->slirp, rtmp->is_udp, rtmp->inaddr, rtmp->lport); - slirp->rtcp = rtmp->next; - g_free (rtmp); - } - g_array_free(slirp->gpollfds, true); - if (slirp->db_chime != INVALID_SOCKET) - closesocket (slirp->db_chime); - if (1) { - struct slirp_write_request *buffer; - - while (NULL != (buffer = slirp->write_buffers)) { - slirp->write_buffers = buffer->next; - free(buffer); - } - while (NULL != (buffer = slirp->write_requests)) { - slirp->write_requests = buffer->next; - free(buffer); - } - } - pthread_mutex_destroy (&slirp->write_buffer_lock); - if (slirp->slirp) - slirp_cleanup(slirp->slirp); - } -g_free (slirp); -} - -t_stat sim_slirp_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) -{ -fprintf (st, "%s", -"NAT options:\n" -" DHCP{=dhcp_start_address} Enables DHCP server and specifies\n" -" guest LAN DHCP start IP address\n" -" BOOTFILE=bootfilename specifies DHCP returned Boot Filename\n" -" TFTP=tftp-base-path Enables TFTP server and specifies\n" -" base file path\n" -" NAMESERVER=nameserver_ipaddres specifies DHCP nameserver IP address\n" -" DNS=nameserver_ipaddres specifies DHCP nameserver IP address\n" -" DNSSEARCH=domain{:domain{:domain}} specifies DNS Domains search suffixes\n" -" GATEWAY=host_ipaddress{/masklen} specifies LAN gateway IP address\n" -" NETWORK=network_ipaddress{/masklen} specifies LAN network address\n" -" UDP=port:address:address's-port maps host UDP port to guest port\n" -" TCP=port:address:address's-port maps host TCP port to guest port\n" -" NODHCP disables DHCP server\n\n" -"Default NAT Options: GATEWAY=10.0.2.2, masklen=24(netmask is 255.255.255.0)\n" -" DHCP=10.0.2.15, NAMESERVER=10.0.2.3\n" -" Nameserver defaults to proxy traffic to host system's active nameserver\n\n" -"The 'address' field in the UDP and TCP port mappings are the simulated\n" -"(guest) system's IP address which, if DHCP allocated would default to\n" -"10.0.2.15 or could be statically configured to any address including\n" -"10.0.2.4 thru 10.0.2.14.\n\n" -"NAT limitations\n\n" -"There are four limitations of NAT mode which users should be aware of:\n\n" -" 1) ICMP protocol limitations:\n" -" Some frequently used network debugging tools (e.g. ping or tracerouting)\n" -" rely on the ICMP protocol for sending/receiving messages. While some\n" -" ICMP support is available on some hosts (ping may or may not work),\n" -" some other tools may not work reliably.\n\n" -" 2) Receiving of UDP broadcasts is not reliable:\n" -" The guest does not reliably receive broadcasts, since, in order to save\n" -" resources, it only listens for a certain amount of time after the guest\n" -" has sent UDP data on a particular port.\n\n" -" 3) Protocols such as GRE, DECnet, LAT and Clustering are unsupported:\n" -" Protocols other than TCP and UDP are not supported.\n\n" -" 4) Forwarding host ports < 1024 impossible:\n" -" On Unix-based hosts (e.g. Linux, Solaris, Mac OS X) it is not possible\n" -" to bind to ports below 1024 from applications that are not run by root.\n" -" As a result, if you try to configure such a port forwarding, the attach\n" -" will fail.\n\n" -"These limitations normally don't affect standard network use. But the\n" -"presence of NAT has also subtle effects that may interfere with protocols\n" -"that are normally working. One example is NFS, where the server is often\n" -"configured to refuse connections from non-privileged ports (i.e. ports not\n" -" below 1024).\n" -); -return SCPE_OK; -} - -int sim_slirp_send (SLIRP *slirp, const char *msg, size_t len, int flags) -{ -struct slirp_write_request *request; -int wake_needed = 0; - -if (!slirp) { - errno = EBADF; - return 0; - } -/* Get a buffer */ -pthread_mutex_lock (&slirp->write_buffer_lock); -if (NULL != (request = slirp->write_buffers)) - slirp->write_buffers = request->next; -pthread_mutex_unlock (&slirp->write_buffer_lock); -if (NULL == request) - request = (struct slirp_write_request *)g_malloc(sizeof(*request)); - -/* Copy buffer contents */ -request->len = len; -memcpy(request->msg, msg, len); - -/* Insert buffer at the end of the write list (to make sure that */ -/* packets make it to the wire in the order they were presented here) */ -pthread_mutex_lock (&slirp->write_buffer_lock); -request->next = NULL; -if (slirp->write_requests) { - struct slirp_write_request *last_request = slirp->write_requests; - - while (last_request->next) { - last_request = last_request->next; - } - last_request->next = request; - } -else { - slirp->write_requests = request; - wake_needed = 1; - } -pthread_mutex_unlock (&slirp->write_buffer_lock); - -if (wake_needed) - sim_write_sock (slirp->db_chime, msg, 0); -return len; -} - -void slirp_output (void *opaque, const uint8_t *pkt, int pkt_len) -{ -SLIRP *slirp = (SLIRP *)opaque; - -slirp->callback (slirp->opaque, pkt, pkt_len); -} - -void sim_slirp_show (SLIRP *slirp, FILE *st) -{ -struct redir_tcp_udp *rtmp; - -if ((slirp == NULL) || (slirp->slirp == NULL)) - return; -fprintf (st, "NAT args: %s\n", slirp->args); -fprintf (st, "NAT network setup:\n"); -fprintf (st, " gateway =%s/%d", inet_ntoa(slirp->vgateway), slirp->maskbits); -fprintf (st, "(%s)\n", inet_ntoa(slirp->vnetmask)); -fprintf (st, " DNS =%s\n", inet_ntoa(slirp->vnameserver)); -if (slirp->vdhcp_start.s_addr != 0) - fprintf (st, " dhcp_start =%s\n", inet_ntoa(slirp->vdhcp_start)); -if (slirp->boot_file) - fprintf (st, " dhcp bootfile =%s\n", slirp->boot_file); -if (slirp->dns_search_domains) { - char **domains = slirp->dns_search_domains; - - fprintf (st, " DNS domains ="); - while (*domains) { - fprintf (st, "%s%s", (domains != slirp->dns_search_domains) ? ", " : "", *domains); - ++domains; - } - fprintf (st, "\n"); - } -if (slirp->tftp_path) - fprintf (st, " tftp prefix =%s\n", slirp->tftp_path); -rtmp = slirp->rtcp; -while (rtmp) { - fprintf (st, " redir %3s =%d:%s:%d\n", tcpudp[rtmp->is_udp], rtmp->lport, inet_ntoa(rtmp->inaddr), rtmp->port); - rtmp = rtmp->next; - } -slirp_connection_info (slirp->slirp, (Monitor *)st); -} - -#if !defined(MAX) -#define MAX(a,b) (((a)>(b)) ? (a) : (b)) -#endif - -static int pollfds_fill (GArray *pollfds, fd_set *rfds, fd_set *wfds, - fd_set *xfds) -{ -int nfds = -1; -guint i; - -for (i = 0; i < pollfds->len; i++) { - GPollFD *pfd = &g_array_index(pollfds, GPollFD, i); - int fd = pfd->fd; - int events = pfd->events; - if (events & G_IO_IN) { - FD_SET(fd, rfds); - nfds = MAX(nfds, fd); - } - if (events & G_IO_OUT) { - FD_SET(fd, wfds); - nfds = MAX(nfds, fd); - } - if (events & (G_IO_PRI | G_IO_HUP | G_IO_ERR)) { - FD_SET(fd, xfds); - nfds = MAX(nfds, fd); - } - } -return nfds; -} - -static void pollfds_poll (GArray *pollfds, int nfds, fd_set *rfds, - fd_set *wfds, fd_set *xfds) -{ -guint i; - -for (i = 0; i < pollfds->len; i++) { - GPollFD *pfd = &g_array_index(pollfds, GPollFD, i); - int fd = pfd->fd; - int revents = 0; - - if (FD_ISSET(fd, rfds)) { - revents |= G_IO_IN; - } - if (FD_ISSET(fd, wfds)) { - revents |= G_IO_OUT; - } - if (FD_ISSET(fd, xfds)) { - revents |= G_IO_PRI; - } - pfd->revents = revents & pfd->events; - } -} - -int sim_slirp_select (SLIRP *slirp, int ms_timeout) -{ -int select_ret = 0; -uint32 slirp_timeout = ms_timeout; -struct timeval timeout; -fd_set rfds, wfds, xfds; -fd_set save_rfds, save_wfds, save_xfds; -int nfds; - -if (!slirp) /* Not active? */ - return -1; /* That's an error */ -/* Populate the GPollFDs from slirp */ -g_array_set_size (slirp->gpollfds, 1); /* Leave the doorbell chime alone */ -slirp_pollfds_fill(slirp->gpollfds, &slirp_timeout); -timeout.tv_sec = slirp_timeout / 1000; -timeout.tv_usec = (slirp_timeout % 1000) * 1000; - -FD_ZERO(&rfds); -FD_ZERO(&wfds); -FD_ZERO(&xfds); -/* Extract the GPollFDs interest */ -nfds = pollfds_fill (slirp->gpollfds, &rfds, &wfds, &xfds); -save_rfds = rfds; -save_wfds = wfds; -save_xfds = xfds; -select_ret = select(nfds + 1, &rfds, &wfds, &xfds, &timeout); -if (select_ret) { - int i; - /* Update the GPollFDs results */ - pollfds_poll (slirp->gpollfds, nfds, &rfds, &wfds, &xfds); - if (FD_ISSET (slirp->db_chime, &rfds)) { - char buf[32]; - /* consume the doorbell wakeup ring */ - (void)recv (slirp->db_chime, buf, sizeof (buf), 0); - } - sim_debug (slirp->dbit, slirp->dptr, "Select returned %d\r\n", select_ret); - for (i=0; idbit, slirp->dptr, "%d: save_rfd=%d, rfd=%d\r\n", i, FD_ISSET(i, &save_rfds), FD_ISSET(i, &rfds)); - if (FD_ISSET(i, &wfds) || FD_ISSET(i, &save_wfds)) - sim_debug (slirp->dbit, slirp->dptr, "%d: save_wfd=%d, wfd=%d\r\n", i, FD_ISSET(i, &save_wfds), FD_ISSET(i, &wfds)); - if (FD_ISSET(i, &xfds) || FD_ISSET(i, &save_xfds)) - sim_debug (slirp->dbit, slirp->dptr, "%d: save_xfd=%d, xfd=%d\r\n", i, FD_ISSET(i, &save_xfds), FD_ISSET(i, &xfds)); - } - } -return select_ret + 1; /* Force dispatch even on timeout */ -} - -void sim_slirp_dispatch (SLIRP *slirp) -{ -struct slirp_write_request *request; - -/* first deliver any transmit packets which are pending */ - -pthread_mutex_lock (&slirp->write_buffer_lock); -while (NULL != (request = slirp->write_requests)) { - /* Pull buffer off request list */ - slirp->write_requests = request->next; - pthread_mutex_unlock (&slirp->write_buffer_lock); - - slirp_input (slirp->slirp, (const uint8_t *)request->msg, (int)request->len); - - pthread_mutex_lock (&slirp->write_buffer_lock); - /* Put buffer on free buffer list */ - request->next = slirp->write_buffers; - slirp->write_buffers = request; - } -pthread_mutex_unlock (&slirp->write_buffer_lock); - -slirp_pollfds_poll(slirp->gpollfds, 0); - -} - diff --git a/slirp_glue/sim_slirp.h b/slirp_glue/sim_slirp.h deleted file mode 100644 index 0411e3fcf..000000000 --- a/slirp_glue/sim_slirp.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef SIM_SLIRP_H -#define SIM_SLIRP_H - -#if defined(HAVE_SLIRP_NETWORK) - -#include "sim_defs.h" -typedef struct sim_slirp SLIRP; - -typedef void (*packet_callback)(void *opaque, const unsigned char *buf, int len); - -SLIRP *sim_slirp_open (const char *args, void *opaque, packet_callback callback, DEVICE *dptr, uint32 dbit, char *errbuf, size_t errbuf_size); -void sim_slirp_close (SLIRP *slirp); -int sim_slirp_send (SLIRP *slirp, const char *msg, size_t len, int flags); -int sim_slirp_select (SLIRP *slirp, int ms_timeout); -void sim_slirp_dispatch (SLIRP *slirp); -t_stat sim_slirp_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); -void sim_slirp_show (SLIRP *slirp, FILE *st); - -#endif /* HAVE_SLIRP_NETWORK */ - -#endif